Dependency inject `me` into post validation schemas to enforce no forwarding posts to self (#485)
Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
This commit is contained in:
parent
16a6f93708
commit
1a6dc879a2
|
@ -621,7 +621,7 @@ export default {
|
|||
return await models.item.update({ where: { id: Number(id) }, data })
|
||||
},
|
||||
upsertLink: async (parent, { id, hash, hmac, ...item }, { me, models, lnd }) => {
|
||||
await ssValidate(linkSchema, item, models)
|
||||
await ssValidate(linkSchema, item, models, me)
|
||||
|
||||
if (id) {
|
||||
return await updateItem(parent, { id, ...item }, { me, models })
|
||||
|
@ -630,7 +630,7 @@ export default {
|
|||
}
|
||||
},
|
||||
upsertDiscussion: async (parent, { id, hash, hmac, ...item }, { me, models, lnd }) => {
|
||||
await ssValidate(discussionSchema, item, models)
|
||||
await ssValidate(discussionSchema, item, models, me)
|
||||
|
||||
if (id) {
|
||||
return await updateItem(parent, { id, ...item }, { me, models })
|
||||
|
@ -639,7 +639,7 @@ export default {
|
|||
}
|
||||
},
|
||||
upsertBounty: async (parent, { id, hash, hmac, ...item }, { me, models, lnd }) => {
|
||||
await ssValidate(bountySchema, item, models)
|
||||
await ssValidate(bountySchema, item, models, me)
|
||||
|
||||
if (id) {
|
||||
return await updateItem(parent, { id, ...item }, { me, models })
|
||||
|
@ -656,7 +656,7 @@ export default {
|
|||
})
|
||||
: 0
|
||||
|
||||
await ssValidate(pollSchema, item, models, optionCount)
|
||||
await ssValidate(pollSchema, item, models, me, optionCount)
|
||||
|
||||
if (id) {
|
||||
return await updateItem(parent, { id, ...item }, { me, models })
|
||||
|
|
|
@ -11,6 +11,7 @@ import CancelButton from './cancel-button'
|
|||
import { useCallback } from 'react'
|
||||
import { normalizeForwards } from '../lib/form'
|
||||
import { MAX_TITLE_LENGTH } from '../lib/constants'
|
||||
import { useMe } from './me'
|
||||
|
||||
export function BountyForm ({
|
||||
item,
|
||||
|
@ -25,7 +26,8 @@ export function BountyForm ({
|
|||
}) {
|
||||
const router = useRouter()
|
||||
const client = useApolloClient()
|
||||
const schema = bountySchema(client)
|
||||
const me = useMe()
|
||||
const schema = bountySchema(client, me)
|
||||
const [upsertBounty] = useMutation(
|
||||
gql`
|
||||
mutation upsertBounty(
|
||||
|
|
|
@ -15,6 +15,7 @@ import CancelButton from './cancel-button'
|
|||
import { useCallback } from 'react'
|
||||
import { normalizeForwards } from '../lib/form'
|
||||
import { MAX_TITLE_LENGTH } from '../lib/constants'
|
||||
import { useMe } from './me'
|
||||
|
||||
export function DiscussionForm ({
|
||||
item, sub, editThreshold, titleLabel = 'title',
|
||||
|
@ -23,11 +24,11 @@ export function DiscussionForm ({
|
|||
}) {
|
||||
const router = useRouter()
|
||||
const client = useApolloClient()
|
||||
const schema = discussionSchema(client)
|
||||
const me = useMe()
|
||||
const schema = discussionSchema(client, me)
|
||||
// if Web Share Target API was used
|
||||
const shareTitle = router.query.title
|
||||
|
||||
// const me = useMe()
|
||||
const [upsertDiscussion] = useMutation(
|
||||
gql`
|
||||
mutation upsertDiscussion($sub: String, $id: ID, $title: String!, $text: String, $boost: Int, $forward: [ItemForwardInput], $hash: String, $hmac: String) {
|
||||
|
|
|
@ -16,11 +16,13 @@ import { SubSelectInitial } from './sub-select-form'
|
|||
import CancelButton from './cancel-button'
|
||||
import { normalizeForwards } from '../lib/form'
|
||||
import { MAX_TITLE_LENGTH } from '../lib/constants'
|
||||
import { useMe } from './me'
|
||||
|
||||
export function LinkForm ({ item, sub, editThreshold, children }) {
|
||||
const router = useRouter()
|
||||
const client = useApolloClient()
|
||||
const schema = linkSchema(client)
|
||||
const me = useMe()
|
||||
const schema = linkSchema(client, me)
|
||||
// if Web Share Target API was used
|
||||
const shareUrl = router.query.url
|
||||
const shareTitle = router.query.title
|
||||
|
|
|
@ -12,11 +12,13 @@ import { SubSelectInitial } from './sub-select-form'
|
|||
import CancelButton from './cancel-button'
|
||||
import { useCallback } from 'react'
|
||||
import { normalizeForwards } from '../lib/form'
|
||||
import { useMe } from './me'
|
||||
|
||||
export function PollForm ({ item, sub, editThreshold, children }) {
|
||||
const router = useRouter()
|
||||
const client = useApolloClient()
|
||||
const schema = pollSchema(client)
|
||||
const me = useMe()
|
||||
const schema = pollSchema(client, me)
|
||||
|
||||
const [upsertPoll] = useMutation(
|
||||
gql`
|
||||
|
|
|
@ -58,7 +58,7 @@ async function usernameExists (client, name) {
|
|||
return !!user
|
||||
}
|
||||
|
||||
export function advPostSchemaMembers (client) {
|
||||
export function advPostSchemaMembers (client, me) {
|
||||
return {
|
||||
boost: intValidator
|
||||
.min(BOOST_MIN, `must be blank or at least ${BOOST_MIN}`).test({
|
||||
|
@ -66,18 +66,25 @@ export function advPostSchemaMembers (client) {
|
|||
test: async boost => !boost || boost % BOOST_MIN === 0,
|
||||
message: `must be divisble be ${BOOST_MIN}`
|
||||
}),
|
||||
// XXX this lets you forward to youself (it's financially equivalent but it should be disallowed)
|
||||
forward: array()
|
||||
.max(MAX_FORWARDS, `you can only configure ${MAX_FORWARDS} forward recipients`)
|
||||
.of(object().shape({
|
||||
nym: string().required('must specify a stacker').test({
|
||||
name: 'nym',
|
||||
test: async name => {
|
||||
if (!name || !name.length) return true
|
||||
return await usernameExists(client, name)
|
||||
},
|
||||
message: 'stacker does not exist'
|
||||
}),
|
||||
nym: string().required('must specify a stacker')
|
||||
.test({
|
||||
name: 'nym',
|
||||
test: async name => {
|
||||
if (!name || !name.length) return false
|
||||
return await usernameExists(client, name)
|
||||
},
|
||||
message: 'stacker does not exist'
|
||||
})
|
||||
.test({
|
||||
name: 'self',
|
||||
test: async name => {
|
||||
return me?.name !== name
|
||||
},
|
||||
message: 'cannot forward to yourself'
|
||||
}),
|
||||
pct: intValidator.required('must specify a percentage').min(1, 'percentage must be at least 1').max(100, 'percentage must not exceed 100')
|
||||
}))
|
||||
.compact((v) => !v.nym && !v.pct)
|
||||
|
@ -100,35 +107,35 @@ export function subSelectSchemaMembers (client) {
|
|||
}
|
||||
}
|
||||
|
||||
export function bountySchema (client) {
|
||||
export function bountySchema (client, me) {
|
||||
return object({
|
||||
title: titleValidator,
|
||||
bounty: intValidator
|
||||
.min(1000, 'must be at least 1000')
|
||||
.max(1000000, 'must be at most 1m'),
|
||||
...advPostSchemaMembers(client),
|
||||
...advPostSchemaMembers(client, me),
|
||||
...subSelectSchemaMembers()
|
||||
})
|
||||
}
|
||||
|
||||
export function discussionSchema (client) {
|
||||
export function discussionSchema (client, me) {
|
||||
return object({
|
||||
title: titleValidator,
|
||||
...advPostSchemaMembers(client),
|
||||
...advPostSchemaMembers(client, me),
|
||||
...subSelectSchemaMembers()
|
||||
})
|
||||
}
|
||||
|
||||
export function linkSchema (client) {
|
||||
export function linkSchema (client, me) {
|
||||
return object({
|
||||
title: titleValidator,
|
||||
url: string().matches(URL_REGEXP, 'invalid url').required('required'),
|
||||
...advPostSchemaMembers(client),
|
||||
...advPostSchemaMembers(client, me),
|
||||
...subSelectSchemaMembers()
|
||||
})
|
||||
}
|
||||
|
||||
export function pollSchema (client, numExistingChoices = 0) {
|
||||
export function pollSchema (client, me, numExistingChoices = 0) {
|
||||
return object({
|
||||
title: titleValidator,
|
||||
options: array().of(
|
||||
|
@ -144,7 +151,7 @@ export function pollSchema (client, numExistingChoices = 0) {
|
|||
message: `at least ${MIN_POLL_NUM_CHOICES} choices required`,
|
||||
test: arr => arr.length >= MIN_POLL_NUM_CHOICES - numExistingChoices
|
||||
}),
|
||||
...advPostSchemaMembers(client),
|
||||
...advPostSchemaMembers(client, me),
|
||||
...subSelectSchemaMembers()
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue