Skip to content

Commit 2f7e852

Browse files
authored
Merge branch 'master' into custom_domain
2 parents f405dd1 + 1147e1f commit 2f7e852

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

+1853
-965
lines changed

.env.development

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ IMGPROXY_READ_TIMEOUT=10
8585
IMGPROXY_WRITE_TIMEOUT=10
8686
IMGPROXY_DOWNLOAD_TIMEOUT=9
8787
IMGPROXY_ENABLE_VIDEO_THUMBNAILS=1
88+
IMGPROXY_ALLOW_ORIGIN=http://localhost:3000
8889
# IMGPROXY_DEVELOPMENT_ERRORS_MODE=1
8990
# IMGPROXY_ENABLE_DEBUG_HEADERS=true
9091

.github/workflows/extend-awards.yml

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,36 @@ jobs:
2222
with:
2323
python-version: '3.13'
2424
- run: pip install requests
25+
- name: Check if branch exists
26+
id: check_branch
27+
run: |
28+
git fetch origin extend-awards/patch || echo "Branch does not exist"
29+
if git show-ref --verify --quiet refs/remotes/origin/extend-awards/patch; then
30+
echo "exists=true" >> $GITHUB_ENV
31+
else
32+
echo "exists=false" >> $GITHUB_ENV
33+
fi
34+
- name: Checkout to existing branch
35+
if: env.exists == 'true'
36+
run: |
37+
git checkout extend-awards/patch
38+
git config user.name 'github-actions[bot]'
39+
git config user.email 'github-actions[bot]@users.noreply.github.com'
2540
- run: python extend-awards.py
2641
env:
2742
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2843
GITHUB_CONTEXT: ${{ toJson(github) }}
44+
- name: Commit changes and push to existing branch
45+
if: env.exists == 'true'
46+
run: |
47+
git commit -am "Extending awards.csv"
48+
git push origin extend-awards/patch
2949
- uses: peter-evans/create-pull-request@v7
50+
if: env.exists == 'false'
3051
with:
3152
add-paths: awards.csv
3253
branch: extend-awards/patch
3354
commit-message: Extending awards.csv
3455
title: Extending awards.csv
35-
body: A PR was merged that solves an issue and awards.csv should be extended.
56+
body: One or more PR's were merged that solve an issue(s) and awards.csv should be extended. Remembere to delete the branch after merging.
57+
delete-branch: true

api/resolvers/item.js

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import performPaidAction from '../paidAction'
2626
import { GqlAuthenticationError, GqlInputError } from '@/lib/error'
2727
import { verifyHmac } from './wallet'
2828
import { parse } from 'tldts'
29+
import { shuffleArray } from '@/lib/rand'
2930

