unify idempotent act and act

This commit is contained in:
keyan 2023-12-27 10:15:18 -06:00
parent 73ad93f2bb
commit 6170853d72
3 changed files with 26 additions and 60 deletions

View File

@ -1,6 +1,6 @@
import { GraphQLError } from 'graphql' import { GraphQLError } from 'graphql'
import { ensureProtocol, removeTracking } from '../../lib/url' import { ensureProtocol, removeTracking } from '../../lib/url'
import { serializeInvoicable } from './serial' import serialize, { serializeInvoicable } from './serial'
import { decodeCursor, LIMIT, nextCursorEncoded } from '../../lib/cursor' import { decodeCursor, LIMIT, nextCursorEncoded } from '../../lib/cursor'
import { getMetadata, metadataRuleSets } from 'page-metadata-parser' import { getMetadata, metadataRuleSets } from 'page-metadata-parser'
import { ruleSet as publicationDateRuleSet } from '../../lib/timedate-scraper' import { ruleSet as publicationDateRuleSet } from '../../lib/timedate-scraper'
@ -752,7 +752,7 @@ export default {
return id return id
}, },
act: async (parent, { id, sats, act = 'TIP', hash, hmac }, { me, models, lnd, headers }) => { act: async (parent, { id, sats, act = 'TIP', idempotent, hash, hmac }, { me, models, lnd, headers }) => {
await ssValidate(actSchema, { sats, act }) await ssValidate(actSchema, { sats, act })
await assertGofacYourself({ models, headers }) await assertGofacYourself({ models, headers })
@ -776,59 +776,27 @@ export default {
} }
} }
await serializeInvoicable( if (idempotent) {
models.$queryRaw` await serialize(
models,
models.$queryRaw`
SELECT SELECT
item_act(${Number(id)}::INTEGER, item_act(${Number(id)}::INTEGER, ${me.id}::INTEGER, ${act}::"ItemActType",
${me?.id || ANON_USER_ID}::INTEGER, ${act}::"ItemActType", ${Number(sats)}::INTEGER)`, (SELECT ${Number(sats)}::INTEGER - COALESCE(sum(msats) / 1000, 0)
{ me, models, lnd, hash, hmac, enforceFee: sats } FROM "ItemAct"
) WHERE act IN ('TIP', 'FEE')
AND "itemId" = ${Number(id)}::INTEGER
notifyZapped({ models, id }) AND "userId" = ${me.id}::INTEGER)::INTEGER)`
)
return { } else {
id, await serializeInvoicable(
sats, models.$queryRaw`
act, SELECT
path: item.path item_act(${Number(id)}::INTEGER,
${me?.id || ANON_USER_ID}::INTEGER, ${act}::"ItemActType", ${Number(sats)}::INTEGER)`,
{ me, models, lnd, hash, hmac, enforceFee: sats }
)
} }
},
idempotentAct: async (parent, { id, sats, act = 'TIP', hash, hmac }, { me, models, lnd, headers }) => {
if (!me) {
throw new GraphQLError('you must be logged in', { extensions: { code: 'FORBIDDEN' } })
}
await ssValidate(actSchema, { sats, act })
await assertGofacYourself({ models, headers })
const [item] = await models.$queryRawUnsafe(`
${SELECT}
FROM "Item"
WHERE id = $1`, Number(id))
if (Number(item.userId) === Number(me.id)) {
throw new GraphQLError('cannot zap your self', { extensions: { code: 'BAD_INPUT' } })
}
// Disallow tips if me is one of the forward user recipients
if (act === 'TIP') {
const existingForwards = await models.itemForward.findMany({ where: { itemId: Number(id) } })
if (existingForwards.some(fwd => Number(fwd.userId) === Number(me.id))) {
throw new GraphQLError('cannot zap a post for which you are forwarded zaps', { extensions: { code: 'BAD_INPUT' } })
}
}
await serializeInvoicable(
models.$queryRaw`
SELECT
item_act(${Number(id)}::INTEGER, ${me.id}::INTEGER, ${act}::"ItemActType",
(SELECT ${Number(sats)}::INTEGER - COALESCE(sum(msats) / 1000, 0)
FROM "ItemAct"
WHERE act IN ('TIP', 'FEE')
AND "itemId" = ${Number(id)}::INTEGER
AND "userId" = ${me.id}::INTEGER)::INTEGER)`,
{ me, models, lnd, hash, hmac, enforceFee: sats }
)
notifyZapped({ models, id }) notifyZapped({ models, id })

View File

@ -36,8 +36,7 @@ export default gql`
upsertPoll(id: ID, sub: String, title: String!, text: String, options: [String!]!, boost: Int, forward: [ItemForwardInput], hash: String, hmac: String): Item! upsertPoll(id: ID, sub: String, title: String!, text: String, options: [String!]!, boost: Int, forward: [ItemForwardInput], hash: String, hmac: String): Item!
updateNoteId(id: ID!, noteId: String!): Item! updateNoteId(id: ID!, noteId: String!): Item!
upsertComment(id:ID, text: String!, parentId: ID, hash: String, hmac: String): Item! upsertComment(id:ID, text: String!, parentId: ID, hash: String, hmac: String): Item!
act(id: ID!, sats: Int, act: String, hash: String, hmac: String): ItemActResult! act(id: ID!, sats: Int, act: String, idempotent: Boolean, hash: String, hmac: String): ItemActResult!
idempotentAct(id: ID!, sats: Int, hash: String, hmac: String): ItemActResult!
pollVote(id: ID!, hash: String, hmac: String): ID! pollVote(id: ID!, hash: String, hmac: String): ID!
} }

View File

@ -173,7 +173,7 @@ export function useAct ({ onUpdate } = {}) {
export function useZap () { export function useZap () {
const update = useCallback((cache, args) => { const update = useCallback((cache, args) => {
const { data: { idempotentAct: { id, sats, path } } } = args const { data: { act: { id, sats, path } } } = args
// determine how much we increased existing sats by by checking the // determine how much we increased existing sats by by checking the
// difference between result sats and meSats // difference between result sats and meSats
@ -221,8 +221,8 @@ export function useZap () {
const [zap] = useMutation( const [zap] = useMutation(
gql` gql`
mutation idempotentAct($id: ID!, $sats: Int!, $hash: String, $hmac: String) { mutation idempotentAct($id: ID!, $sats: Int!) {
idempotentAct(id: $id, sats: $sats, hash: $hash, hmac: $hmac) { act(id: $id, sats: $sats, idempotent: true) {
id id
sats sats
path path
@ -241,7 +241,6 @@ export function useZap () {
}, [act, strike]) }, [act, strike])
return useCallback(async ({ item, me }) => { return useCallback(async ({ item, me }) => {
console.log(item)
const meSats = (item?.meSats || 0) const meSats = (item?.meSats || 0)
// what should our next tip be? // what should our next tip be?
@ -259,7 +258,7 @@ export function useZap () {
await zap({ await zap({
variables, variables,
optimisticResponse: { optimisticResponse: {
idempotentAct: { act: {
path: item.path, path: item.path,
...variables ...variables
} }