Allow SN users to edit special items forever (#1204)
* Allow SN users to edit special items * Refactor item edit validation * Create object for user IDs * Remove anon from SN_USER_IDS * Fix isMine and myBio checks * Don't update author * remove anon from trust graph --------- Co-authored-by: keyan <keyan.kousha+huumn@gmail.com>
This commit is contained in:
parent
e9aa268996
commit
86b857b8d4
|
@ -1,4 +1,4 @@
|
|||
import { ANON_USER_ID, AWS_S3_URL_REGEXP } from '@/lib/constants'
|
||||
import { USER_ID, AWS_S3_URL_REGEXP } from '@/lib/constants'
|
||||
import { msatsToSats } from '@/lib/format'
|
||||
|
||||
export default {
|
||||
|
@ -17,7 +17,7 @@ export function uploadIdsFromText (text, { models }) {
|
|||
export async function imageFeesInfo (s3Keys, { models, me }) {
|
||||
// returns info object in this format:
|
||||
// { bytes24h: int, bytesUnpaid: int, nUnpaid: int, imageFeeMsats: BigInt }
|
||||
const [info] = await models.$queryRawUnsafe('SELECT * FROM image_fees_info($1::INTEGER, $2::INTEGER[])', me ? me.id : ANON_USER_ID, s3Keys)
|
||||
const [info] = await models.$queryRawUnsafe('SELECT * FROM image_fees_info($1::INTEGER, $2::INTEGER[])', me ? me.id : USER_ID.anon, s3Keys)
|
||||
const imageFee = msatsToSats(info.imageFeeMsats)
|
||||
const totalFeesMsats = info.nUnpaid * Number(info.imageFeeMsats)
|
||||
const totalFees = msatsToSats(totalFeesMsats)
|
||||
|
|
|
@ -8,8 +8,8 @@ import domino from 'domino'
|
|||
import {
|
||||
ITEM_SPAM_INTERVAL, ITEM_FILTER_THRESHOLD,
|
||||
COMMENT_DEPTH_LIMIT, COMMENT_TYPE_QUERY,
|
||||
ANON_USER_ID, ANON_ITEM_SPAM_INTERVAL, POLL_COST,
|
||||
ITEM_ALLOW_EDITS, GLOBAL_SEED, ANON_FEE_MULTIPLIER, NOFOLLOW_LIMIT, UNKNOWN_LINK_REL
|
||||
USER_ID, ANON_ITEM_SPAM_INTERVAL, POLL_COST,
|
||||
ITEM_ALLOW_EDITS, GLOBAL_SEED, ANON_FEE_MULTIPLIER, NOFOLLOW_LIMIT, UNKNOWN_LINK_REL, SN_USER_IDS
|
||||
} from '@/lib/constants'
|
||||
import { msatsToSats } from '@/lib/format'
|
||||
import { parse } from 'tldts'
|
||||
|
@ -876,7 +876,7 @@ export default {
|
|||
models.$queryRaw`
|
||||
SELECT
|
||||
item_act(${Number(id)}::INTEGER,
|
||||
${me?.id || ANON_USER_ID}::INTEGER, ${act}::"ItemActType", ${Number(sats)}::INTEGER)`,
|
||||
${me?.id || USER_ID.anon}::INTEGER, ${act}::"ItemActType", ${Number(sats)}::INTEGER)`,
|
||||
{ models, lnd, me, hash, hmac, fee: sats }
|
||||
)
|
||||
}
|
||||
|
@ -1157,7 +1157,7 @@ export default {
|
|||
return parent.otsHash
|
||||
},
|
||||
deleteScheduledAt: async (item, args, { me, models }) => {
|
||||
const meId = me?.id ?? ANON_USER_ID
|
||||
const meId = me?.id ?? USER_ID.anon
|
||||
if (meId !== item.userId) {
|
||||
// Only query for deleteScheduledAt for your own items to keep DB queries minimized
|
||||
return null
|
||||
|
@ -1166,8 +1166,8 @@ export default {
|
|||
return deleteJobs[0]?.startafter ?? null
|
||||
},
|
||||
reminderScheduledAt: async (item, args, { me, models }) => {
|
||||
const meId = me?.id ?? ANON_USER_ID
|
||||
if (meId !== item.userId || meId === ANON_USER_ID) {
|
||||
const meId = me?.id ?? USER_ID.anon
|
||||
if (meId !== item.userId || meId === USER_ID.anon) {
|
||||
// don't show reminders on an item if it isn't yours
|
||||
// don't support reminders for ANON
|
||||
return null
|
||||
|
@ -1227,10 +1227,21 @@ export const createMentions = async (item, models) => {
|
|||
export const updateItem = async (parent, { sub: subName, forward, options, ...item }, { me, models, lnd, hash, hmac }) => {
|
||||
// update iff this item belongs to me
|
||||
const old = await models.item.findUnique({ where: { id: Number(item.id) }, include: { sub: true } })
|
||||
if (Number(old.userId) !== Number(me?.id)) {
|
||||
|
||||
// author can always edit their own item
|
||||
const mid = Number(me?.id)
|
||||
const isMine = Number(old.userId) === mid
|
||||
|
||||
// allow admins to edit special items
|
||||
const allowEdit = ITEM_ALLOW_EDITS.includes(old.id)
|
||||
const adminEdit = SN_USER_IDS.includes(mid) && allowEdit
|
||||
|
||||
if (!isMine && !adminEdit) {
|
||||
throw new GraphQLError('item does not belong to you', { extensions: { code: 'FORBIDDEN' } })
|
||||
}
|
||||
if (subName && old.subName !== subName) {
|
||||
|
||||
const differentSub = subName && old.subName !== subName
|
||||
if (differentSub) {
|
||||
const sub = await models.sub.findUnique({ where: { name: subName } })
|
||||
if (old.freebie) {
|
||||
if (!sub.allowFreebies) {
|
||||
|
@ -1244,10 +1255,13 @@ export const updateItem = async (parent, { sub: subName, forward, options, ...it
|
|||
// in case they lied about their existing boost
|
||||
await ssValidate(advSchema, { boost: item.boost }, { models, me, existingBoost: old.boost })
|
||||
|
||||
// prevent update if it's not explicitly allowed, not their bio, not their job and older than 10 minutes
|
||||
const user = await models.user.findUnique({ where: { id: me.id } })
|
||||
if (!ITEM_ALLOW_EDITS.includes(old.id) && user.bioId !== old.id &&
|
||||
!isJob(item) && Date.now() > new Date(old.createdAt).getTime() + 10 * 60000) {
|
||||
|
||||
// prevent update if it's not explicitly allowed, not their bio, not their job and older than 10 minutes
|
||||
const myBio = user.bioId === old.id
|
||||
const timer = Date.now() < new Date(old.createdAt).getTime() + 10 * 60_000
|
||||
|
||||
if (!allowEdit && !myBio && !timer) {
|
||||
throw new GraphQLError('item can no longer be editted', { extensions: { code: 'BAD_INPUT' } })
|
||||
}
|
||||
|
||||
|
@ -1266,7 +1280,7 @@ export const updateItem = async (parent, { sub: subName, forward, options, ...it
|
|||
}
|
||||
}
|
||||
|
||||
item = { subName, userId: me.id, ...item }
|
||||
item = { subName, userId: old.userId, ...item }
|
||||
const fwdUsers = await getForwardUsers(models, forward)
|
||||
|
||||
const uploadIds = uploadIdsFromText(item.text, { models })
|
||||
|
@ -1303,7 +1317,7 @@ export const createItem = async (parent, { forward, options, ...item }, { me, mo
|
|||
item.subName = item.sub
|
||||
delete item.sub
|
||||
|
||||
item.userId = me ? Number(me.id) : ANON_USER_ID
|
||||
item.userId = me ? Number(me.id) : USER_ID.anon
|
||||
|
||||
const fwdUsers = await getForwardUsers(models, forward)
|
||||
if (item.url && !isJob(item)) {
|
||||
|
@ -1367,7 +1381,7 @@ const enqueueDeletionJob = async (item, models) => {
|
|||
}
|
||||
|
||||
const deleteReminderAndJob = async ({ me, item, models }) => {
|
||||
if (me?.id && me.id !== ANON_USER_ID) {
|
||||
if (me?.id && me.id !== USER_ID.anon) {
|
||||
await models.$transaction([
|
||||
models.$queryRawUnsafe(`
|
||||
DELETE FROM pgboss.job
|
||||
|
@ -1389,7 +1403,7 @@ const deleteReminderAndJob = async ({ me, item, models }) => {
|
|||
|
||||
const createReminderAndJob = async ({ me, item, models }) => {
|
||||
// disallow anon to use reminder
|
||||
if (!me || me.id === ANON_USER_ID) {
|
||||
if (!me || me.id === USER_ID.anon) {
|
||||
return
|
||||
}
|
||||
const reminderCommand = getReminderCommand(item.text)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { GraphQLError } from 'graphql'
|
||||
import { amountSchema, ssValidate } from '@/lib/validate'
|
||||
import serialize from './serial'
|
||||
import { ANON_USER_ID } from '@/lib/constants'
|
||||
import { USER_ID } from '@/lib/constants'
|
||||
import { getItem } from './item'
|
||||
import { topUsers } from './user'
|
||||
|
||||
|
@ -165,7 +165,7 @@ export default {
|
|||
await ssValidate(amountSchema, { amount: sats })
|
||||
|
||||
await serialize(
|
||||
models.$queryRaw`SELECT donate(${sats}::INTEGER, ${me?.id || ANON_USER_ID}::INTEGER)`,
|
||||
models.$queryRaw`SELECT donate(${sats}::INTEGER, ${me?.id || USER_ID.anon}::INTEGER)`,
|
||||
{ models, lnd, me, hash, hmac, fee: sats }
|
||||
)
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { GraphQLError } from 'graphql'
|
||||
import { ANON_USER_ID, IMAGE_PIXELS_MAX, UPLOAD_SIZE_MAX, UPLOAD_SIZE_MAX_AVATAR, UPLOAD_TYPES_ALLOW } from '@/lib/constants'
|
||||
import { USER_ID, IMAGE_PIXELS_MAX, UPLOAD_SIZE_MAX, UPLOAD_SIZE_MAX_AVATAR, UPLOAD_TYPES_ALLOW } from '@/lib/constants'
|
||||
import { createPresignedPost } from '@/api/s3'
|
||||
|
||||
export default {
|
||||
|
@ -26,7 +26,7 @@ export default {
|
|||
size,
|
||||
width,
|
||||
height,
|
||||
userId: me?.id || ANON_USER_ID,
|
||||
userId: me?.id || USER_ID.anon,
|
||||
paid: false
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import { decodeCursor, LIMIT, nextCursorEncoded } from '@/lib/cursor'
|
|||
import { msatsToSats } from '@/lib/format'
|
||||
import { bioSchema, emailSchema, settingsSchema, ssValidate, userSchema } from '@/lib/validate'
|
||||
import { getItem, updateItem, filterClause, createItem, whereClause, muteClause } from './item'
|
||||
import { ANON_USER_ID, DELETE_USER_ID, RESERVED_MAX_USER_ID, SN_NO_REWARDS_IDS } from '@/lib/constants'
|
||||
import { USER_ID, RESERVED_MAX_USER_ID, SN_NO_REWARDS_IDS } from '@/lib/constants'
|
||||
import { viewGroup } from './growth'
|
||||
import { timeUnitForRange, whenRange } from '@/lib/time'
|
||||
import assertApiKeyNotPermitted from './apiKey'
|
||||
|
@ -217,7 +217,7 @@ export default {
|
|||
SELECT name
|
||||
FROM users
|
||||
WHERE (
|
||||
id > ${RESERVED_MAX_USER_ID} OR id IN (${ANON_USER_ID}, ${DELETE_USER_ID})
|
||||
id > ${RESERVED_MAX_USER_ID} OR id IN (${USER_ID.anon}, ${USER_ID.delete})
|
||||
)
|
||||
AND SIMILARITY(name, ${q}) > 0.1
|
||||
ORDER BY SIMILARITY(name, ${q}) DESC
|
||||
|
@ -518,7 +518,7 @@ export default {
|
|||
return await models.$queryRaw`
|
||||
SELECT *
|
||||
FROM users
|
||||
WHERE (id > ${RESERVED_MAX_USER_ID} OR id IN (${ANON_USER_ID}, ${DELETE_USER_ID}))
|
||||
WHERE (id > ${RESERVED_MAX_USER_ID} OR id IN (${USER_ID.anon}, ${USER_ID.delete}))
|
||||
AND SIMILARITY(name, ${q}) > ${Number(similarity) || 0.1} ORDER BY SIMILARITY(name, ${q}) DESC LIMIT ${Number(limit) || 5}`
|
||||
},
|
||||
userStatsActions: async (parent, { when, from, to }, { me, models }) => {
|
||||
|
|
|
@ -7,7 +7,7 @@ import { SELECT } from './item'
|
|||
import { lnAddrOptions } from '@/lib/lnurl'
|
||||
import { msatsToSats, msatsToSatsDecimal, ensureB64 } from '@/lib/format'
|
||||
import { CLNAutowithdrawSchema, LNDAutowithdrawSchema, amountSchema, lnAddrAutowithdrawSchema, lnAddrSchema, ssValidate, withdrawlSchema } from '@/lib/validate'
|
||||
import { ANON_BALANCE_LIMIT_MSATS, ANON_INV_PENDING_LIMIT, ANON_USER_ID, BALANCE_LIMIT_MSATS, INVOICE_RETENTION_DAYS, INV_PENDING_LIMIT, USER_IDS_BALANCE_NO_LIMIT, Wallet } from '@/lib/constants'
|
||||
import { ANON_BALANCE_LIMIT_MSATS, ANON_INV_PENDING_LIMIT, USER_ID, BALANCE_LIMIT_MSATS, INVOICE_RETENTION_DAYS, INV_PENDING_LIMIT, USER_IDS_BALANCE_NO_LIMIT, Wallet } from '@/lib/constants'
|
||||
import { datePivot } from '@/lib/time'
|
||||
import assertGofacYourself from './ofac'
|
||||
import assertApiKeyNotPermitted from './apiKey'
|
||||
|
@ -28,7 +28,7 @@ export async function getInvoice (parent, { id }, { me, models, lnd }) {
|
|||
throw new GraphQLError('invoice not found', { extensions: { code: 'BAD_INPUT' } })
|
||||
}
|
||||
|
||||
if (inv.user.id === ANON_USER_ID) {
|
||||
if (inv.user.id === USER_ID.anon) {
|
||||
return inv
|
||||
}
|
||||
if (!me) {
|
||||
|
@ -339,7 +339,7 @@ export default {
|
|||
expirePivot = { seconds: Math.min(expireSecs, 180) }
|
||||
invLimit = ANON_INV_PENDING_LIMIT
|
||||
balanceLimit = ANON_BALANCE_LIMIT_MSATS
|
||||
id = ANON_USER_ID
|
||||
id = USER_ID.anon
|
||||
}
|
||||
|
||||
const user = await models.user.findUnique({ where: { id } })
|
||||
|
|
|
@ -2,7 +2,7 @@ import { useApolloClient } from '@apollo/client'
|
|||
import { useMe } from './me'
|
||||
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'
|
||||
import { datePivot, timeSince } from '@/lib/time'
|
||||
import { ANON_USER_ID, JIT_INVOICE_TIMEOUT_MS } from '@/lib/constants'
|
||||
import { USER_ID, JIT_INVOICE_TIMEOUT_MS } from '@/lib/constants'
|
||||
import { HAS_NOTIFICATIONS } from '@/fragments/notifications'
|
||||
import Item from './item'
|
||||
import { RootProvider } from './root'
|
||||
|
@ -25,7 +25,7 @@ export function ClientNotificationProvider ({ children }) {
|
|||
const me = useMe()
|
||||
// anons don't have access to /notifications
|
||||
// but we'll store client notifications anyway for simplicity's sake
|
||||
const storageKey = `client-notifications:${me?.id || ANON_USER_ID}`
|
||||
const storageKey = `client-notifications:${me?.id || USER_ID.anon}`
|
||||
|
||||
useEffect(() => {
|
||||
const loaded = loadNotifications(storageKey, client)
|
||||
|
|
|
@ -9,7 +9,7 @@ import Eye from '@/svgs/eye-fill.svg'
|
|||
import EyeClose from '@/svgs/eye-close-line.svg'
|
||||
import { useRouter } from 'next/router'
|
||||
import CommentEdit from './comment-edit'
|
||||
import { ANON_USER_ID, COMMENT_DEPTH_LIMIT, UNKNOWN_LINK_REL } from '@/lib/constants'
|
||||
import { USER_ID, COMMENT_DEPTH_LIMIT, UNKNOWN_LINK_REL } from '@/lib/constants'
|
||||
import PayBounty from './pay-bounty'
|
||||
import BountyIcon from '@/svgs/bounty-bag.svg'
|
||||
import ActionTooltip from './action-tooltip'
|
||||
|
@ -128,9 +128,9 @@ export default function Comment ({
|
|||
|
||||
const bottomedOut = depth === COMMENT_DEPTH_LIMIT
|
||||
// Don't show OP badge when anon user comments on anon user posts
|
||||
const op = root.user.name === item.user.name && Number(item.user.id) !== ANON_USER_ID
|
||||
const op = root.user.name === item.user.name && Number(item.user.id) !== USER_ID.anon
|
||||
? 'OP'
|
||||
: root.forwards?.some(f => f.user.name === item.user.name) && Number(item.user.id) !== ANON_USER_ID
|
||||
: root.forwards?.some(f => f.user.name === item.user.name) && Number(item.user.id) !== USER_ID.anon
|
||||
? 'fwd'
|
||||
: null
|
||||
const bountyPaid = root.bountyPaidTo?.includes(Number(item.id))
|
||||
|
|
|
@ -4,11 +4,11 @@ import Tooltip from 'react-bootstrap/Tooltip'
|
|||
import CowboyHatIcon from '@/svgs/cowboy.svg'
|
||||
import AnonIcon from '@/svgs/spy-fill.svg'
|
||||
import { numWithUnits } from '@/lib/format'
|
||||
import { AD_USER_ID, ANON_USER_ID } from '@/lib/constants'
|
||||
import { USER_ID } from '@/lib/constants'
|
||||
|
||||
export default function Hat ({ user, badge, className = 'ms-1', height = 16, width = 16 }) {
|
||||
if (!user || Number(user.id) === AD_USER_ID) return null
|
||||
if (Number(user.id) === ANON_USER_ID) {
|
||||
if (!user || Number(user.id) === USER_ID.ad) return null
|
||||
if (Number(user.id) === USER_ID.anon) {
|
||||
return (
|
||||
<HatTooltip overlayText='anonymous'>
|
||||
{badge
|
||||
|
|
|
@ -15,7 +15,7 @@ import BookmarkDropdownItem from './bookmark'
|
|||
import SubscribeDropdownItem from './subscribe'
|
||||
import { CopyLinkDropdownItem, CrosspostDropdownItem } from './share'
|
||||
import Hat from './hat'
|
||||
import { AD_USER_ID } from '@/lib/constants'
|
||||
import { USER_ID } from '@/lib/constants'
|
||||
import ActionDropdown from './action-dropdown'
|
||||
import MuteDropdownItem from './mute'
|
||||
import { DropdownItemUpVote } from './upvote'
|
||||
|
@ -58,7 +58,7 @@ export default function ItemInfo ({
|
|||
|
||||
return (
|
||||
<div className={className || `${styles.other}`}>
|
||||
{!(item.position && (pinnable || !item.subName)) && !(!item.parentId && Number(item.user?.id) === AD_USER_ID) &&
|
||||
{!(item.position && (pinnable || !item.subName)) && !(!item.parentId && Number(item.user?.id) === USER_ID.ad) &&
|
||||
<>
|
||||
<span title={`from ${numWithUnits(item.upvotes, {
|
||||
abbreviate: false,
|
||||
|
|
|
@ -2,7 +2,7 @@ import Link from 'next/link'
|
|||
import styles from './item.module.css'
|
||||
import UpVote from './upvote'
|
||||
import { useRef } from 'react'
|
||||
import { AD_USER_ID, UNKNOWN_LINK_REL } from '@/lib/constants'
|
||||
import { USER_ID, UNKNOWN_LINK_REL } from '@/lib/constants'
|
||||
import Pin from '@/svgs/pushpin-fill.svg'
|
||||
import reactStringReplace from 'react-string-replace'
|
||||
import PollIcon from '@/svgs/bar-chart-horizontal-fill.svg'
|
||||
|
@ -64,7 +64,7 @@ export default function Item ({ item, rank, belowTitle, right, full, children, s
|
|||
? <Pin width={24} height={24} className={styles.pin} />
|
||||
: item.meDontLikeSats > item.meSats
|
||||
? <DownZap width={24} height={24} className={styles.dontLike} item={item} />
|
||||
: Number(item.user?.id) === AD_USER_ID
|
||||
: Number(item.user?.id) === USER_ID.ad
|
||||
? <AdIcon width={24} height={24} className={styles.ad} />
|
||||
: <UpVote item={item} className={styles.upvote} />}
|
||||
<div className={styles.hunk}>
|
||||
|
@ -99,7 +99,7 @@ export default function Item ({ item, rank, belowTitle, right, full, children, s
|
|||
full={full} item={item}
|
||||
onQuoteReply={onQuoteReply}
|
||||
pinnable={pinnable}
|
||||
extraBadges={Number(item?.user?.id) === AD_USER_ID && <Badge className={styles.newComment} bg={null}>AD</Badge>}
|
||||
extraBadges={Number(item?.user?.id) === USER_ID.ad && <Badge className={styles.newComment} bg={null}>AD</Badge>}
|
||||
/>
|
||||
{belowTitle}
|
||||
</div>
|
||||
|
@ -130,7 +130,7 @@ export function ItemSummary ({ item }) {
|
|||
item={item}
|
||||
showUser={false}
|
||||
showActionDropdown={false}
|
||||
extraBadges={item.title && Number(item?.user?.id) === AD_USER_ID && <Badge className={styles.newComment} bg={null}>AD</Badge>}
|
||||
extraBadges={item.title && Number(item?.user?.id) === USER_ID.ad && <Badge className={styles.newComment} bg={null}>AD</Badge>}
|
||||
/>
|
||||
)
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import BackArrow from '../../svgs/arrow-left-line.svg'
|
|||
import { useCallback, useEffect, useState } from 'react'
|
||||
import Price from '../price'
|
||||
import SubSelect from '../sub-select'
|
||||
import { ANON_USER_ID, BALANCE_LIMIT_MSATS, Wallet } from '../../lib/constants'
|
||||
import { USER_ID, BALANCE_LIMIT_MSATS, Wallet } from '../../lib/constants'
|
||||
import Head from 'next/head'
|
||||
import NoteIcon from '../../svgs/notification-4-fill.svg'
|
||||
import { useMe } from '../me'
|
||||
|
@ -307,7 +307,7 @@ export function AnonDropdown ({ path }) {
|
|||
<Dropdown className={styles.dropdown} align='end'>
|
||||
<Dropdown.Toggle className='nav-link nav-item' id='profile' variant='custom'>
|
||||
<Nav.Link eventKey='anon' as='span' className='p-0 fw-normal'>
|
||||
@anon<Hat user={{ id: ANON_USER_ID }} />
|
||||
@anon<Hat user={{ id: USER_ID.anon }} />
|
||||
</Nav.Link>
|
||||
</Dropdown.Toggle>
|
||||
<Dropdown.Menu className='p-3'>
|
||||
|
|
|
@ -36,8 +36,16 @@ export const ITEM_SPAM_INTERVAL = '10m'
|
|||
export const ANON_ITEM_SPAM_INTERVAL = '0'
|
||||
export const INV_PENDING_LIMIT = 100
|
||||
export const BALANCE_LIMIT_MSATS = 100000000 // 100k sat
|
||||
export const SN_USER_IDS = [616, 6030, 4502, 27]
|
||||
export const SN_NO_REWARDS_IDS = [27, 4502]
|
||||
export const USER_ID = {
|
||||
k00b: 616,
|
||||
ek: 6030,
|
||||
sn: 4502,
|
||||
anon: 27,
|
||||
ad: 9,
|
||||
delete: 106
|
||||
}
|
||||
export const SN_USER_IDS = [USER_ID.k00b, USER_ID.ek, USER_ID.sn]
|
||||
export const SN_NO_REWARDS_IDS = [USER_ID.anon, USER_ID.sn]
|
||||
export const ANON_INV_PENDING_LIMIT = 1000
|
||||
export const ANON_BALANCE_LIMIT_MSATS = 0 // disable
|
||||
export const MAX_POLL_NUM_CHOICES = 10
|
||||
|
@ -54,17 +62,14 @@ export const ITEM_TYPES_USER = ['all', 'posts', 'comments', 'bounties', 'links',
|
|||
export const ITEM_TYPES = ['all', 'posts', 'comments', 'bounties', 'links', 'discussions', 'polls', 'freebies', 'bios', 'jobs']
|
||||
export const ITEM_TYPES_UNIVERSAL = ['all', 'posts', 'comments', 'freebies']
|
||||
export const OLD_ITEM_DAYS = 3
|
||||
export const ANON_USER_ID = 27
|
||||
export const DELETE_USER_ID = 106
|
||||
export const AD_USER_ID = 9
|
||||
export const ANON_FEE_MULTIPLIER = 100
|
||||
export const SSR = typeof window === 'undefined'
|
||||
export const MAX_FORWARDS = 5
|
||||
export const LNURLP_COMMENT_MAX_LENGTH = 1000
|
||||
export const RESERVED_MAX_USER_ID = 615
|
||||
export const GLOBAL_SEED = 616
|
||||
export const GLOBAL_SEED = USER_ID.k00b
|
||||
export const FREEBIE_BASE_COST_THRESHOLD = 10
|
||||
export const USER_IDS_BALANCE_NO_LIMIT = [...SN_USER_IDS, AD_USER_ID]
|
||||
export const USER_IDS_BALANCE_NO_LIMIT = [...SN_USER_IDS, USER_ID.anon, USER_ID.ad]
|
||||
|
||||
// WIP ultimately subject to this list: https://ofac.treasury.gov/sanctions-programs-and-country-information
|
||||
// From lawyers: north korea, cuba, iran, ukraine, syria
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import webPush from 'web-push'
|
||||
import removeMd from 'remove-markdown'
|
||||
import { ANON_USER_ID, COMMENT_DEPTH_LIMIT, FOUND_BLURBS, LOST_BLURBS } from './constants'
|
||||
import { USER_ID, COMMENT_DEPTH_LIMIT, FOUND_BLURBS, LOST_BLURBS } from './constants'
|
||||
import { msatsToSats, numWithUnits } from './format'
|
||||
import models from '@/api/models'
|
||||
import { isMuted } from '@/lib/user'
|
||||
|
@ -179,7 +179,7 @@ export const notifyTerritorySubscribers = async ({ models, item }) => {
|
|||
|
||||
export const notifyItemParents = async ({ models, item, me }) => {
|
||||
try {
|
||||
const user = await models.user.findUnique({ where: { id: me?.id || ANON_USER_ID } })
|
||||
const user = await models.user.findUnique({ where: { id: me?.id || USER_ID.anon } })
|
||||
const parents = await models.$queryRawUnsafe(
|
||||
'SELECT DISTINCT p."userId" FROM "Item" i JOIN "Item" p ON p.path @> i.path WHERE i.id = $1 and p."userId" <> $2 ' +
|
||||
'AND NOT EXISTS (SELECT 1 FROM "Mute" m WHERE m."muterId" = p."userId" AND m."mutedId" = $2)',
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { deleteObjects } from '@/api/s3'
|
||||
import { ANON_USER_ID } from '@/lib/constants'
|
||||
import { USER_ID } from '@/lib/constants'
|
||||
|
||||
export async function deleteUnusedImages ({ models }) {
|
||||
// delete all images in database and S3 which weren't paid in the last 24 hours
|
||||
|
@ -14,7 +14,7 @@ export async function deleteUnusedImages ({ models }) {
|
|||
AND NOT EXISTS (SELECT * FROM users WHERE "photoId" = "Upload".id)
|
||||
AND NOT EXISTS (SELECT * FROM "Item" WHERE "uploadId" = "Upload".id)
|
||||
))
|
||||
AND created_at < date_trunc('hour', now() - CASE WHEN "userId" = ${ANON_USER_ID} THEN interval '1 hour' ELSE interval '24 hours' END)`
|
||||
AND created_at < date_trunc('hour', now() - CASE WHEN "userId" = ${USER_ID.anon} THEN interval '1 hour' ELSE interval '24 hours' END)`
|
||||
|
||||
const s3Keys = unpaidImages.map(({ id }) => id)
|
||||
if (s3Keys.length === 0) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as math from 'mathjs'
|
||||
import { ANON_USER_ID, SN_USER_IDS } from '@/lib/constants.js'
|
||||
import { USER_ID, SN_USER_IDS } from '@/lib/constants.js'
|
||||
|
||||
export async function trust ({ boss, models }) {
|
||||
try {
|
||||
|
@ -127,7 +127,7 @@ async function getGraph (models) {
|
|||
FROM "ItemAct"
|
||||
JOIN "Item" ON "Item".id = "ItemAct"."itemId" AND "ItemAct".act IN ('FEE', 'TIP', 'DONT_LIKE_THIS')
|
||||
AND "Item"."parentId" IS NULL AND NOT "Item".bio AND "Item"."userId" <> "ItemAct"."userId"
|
||||
JOIN users ON "ItemAct"."userId" = users.id AND users.id <> ${ANON_USER_ID}
|
||||
JOIN users ON "ItemAct"."userId" = users.id AND users.id <> ${USER_ID.anon}
|
||||
GROUP BY user_id, name, item_id, user_at, against
|
||||
HAVING CASE WHEN
|
||||
"ItemAct".act = 'DONT_LIKE_THIS' THEN sum("ItemAct".msats) > ${AGAINST_MSAT_MIN}
|
||||
|
|
Loading…
Reference in New Issue