replace greeter mode with investment filter (#1291)
* replace greeter mode with investment filter * change name to satsFilter * drop freebie column --------- Co-authored-by: k00b <k00b@stacker.news>
This commit is contained in:
parent
e897a2d1dc
commit
c5f043c625
@ -1,7 +1,7 @@
|
|||||||
import { ANON_ITEM_SPAM_INTERVAL, ITEM_SPAM_INTERVAL, USER_ID } from '@/lib/constants'
|
import { ANON_ITEM_SPAM_INTERVAL, ITEM_SPAM_INTERVAL, USER_ID } from '@/lib/constants'
|
||||||
import { notifyItemMention, notifyItemParents, notifyMention, notifyTerritorySubscribers, notifyUserSubscribers } from '@/lib/webPush'
|
import { notifyItemMention, notifyItemParents, notifyMention, notifyTerritorySubscribers, notifyUserSubscribers } from '@/lib/webPush'
|
||||||
import { getItemMentions, getMentions, performBotBehavior } from './lib/item'
|
import { getItemMentions, getMentions, performBotBehavior } from './lib/item'
|
||||||
import { satsToMsats } from '@/lib/format'
|
import { msatsToSats, satsToMsats } from '@/lib/format'
|
||||||
|
|
||||||
export const anonable = true
|
export const anonable = true
|
||||||
export const supportsPessimism = true
|
export const supportsPessimism = true
|
||||||
@ -51,8 +51,7 @@ export async function perform (args, context) {
|
|||||||
itemActs.push({
|
itemActs.push({
|
||||||
msats: cost - boostMsats, act: 'FEE', userId: data.userId, ...invoiceData
|
msats: cost - boostMsats, act: 'FEE', userId: data.userId, ...invoiceData
|
||||||
})
|
})
|
||||||
} else {
|
data.cost = msatsToSats(cost - boostMsats)
|
||||||
data.freebie = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const mentions = await getMentions(args, context)
|
const mentions = await getMentions(args, context)
|
||||||
|
@ -30,12 +30,12 @@ function commentsOrderByClause (me, models, sort) {
|
|||||||
return `ORDER BY COALESCE(
|
return `ORDER BY COALESCE(
|
||||||
personal_hot_score,
|
personal_hot_score,
|
||||||
${orderByNumerator(models, 0)}/POWER(GREATEST(3, EXTRACT(EPOCH FROM (now_utc() - "Item".created_at))/3600), 1.3)) DESC NULLS LAST,
|
${orderByNumerator(models, 0)}/POWER(GREATEST(3, EXTRACT(EPOCH FROM (now_utc() - "Item".created_at))/3600), 1.3)) DESC NULLS LAST,
|
||||||
"Item".msats DESC, ("Item".freebie IS FALSE) DESC, "Item".id DESC`
|
"Item".msats DESC, ("Item".cost > 0) DESC, "Item".id DESC`
|
||||||
} else {
|
} else {
|
||||||
if (sort === 'top') {
|
if (sort === 'top') {
|
||||||
return `ORDER BY ${orderByNumerator(models, 0)} DESC NULLS LAST, "Item".msats DESC, ("Item".freebie IS FALSE) DESC, "Item".id DESC`
|
return `ORDER BY ${orderByNumerator(models, 0)} DESC NULLS LAST, "Item".msats DESC, ("Item".cost > 0) DESC, "Item".id DESC`
|
||||||
} else {
|
} else {
|
||||||
return `ORDER BY ${orderByNumerator(models, 0)}/POWER(GREATEST(3, EXTRACT(EPOCH FROM (now_utc() - "Item".created_at))/3600), 1.3) DESC NULLS LAST, "Item".msats DESC, ("Item".freebie IS FALSE) DESC, "Item".id DESC`
|
return `ORDER BY ${orderByNumerator(models, 0)}/POWER(GREATEST(3, EXTRACT(EPOCH FROM (now_utc() - "Item".created_at))/3600), 1.3) DESC NULLS LAST, "Item".msats DESC, ("Item".cost > 0) DESC, "Item".id DESC`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,22 +225,16 @@ export async function filterClause (me, models, type) {
|
|||||||
|
|
||||||
// handle freebies
|
// handle freebies
|
||||||
// by default don't include freebies unless they have upvotes
|
// by default don't include freebies unless they have upvotes
|
||||||
let freebieClauses = ['NOT "Item".freebie', '"Item"."weightedVotes" - "Item"."weightedDownVotes" > 0']
|
let investmentClause = '("Item".cost + "Item".boost + ("Item".msats / 1000)) >= 10'
|
||||||
if (me) {
|
if (me) {
|
||||||
const user = await models.user.findUnique({ where: { id: me.id } })
|
const user = await models.user.findUnique({ where: { id: me.id } })
|
||||||
// wild west mode has everything
|
|
||||||
if (user.wildWestMode) {
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
// greeter mode includes freebies if feebies haven't been flagged
|
|
||||||
if (user.greeterMode) {
|
|
||||||
freebieClauses = ['NOT "Item".freebie', '"Item"."weightedVotes" - "Item"."weightedDownVotes" >= 0']
|
|
||||||
}
|
|
||||||
|
|
||||||
// always include if it's mine
|
investmentClause = `(("Item".cost + "Item".boost + ("Item".msats / 1000)) >= ${user.satsFilter} OR "Item"."userId" = ${me.id})`
|
||||||
freebieClauses.push(`"Item"."userId" = ${me.id}`)
|
|
||||||
|
if (user.wildWestMode) {
|
||||||
|
return investmentClause
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const freebieClause = '(' + freebieClauses.join(' OR ') + ')'
|
|
||||||
|
|
||||||
// handle outlawed
|
// handle outlawed
|
||||||
// if the item is above the threshold or is mine
|
// if the item is above the threshold or is mine
|
||||||
@ -250,7 +244,7 @@ export async function filterClause (me, models, type) {
|
|||||||
}
|
}
|
||||||
const outlawClause = '(' + outlawClauses.join(' OR ') + ')'
|
const outlawClause = '(' + outlawClauses.join(' OR ') + ')'
|
||||||
|
|
||||||
return [freebieClause, outlawClause]
|
return [investmentClause, outlawClause]
|
||||||
}
|
}
|
||||||
|
|
||||||
function typeClause (type) {
|
function typeClause (type) {
|
||||||
@ -268,7 +262,7 @@ function typeClause (type) {
|
|||||||
case 'comments':
|
case 'comments':
|
||||||
return '"Item"."parentId" IS NOT NULL'
|
return '"Item"."parentId" IS NOT NULL'
|
||||||
case 'freebies':
|
case 'freebies':
|
||||||
return '"Item".freebie'
|
return '"Item".cost = 0'
|
||||||
case 'outlawed':
|
case 'outlawed':
|
||||||
return `"Item"."weightedVotes" - "Item"."weightedDownVotes" <= -${ITEM_FILTER_THRESHOLD} OR "Item".outlawed`
|
return `"Item"."weightedVotes" - "Item"."weightedDownVotes" <= -${ITEM_FILTER_THRESHOLD} OR "Item".outlawed`
|
||||||
case 'borderland':
|
case 'borderland':
|
||||||
@ -470,10 +464,10 @@ export default {
|
|||||||
'"Item".bio = false',
|
'"Item".bio = false',
|
||||||
activeOrMine(me),
|
activeOrMine(me),
|
||||||
await filterClause(me, models, type))}
|
await filterClause(me, models, type))}
|
||||||
ORDER BY ${orderByNumerator(models, 0)}/POWER(GREATEST(3, EXTRACT(EPOCH FROM (now_utc() - "Item".created_at))/3600), 1.3) DESC NULLS LAST, "Item".msats DESC, ("Item".freebie IS FALSE) DESC, "Item".id DESC
|
ORDER BY ${orderByNumerator(models, 0)}/POWER(GREATEST(3, EXTRACT(EPOCH FROM (now_utc() - "Item".created_at))/3600), 1.3) DESC NULLS LAST, "Item".msats DESC, ("Item".cost > 0) DESC, "Item".id DESC
|
||||||
OFFSET $1
|
OFFSET $1
|
||||||
LIMIT $2`,
|
LIMIT $2`,
|
||||||
orderBy: `ORDER BY ${orderByNumerator(models, 0)}/POWER(GREATEST(3, EXTRACT(EPOCH FROM (now_utc() - "Item".created_at))/3600), 1.3) DESC NULLS LAST, "Item".msats DESC, ("Item".freebie IS FALSE) DESC, "Item".id DESC`
|
orderBy: `ORDER BY ${orderByNumerator(models, 0)}/POWER(GREATEST(3, EXTRACT(EPOCH FROM (now_utc() - "Item".created_at))/3600), 1.3) DESC NULLS LAST, "Item".msats DESC, ("Item".cost > 0) DESC, "Item".id DESC`
|
||||||
}, decodedCursor.offset, limit, ...subArr)
|
}, decodedCursor.offset, limit, ...subArr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1054,6 +1048,9 @@ export default {
|
|||||||
freedFreebie: async (item) => {
|
freedFreebie: async (item) => {
|
||||||
return item.weightedVotes - item.weightedDownVotes > 0
|
return item.weightedVotes - item.weightedDownVotes > 0
|
||||||
},
|
},
|
||||||
|
freebie: async (item) => {
|
||||||
|
return item.cost === 0
|
||||||
|
},
|
||||||
meSats: async (item, args, { me, models }) => {
|
meSats: async (item, args, { me, models }) => {
|
||||||
if (!me) return 0
|
if (!me) return 0
|
||||||
if (typeof item.meMsats !== 'undefined') {
|
if (typeof item.meMsats !== 'undefined') {
|
||||||
@ -1255,7 +1252,7 @@ export const updateItem = async (parent, { sub: subName, forward, ...item }, { m
|
|||||||
const differentSub = subName && old.subName !== subName
|
const differentSub = subName && old.subName !== subName
|
||||||
if (differentSub) {
|
if (differentSub) {
|
||||||
const sub = await models.sub.findUnique({ where: { name: subName } })
|
const sub = await models.sub.findUnique({ where: { name: subName } })
|
||||||
if (old.freebie) {
|
if (old.cost === 0) {
|
||||||
if (!sub.allowFreebies) {
|
if (!sub.allowFreebies) {
|
||||||
throw new GraphQLError(`~${subName} does not allow freebies`, { extensions: { code: 'BAD_INPUT' } })
|
throw new GraphQLError(`~${subName} does not allow freebies`, { extensions: { code: 'BAD_INPUT' } })
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ export default gql`
|
|||||||
diagnostics: Boolean!
|
diagnostics: Boolean!
|
||||||
noReferralLinks: Boolean!
|
noReferralLinks: Boolean!
|
||||||
fiatCurrency: String!
|
fiatCurrency: String!
|
||||||
greeterMode: Boolean!
|
satsFilter: Int!
|
||||||
hideBookmarks: Boolean!
|
hideBookmarks: Boolean!
|
||||||
hideCowboyHat: Boolean!
|
hideCowboyHat: Boolean!
|
||||||
hideGithub: Boolean!
|
hideGithub: Boolean!
|
||||||
@ -140,7 +140,7 @@ export default gql`
|
|||||||
diagnostics: Boolean!
|
diagnostics: Boolean!
|
||||||
noReferralLinks: Boolean!
|
noReferralLinks: Boolean!
|
||||||
fiatCurrency: String!
|
fiatCurrency: String!
|
||||||
greeterMode: Boolean!
|
satsFilter: Int!
|
||||||
hideBookmarks: Boolean!
|
hideBookmarks: Boolean!
|
||||||
hideCowboyHat: Boolean!
|
hideCowboyHat: Boolean!
|
||||||
hideGithub: Boolean!
|
hideGithub: Boolean!
|
||||||
|
@ -97,7 +97,7 @@ export default function Comment ({
|
|||||||
}) {
|
}) {
|
||||||
const [edit, setEdit] = useState()
|
const [edit, setEdit] = useState()
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
const isHiddenFreebie = !me?.privates?.wildWestMode && !me?.privates?.greeterMode && !item.mine && item.freebie && !item.freedFreebie
|
const isHiddenFreebie = me?.privates?.satsFilter !== 0 && !item.mine && item.freebie && !item.freedFreebie
|
||||||
const [collapse, setCollapse] = useState(
|
const [collapse, setCollapse] = useState(
|
||||||
(isHiddenFreebie || item?.user?.meMute || (item?.outlawed && !me?.privates?.wildWestMode)) && !includeParent
|
(isHiddenFreebie || item?.user?.meMute || (item?.outlawed && !me?.privates?.wildWestMode)) && !includeParent
|
||||||
? 'yep'
|
? 'yep'
|
||||||
|
@ -15,7 +15,7 @@ export const ME = gql`
|
|||||||
diagnostics
|
diagnostics
|
||||||
noReferralLinks
|
noReferralLinks
|
||||||
fiatCurrency
|
fiatCurrency
|
||||||
greeterMode
|
satsFilter
|
||||||
hideCowboyHat
|
hideCowboyHat
|
||||||
hideFromTopUsers
|
hideFromTopUsers
|
||||||
hideGithub
|
hideGithub
|
||||||
@ -104,7 +104,7 @@ export const SETTINGS_FIELDS = gql`
|
|||||||
nostrCrossposting
|
nostrCrossposting
|
||||||
nostrRelays
|
nostrRelays
|
||||||
wildWestMode
|
wildWestMode
|
||||||
greeterMode
|
satsFilter
|
||||||
nsfwMode
|
nsfwMode
|
||||||
authMethods {
|
authMethods {
|
||||||
lightning
|
lightning
|
||||||
|
@ -579,6 +579,7 @@ export const settingsSchema = object().shape({
|
|||||||
diagnostics: boolean(),
|
diagnostics: boolean(),
|
||||||
noReferralLinks: boolean(),
|
noReferralLinks: boolean(),
|
||||||
hideIsContributor: boolean(),
|
hideIsContributor: boolean(),
|
||||||
|
satsFilter: intValidator.required('required').min(0, 'must be at least 0').max(1000, 'must be at most 1000'),
|
||||||
zapUndos: intValidator.nullable().min(0, 'must be greater or equal to 0')
|
zapUndos: intValidator.nullable().min(0, 'must be greater or equal to 0')
|
||||||
// exclude from cyclic analysis. see https://github.com/jquense/yup/issues/720
|
// exclude from cyclic analysis. see https://github.com/jquense/yup/issues/720
|
||||||
}, [['tipRandomMax', 'tipRandomMin']])
|
}, [['tipRandomMax', 'tipRandomMin']])
|
||||||
|
@ -140,7 +140,7 @@ export default function Settings ({ ssrData }) {
|
|||||||
hideTwitter: settings?.hideTwitter,
|
hideTwitter: settings?.hideTwitter,
|
||||||
imgproxyOnly: settings?.imgproxyOnly,
|
imgproxyOnly: settings?.imgproxyOnly,
|
||||||
wildWestMode: settings?.wildWestMode,
|
wildWestMode: settings?.wildWestMode,
|
||||||
greeterMode: settings?.greeterMode,
|
satsFilter: settings?.satsFilter,
|
||||||
nsfwMode: settings?.nsfwMode,
|
nsfwMode: settings?.nsfwMode,
|
||||||
nostrPubkey: settings?.nostrPubkey ? bech32encode(settings.nostrPubkey) : '',
|
nostrPubkey: settings?.nostrPubkey ? bech32encode(settings.nostrPubkey) : '',
|
||||||
nostrCrossposting: settings?.nostrCrossposting,
|
nostrCrossposting: settings?.nostrCrossposting,
|
||||||
@ -152,7 +152,11 @@ export default function Settings ({ ssrData }) {
|
|||||||
noReferralLinks: settings?.noReferralLinks
|
noReferralLinks: settings?.noReferralLinks
|
||||||
}}
|
}}
|
||||||
schema={settingsSchema}
|
schema={settingsSchema}
|
||||||
onSubmit={async ({ tipDefault, tipRandom, tipRandomMin, tipRandomMax, withdrawMaxFeeDefault, zapUndos, zapUndosEnabled, nostrPubkey, nostrRelays, ...values }) => {
|
onSubmit={async ({
|
||||||
|
tipDefault, tipRandom, tipRandomMin, tipRandomMax, withdrawMaxFeeDefault,
|
||||||
|
zapUndos, zapUndosEnabled, nostrPubkey, nostrRelays, satsFilter,
|
||||||
|
...values
|
||||||
|
}) => {
|
||||||
if (nostrPubkey.length === 0) {
|
if (nostrPubkey.length === 0) {
|
||||||
nostrPubkey = null
|
nostrPubkey = null
|
||||||
} else {
|
} else {
|
||||||
@ -172,6 +176,7 @@ export default function Settings ({ ssrData }) {
|
|||||||
tipRandomMin: tipRandom ? Number(tipRandomMin) : null,
|
tipRandomMin: tipRandom ? Number(tipRandomMin) : null,
|
||||||
tipRandomMax: tipRandom ? Number(tipRandomMax) : null,
|
tipRandomMax: tipRandom ? Number(tipRandomMax) : null,
|
||||||
withdrawMaxFeeDefault: Number(withdrawMaxFeeDefault),
|
withdrawMaxFeeDefault: Number(withdrawMaxFeeDefault),
|
||||||
|
satsFilter: Number(satsFilter),
|
||||||
zapUndos: zapUndosEnabled ? Number(zapUndos) : null,
|
zapUndos: zapUndosEnabled ? Number(zapUndos) : null,
|
||||||
nostrPubkey,
|
nostrPubkey,
|
||||||
nostrRelays: nostrRelaysFiltered,
|
nostrRelays: nostrRelaysFiltered,
|
||||||
@ -467,7 +472,27 @@ export default function Settings ({ ssrData }) {
|
|||||||
label={<>don't create referral links on copy</>}
|
label={<>don't create referral links on copy</>}
|
||||||
name='noReferralLinks'
|
name='noReferralLinks'
|
||||||
/>
|
/>
|
||||||
<div className='form-label'>content</div>
|
<h4>content</h4>
|
||||||
|
<Input
|
||||||
|
label={
|
||||||
|
<div className='d-flex align-items-center'>filter by sats
|
||||||
|
<Info>
|
||||||
|
<ul className='fw-bold'>
|
||||||
|
<li>hide the post if the sum of these is less than your setting:</li>
|
||||||
|
<ul>
|
||||||
|
<li>posting cost</li>
|
||||||
|
<li>total sats from zaps</li>
|
||||||
|
<li>boost</li>
|
||||||
|
</ul>
|
||||||
|
<li>set to zero to be a greeter, with the tradeoff of seeing more spam</li>
|
||||||
|
</ul>
|
||||||
|
</Info>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
name='satsFilter'
|
||||||
|
required
|
||||||
|
append={<InputGroup.Text className='text-monospace'>sats</InputGroup.Text>}
|
||||||
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={
|
label={
|
||||||
<div className='d-flex align-items-center'>wild west mode
|
<div className='d-flex align-items-center'>wild west mode
|
||||||
@ -482,21 +507,6 @@ export default function Settings ({ ssrData }) {
|
|||||||
name='wildWestMode'
|
name='wildWestMode'
|
||||||
groupClassName='mb-0'
|
groupClassName='mb-0'
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
|
||||||
label={
|
|
||||||
<div className='d-flex align-items-center'>greeter mode
|
|
||||||
<Info>
|
|
||||||
<ul className='fw-bold'>
|
|
||||||
<li>see and screen free posts and comments</li>
|
|
||||||
<li>help onboard new stackers to SN and Lightning</li>
|
|
||||||
<li>you might be subject to more spam</li>
|
|
||||||
</ul>
|
|
||||||
</Info>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
name='greeterMode'
|
|
||||||
groupClassName='mb-0'
|
|
||||||
/>
|
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={
|
label={
|
||||||
<div className='d-flex align-items-center'>nsfw mode
|
<div className='d-flex align-items-center'>nsfw mode
|
||||||
|
16
prisma/migrations/20240808234214_sats_filter/migration.sql
Normal file
16
prisma/migrations/20240808234214_sats_filter/migration.sql
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Item" ADD COLUMN "cost" INTEGER NOT NULL DEFAULT 0;
|
||||||
|
|
||||||
|
-- use existing "ItemAct".act = FEE AND "Item"."userId" = "ItemAct"."userId" to calculate the cost for existing "Item"s
|
||||||
|
UPDATE "Item" SET "cost" = "ItemAct"."msats" / 1000
|
||||||
|
FROM "ItemAct"
|
||||||
|
WHERE "Item"."id" = "ItemAct"."itemId" AND "ItemAct"."act" = 'FEE' AND "Item"."userId" = "ItemAct"."userId";
|
||||||
|
|
||||||
|
ALTER TABLE "users" ADD COLUMN "satsFilter" INTEGER NOT NULL DEFAULT 10;
|
||||||
|
|
||||||
|
UPDATE "users" SET "satsFilter" = 0 WHERE "greeterMode";
|
||||||
|
|
||||||
|
ALTER TABLE "users" DROP COLUMN "greeterMode";
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "Item_cost_idx" ON "Item"("cost");
|
@ -54,7 +54,7 @@ model User {
|
|||||||
upvoteTrust Float @default(0)
|
upvoteTrust Float @default(0)
|
||||||
hideInvoiceDesc Boolean @default(false)
|
hideInvoiceDesc Boolean @default(false)
|
||||||
wildWestMode Boolean @default(false)
|
wildWestMode Boolean @default(false)
|
||||||
greeterMode Boolean @default(false)
|
satsFilter Int @default(10)
|
||||||
nsfwMode Boolean @default(false)
|
nsfwMode Boolean @default(false)
|
||||||
fiatCurrency String @default("USD")
|
fiatCurrency String @default("USD")
|
||||||
withdrawMaxFeeDefault Int @default(10)
|
withdrawMaxFeeDefault Int @default(10)
|
||||||
@ -425,6 +425,7 @@ model Item {
|
|||||||
lastZapAt DateTime?
|
lastZapAt DateTime?
|
||||||
ncomments Int @default(0)
|
ncomments Int @default(0)
|
||||||
msats BigInt @default(0)
|
msats BigInt @default(0)
|
||||||
|
cost Int @default(0)
|
||||||
weightedDownVotes Float @default(0)
|
weightedDownVotes Float @default(0)
|
||||||
bio Boolean @default(false)
|
bio Boolean @default(false)
|
||||||
freebie Boolean @default(false)
|
freebie Boolean @default(false)
|
||||||
@ -489,6 +490,7 @@ model Item {
|
|||||||
@@index([weightedVotes], map: "Item.weightedVotes_index")
|
@@index([weightedVotes], map: "Item.weightedVotes_index")
|
||||||
@@index([invoiceId])
|
@@index([invoiceId])
|
||||||
@@index([invoiceActionState])
|
@@index([invoiceActionState])
|
||||||
|
@@index([cost])
|
||||||
}
|
}
|
||||||
|
|
||||||
// we use this to denormalize a user's aggregated interactions (zaps) with an item
|
// we use this to denormalize a user's aggregated interactions (zaps) with an item
|
||||||
|
Loading…
x
Reference in New Issue
Block a user