3031
function commentsOrderByClause (me, models, sort) {
3132
const sharedSortsArray = []
@@ -696,7 +697,11 @@ export default {
696697
status: 'ACTIVE',
697698
deletedAt: null,
698699
outlawed: false,
699-
parentId: null
700+
parentId: null,
701+
OR: [
702+
{ invoiceActionState: 'PAID' },
703+
{ invoiceActionState: { is: null } }
704+
]
700705
}
701706
if (id) {
702707
where.id = { not: Number(id) }
@@ -833,8 +838,16 @@ export default {
833838
const data = { itemId: Number(id), userId: me.id }
834839
const old = await models.threadSubscription.findUnique({ where: { userId_itemId: data } })
835840
if (old) {
836-
await models.threadSubscription.delete({ where: { userId_itemId: data } })
837-
} else await models.threadSubscription.create({ data })
841+
await models.$executeRaw`
842+
DELETE FROM "ThreadSubscription" ts
843+
USING "Item" i
844+
WHERE ts."userId" = ${me.id}
845+
AND i.path <@ (SELECT path FROM "Item" WHERE id = ${Number(id)})
846+
AND ts."itemId" = i.id
847+
`
848+
} else {
849+
await models.threadSubscription.create({ data })
850+
}
838851
return { id }
839852
},
840853
deleteItem: async (parent, { id }, { me, models }) => {
@@ -1150,7 +1163,8 @@ export default {
11501163
poll.meVoted = false
11511164
}
11521165

1153-
poll.options = options
1166+
poll.randPollOptions = item?.randPollOptions
1167+
poll.options = poll.randPollOptions ? shuffleArray(options) : options
11541168
poll.count = options.reduce((t, o) => t + o.count, 0)
11551169

11561170
return poll

api/resolvers/notifications.js

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -316,13 +316,36 @@ export default {
316316

317317
if (meFull.noteCowboyHat) {
318318
queries.push(
319-
`(SELECT id::text, updated_at AS "sortTime", 0 as "earnedSats", 'Streak' AS type
319+
`(SELECT id::text, updated_at AS "sortTime", 0 as "earnedSats", 'CowboyHat' AS type
320320
FROM "Streak"
321321
WHERE "userId" = $1
322322
AND updated_at < $2
323+
AND type = 'COWBOY_HAT'
323324
ORDER BY "sortTime" DESC
324325
LIMIT ${LIMIT})`
325326
)
327+
for (const type of ['HORSE', 'GUN']) {
328+
const gqlType = type.charAt(0) + type.slice(1).toLowerCase()
329+
queries.push(
330+
`(SELECT id::text, "startedAt" AS "sortTime", 0 as "earnedSats", 'New${gqlType}' AS type
331+
FROM "Streak"
332+
WHERE "userId" = $1
333+
AND updated_at < $2
334+
AND type = '${type}'::"StreakType"
335+
ORDER BY "sortTime" DESC
336+
LIMIT ${LIMIT})`
337+
)
338+
queries.push(
339+
`(SELECT id::text AS id, "endedAt" AS "sortTime", 0 as "earnedSats", 'Lost${gqlType}' AS type
340+
FROM "Streak"
341+
WHERE "userId" = $1
342+
AND updated_at < $2
343+
AND "endedAt" IS NOT NULL
344+
AND type = '${type}'::"StreakType"
345+
ORDER BY "sortTime" DESC
346+
LIMIT ${LIMIT})`
347+
)
348+
}
326349
}
327350

328351
queries.push(
@@ -500,23 +523,14 @@ export default {
500523
}
501524
}
502525
},
503-
Streak: {
526+
CowboyHat: {
504527
days: async (n, args, { models }) => {
505528
const res = await models.$queryRaw`
506-
SELECT "endedAt" - "startedAt" AS days
529+
SELECT "endedAt"::date - "startedAt"::date AS days
507530
FROM "Streak"
508531
WHERE id = ${Number(n.id)} AND "endedAt" IS NOT NULL
509532
`
510-
511533
return res.length ? res[0].days : null
512-
},
513-
type: async (n, args, { models }) => {
514-
const res = await models.$queryRaw`
515-
SELECT "type"
516-
FROM "Streak"
517-
WHERE id = ${Number(n.id)}
518-
`
519-
return res.length ? res[0].type : null
520534
}
521535
},
522536
Earn: {

api/resolvers/search.js

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { decodeCursor, LIMIT, nextCursorEncoded } from '@/lib/cursor'
22
import { whenToFrom } from '@/lib/time'
33
import { getItem, itemQueryWithMeta, SELECT } from './item'
4+
import { parse } from 'tldts'
45

56
function queryParts (q) {
67
const regex = /"([^"]*)"/gm
@@ -253,24 +254,17 @@ export default {
253254

254255
// if search contains a url term, modify the query text
255256
if (url) {
256-
const uri = url.slice(4)
257-
let uriObj
258-
try {
259-
uriObj = new URL(uri)
260-
} catch {
261-
try {
262-
uriObj = new URL(`https://${uri}`)
263-
} catch {}
264-
}
265-
266-
if (uriObj) {
267-
termQueries.push({
268-
wildcard: { url: `*${uriObj?.hostname ?? uri}${uriObj?.pathname ?? ''}*` }
269-
})
270-
termQueries.push({
271-
match: { text: `${uriObj?.hostname ?? uri}${uriObj?.pathname ?? ''}` }
272-
})
257+
let uri = url.slice(4)
258+
termQueries.push({
259+
match_bool_prefix: { url: { query: uri, operator: 'and', boost: 1000 } }
260+
})
261+
const parsed = parse(uri)
262+
if (parsed?.subdomain?.length > 0) {
263+
uri = uri.replace(`${parsed.subdomain}.`, '')
273264
}
265+
termQueries.push({
266+
wildcard: { url: { value: `*${uri}*` } }
267+
})
274268
}
275269

276270
// if nym, items must contain nym

api/resolvers/user.js

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import assertApiKeyNotPermitted from './apiKey'
1111
import { hashEmail } from '@/lib/crypto'
1212
import { isMuted } from '@/lib/user'
1313
import { GqlAuthenticationError, GqlAuthorizationError, GqlInputError } from '@/lib/error'
14+
import { processCrop } from '@/worker/imgproxy'
1415

1516
const contributors = new Set()
1617

@@ -727,6 +728,18 @@ export default {
727728

728729
return true
729730
},
731+
cropPhoto: async (parent, { photoId, cropData }, { me, models }) => {
732+
if (!me) {
733+
throw new GqlAuthenticationError()
734+
}
735+
736+
const croppedUrl = await processCrop({ photoId: Number(photoId), cropData })
737+
if (!croppedUrl) {
738+
throw new GqlInputError('can\'t crop photo')
739+
}
740+
741+
return croppedUrl
742+
},
730743
setPhoto: async (parent, { photoId }, { me, models }) => {
731744
if (!me) {
732745
throw new GqlAuthenticationError()
@@ -898,6 +911,14 @@ export default {
898911

899912
await models.user.update({ where: { id: me.id }, data: { hideWelcomeBanner: true } })
900913
return true
914+
},
915+
hideWalletRecvPrompt: async (parent, data, { me, models }) => {
916+
if (!me) {
917+
throw new GqlAuthenticationError()
918+
}
919+
920+
await models.user.update({ where: { id: me.id }, data: { hideWalletRecvPrompt: true } })
921+
return true
901922
}
902923
},
903924

@@ -1082,27 +1103,25 @@ export default {
10821103

10831104
return user.streak
10841105
},
1085-
gunStreak: async (user, args, { models }) => {
1106+
hasSendWallet: async (user, args, { models }) => {
10861107
if (user.hideCowboyHat) {
1087-
return null
1108+
return false
10881109
}
1089-
1090-
return user.gunStreak
1110+
return user.hasSendWallet
10911111
},
1092-
horseStreak: async (user, args, { models }) => {
1112+
hasRecvWallet: async (user, args, { models }) => {
10931113
if (user.hideCowboyHat) {
1094-
return null
1114+
return false
10951115
}
1096-
1097-
return user.horseStreak
1116+
return user.hasRecvWallet
10981117
},
10991118
maxStreak: async (user, args, { models }) => {
11001119
if (user.hideCowboyHat) {
11011120
return null
11021121
}
11031122

11041123
const [{ max }] = await models.$queryRaw`
1105-
SELECT MAX(COALESCE("endedAt", (now() AT TIME ZONE 'America/Chicago')::date) - "startedAt")
1124+
SELECT MAX(COALESCE("endedAt"::date, (now() AT TIME ZONE 'America/Chicago')::date) - "startedAt"::date)
11061125
FROM "Streak" WHERE "userId" = ${user.id}`
11071126
return max
11081127
},

api/resolvers/vault.js

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,10 @@ import { E_VAULT_KEY_EXISTS, GqlAuthenticationError, GqlInputError } from '@/lib
22

33
export default {
44
Query: {
5-
getVaultEntry: async (parent, { key }, { me, models }, info) => {
5+
getVaultEntries: async (parent, args, { me, models }) => {
66
if (!me) throw new GqlAuthenticationError()
7-
if (!key) throw new GqlInputError('must have key')
87

9-
const k = await models.vault.findUnique({
10-
where: {
11-
key,
12-
userId: me.id
13-
}
14-
})
15-
return k
16-
},
17-
getVaultEntries: async (parent, { keysFilter }, { me, models }, info) => {
18-
if (!me) throw new GqlAuthenticationError()
19-
20-
const entries = await models.vaultEntry.findMany({
21-
where: {
22-
userId: me.id,
23-
key: keysFilter?.length
24-
? {
25-
in: keysFilter
26-
}
27-
: undefined
28-
}
29-
})
30-
return entries
8+
return await models.vaultEntry.findMany({ where: { userId: me.id } })
319
}
3210
},
3311
Mutation: {

api/resolvers/wallet.js

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -154,37 +154,6 @@ export function verifyHmac (hash, hmac) {
154154
const resolvers = {
155155
Query: {
156156
invoice: getInvoice,
157-
wallet: async (parent, { id }, { me, models }) => {
158-
if (!me) {
159-
throw new GqlAuthenticationError()
160-
}
161-
162-
return await models.wallet.findUnique({
163-
where: {
164-
userId: me.id,
165-
id: Number(id)
166-
},
167-
include: {
168-
vaultEntries: true
169-
}
170-
})
171-
},
172-
walletByType: async (parent, { type }, { me, models }) => {
173-
if (!me) {
174-
throw new GqlAuthenticationError()
175-
}
176-
177-
const wallet = await models.wallet.findFirst({
178-
where: {
179-
userId: me.id,
180-
type
181-
},
182-
include: {
183-
vaultEntries: true
184-
}
185-
})
186-
return wallet
187-
},
188157
wallets: async (parent, args, { me, models }) => {
189158
if (!me) {
190159
throw new GqlAuthenticationError()

api/typeDefs/item.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export default gql`
5757
text: String!, url: String!, boost: Int, status: String, logo: Int): ItemPaidAction!
5858
upsertPoll(
5959
id: ID, sub: String, title: String!, text: String, options: [String!]!, boost: Int, forward: [ItemForwardInput], pollExpiresAt: Date,
60-
hash: String, hmac: String): ItemPaidAction!
60+
randPollOptions: Boolean, hash: String, hmac: String): ItemPaidAction!
6161
updateNoteId(id: ID!, noteId: String!): Item!
6262
upsertComment(id: ID, text: String!, parentId: ID, boost: Int, hash: String, hmac: String): ItemPaidAction!
6363
act(id: ID!, sats: Int, act: String, hasSendWallet: Boolean): ItemActPaidAction!
@@ -81,6 +81,7 @@ export default gql`
8181
meInvoiceActionState: InvoiceActionState
8282
count: Int!
8383
options: [PollOption!]!
84+
randPollOptions: Boolean
8485
}
8586
8687
type Items {

0 commit comments

Comments
 (0)