make anon fees consistent

This commit is contained in:
keyan 2023-12-10 16:56:06 -06:00
parent c8bca3ef63
commit ca02d627c1
5 changed files with 156 additions and 12 deletions

View File

@ -8,8 +8,8 @@ import domino from 'domino'
import { import {
ITEM_SPAM_INTERVAL, ITEM_FILTER_THRESHOLD, ITEM_SPAM_INTERVAL, ITEM_FILTER_THRESHOLD,
DONT_LIKE_THIS_COST, COMMENT_DEPTH_LIMIT, COMMENT_TYPE_QUERY, DONT_LIKE_THIS_COST, COMMENT_DEPTH_LIMIT, COMMENT_TYPE_QUERY,
ANON_COMMENT_FEE, ANON_USER_ID, ANON_POST_FEE, ANON_ITEM_SPAM_INTERVAL, POLL_COST, ANON_USER_ID, ANON_ITEM_SPAM_INTERVAL, POLL_COST,
ITEM_ALLOW_EDITS, GLOBAL_SEED ITEM_ALLOW_EDITS, GLOBAL_SEED, ANON_FEE_MULTIPLIER
} from '../../lib/constants' } from '../../lib/constants'
import { msatsToSats } from '../../lib/format' import { msatsToSats } from '../../lib/format'
import { parse } from 'tldts' import { parse } from 'tldts'
@ -476,7 +476,8 @@ export default {
FROM "Item" FROM "Item"
${whereClause( ${whereClause(
subClause(sub, 3, 'Item', true), subClause(sub, 3, 'Item', true),
muteClause(me))} muteClause(me),
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".freebie IS FALSE) DESC, "Item".id DESC
OFFSET $1 OFFSET $1
LIMIT $2`, LIMIT $2`,
@ -1126,7 +1127,17 @@ export const createItem = async (parent, { forward, options, ...item }, { me, mo
const uploadIds = uploadIdsFromText(item.text, { models }) const uploadIds = uploadIdsFromText(item.text, { models })
const { fees: imgFees } = await imageFeesInfo(uploadIds, { models, me }) const { fees: imgFees } = await imageFeesInfo(uploadIds, { models, me })
const enforceFee = (me ? undefined : (item.parentId ? ANON_COMMENT_FEE : (ANON_POST_FEE + (item.boost || 0)))) + imgFees let enforceFee
if (!me) {
if (item.parentId) {
enforceFee = ANON_FEE_MULTIPLIER
} else {
const sub = await models.sub.findUnique({ where: { name: item.subName } })
enforceFee = sub.baseCost * ANON_FEE_MULTIPLIER + (item.boost || 0)
}
enforceFee += imgFees
}
item = await serializeInvoicable( item = await serializeInvoicable(
models.$queryRawUnsafe( models.$queryRawUnsafe(
`${SELECT} FROM create_item($1::JSONB, $2::JSONB, $3::JSONB, '${spamInterval}'::INTERVAL, $4::INTEGER[]) AS "Item"`, `${SELECT} FROM create_item($1::JSONB, $2::JSONB, $3::JSONB, '${spamInterval}'::INTERVAL, $4::INTEGER[]) AS "Item"`,

View File

@ -4,7 +4,7 @@ import ActionTooltip from './action-tooltip'
import Info from './info' import Info from './info'
import styles from './fee-button.module.css' import styles from './fee-button.module.css'
import { gql, useQuery } from '@apollo/client' import { gql, useQuery } from '@apollo/client'
import { SSR } from '../lib/constants' import { ANON_FEE_MULTIPLIER, SSR } from '../lib/constants'
import { numWithUnits } from '../lib/format' import { numWithUnits } from '../lib/format'
import { useMe } from './me' import { useMe } from './me'
import AnonIcon from '../svgs/spy-fill.svg' import AnonIcon from '../svgs/spy-fill.svg'
@ -15,15 +15,13 @@ import { SubmitButton } from './form'
const FeeButtonContext = createContext() const FeeButtonContext = createContext()
export function postCommentBaseLineItems ({ baseCost = 1, comment = false, allowFreebies = true, me }) { export function postCommentBaseLineItems ({ baseCost = 1, comment = false, allowFreebies = true, me }) {
// XXX this doesn't match the logic on the server but it has the same
// result on fees ... will need to change the server logic to match
const anonCharge = me const anonCharge = me
? {} ? {}
: { : {
anonCharge: { anonCharge: {
term: 'x 100', term: `x ${ANON_FEE_MULTIPLIER}`,
label: 'anon mult', label: 'anon mult',
modifier: (cost) => cost * 100 modifier: (cost) => cost * ANON_FEE_MULTIPLIER
} }
} }
return { return {

View File

@ -50,8 +50,7 @@ export const OLD_ITEM_DAYS = 3
export const ANON_USER_ID = 27 export const ANON_USER_ID = 27
export const DELETE_USER_ID = 106 export const DELETE_USER_ID = 106
export const AD_USER_ID = 9 export const AD_USER_ID = 9
export const ANON_POST_FEE = 1000 export const ANON_FEE_MULTIPLIER = 100
export const ANON_COMMENT_FEE = 100
export const SSR = typeof window === 'undefined' export const SSR = typeof window === 'undefined'
export const MAX_FORWARDS = 5 export const MAX_FORWARDS = 5
export const LNURLP_COMMENT_MAX_LENGTH = 1000 export const LNURLP_COMMENT_MAX_LENGTH = 1000

View File

@ -2,7 +2,7 @@ import { getGetServerSideProps } from '../api/ssrApollo'
import { CenterLayout } from '../components/layout' import { CenterLayout } from '../components/layout'
import TerritoryForm from '../components/territory-form' import TerritoryForm from '../components/territory-form'
export const getServerSideProps = getGetServerSideProps({}) export const getServerSideProps = getGetServerSideProps({ authRequired: true })
export default function TerritoryPage () { export default function TerritoryPage () {
return ( return (

View File

@ -0,0 +1,136 @@
-- no freebies in jobs
update "Sub" set "allowFreebies" = false where "name" = 'jobs';
CREATE OR REPLACE FUNCTION create_item(
jitem JSONB, forward JSONB, poll_options JSONB, spam_within INTERVAL, upload_ids INTEGER[])
RETURNS "Item"
LANGUAGE plpgsql
AS $$
DECLARE
user_msats BIGINT;
cost_msats BIGINT := 1000;
base_cost_msats BIGINT := 1000;
freebie BOOLEAN;
allow_freebies BOOLEAN := true;
item "Item";
med_votes FLOAT;
select_clause TEXT;
BEGIN
PERFORM ASSERT_SERIALIZED();
-- access fields with appropriate types
item := jsonb_populate_record(NULL::"Item", jitem);
SELECT msats INTO user_msats FROM users WHERE id = item."userId";
-- if this is a post, get the base cost of the sub
IF item."parentId" IS NULL AND item."subName" IS NOT NULL THEN
SELECT "baseCost" * 1000, "baseCost" * 1000, "allowFreebies"
INTO base_cost_msats, cost_msats, allow_freebies
FROM "Sub"
WHERE name = item."subName";
END IF;
IF item."maxBid" IS NULL THEN
-- spam multiplier
cost_msats := cost_msats * POWER(10, item_spam(item."parentId", item."userId", spam_within));
IF item."userId" = 27 THEN
-- anon multiplier
cost_msats := cost_msats * 100;
END IF;
END IF;
-- add image fees
IF upload_ids IS NOT NULL THEN
cost_msats := cost_msats + (SELECT "nUnpaid" * "imageFeeMsats" FROM image_fees_info(item."userId", upload_ids));
UPDATE "Upload" SET paid = 't' WHERE id = ANY(upload_ids);
END IF;
-- it's only a freebie if it's no greater than the base cost, they have less than the cost, and boost = 0
freebie := allow_freebies
AND (cost_msats <= base_cost_msats)
AND (user_msats < cost_msats)
AND (item.boost IS NULL OR item.boost = 0)
AND item."userId" <> 27;
IF NOT freebie AND cost_msats > user_msats THEN
RAISE EXCEPTION 'SN_INSUFFICIENT_FUNDS';
END IF;
-- get this user's median item score
SELECT COALESCE(
percentile_cont(0.5) WITHIN GROUP(
ORDER BY "weightedVotes" - "weightedDownVotes"), 0)
INTO med_votes FROM "Item" WHERE "userId" = item."userId";
-- if their median votes are positive, start at 0
-- if the median votes are negative, start their post with that many down votes
-- basically: if their median post is bad, presume this post is too
-- addendum: if they're an anon poster, always start at 0
IF med_votes >= 0 OR item."userId" = 27 THEN
med_votes := 0;
ELSE
med_votes := ABS(med_votes);
END IF;
-- there's no great way to set default column values when using json_populate_record
-- so we need to only select fields with non-null values that way when func input
-- does not include a value, the default value is used instead of null
SELECT string_agg(quote_ident(key), ',') INTO select_clause
FROM jsonb_object_keys(jsonb_strip_nulls(jitem)) k(key);
-- insert the item
EXECUTE format($fmt$
INSERT INTO "Item" (%s, "weightedDownVotes", freebie)
SELECT %1$s, %L, %L
FROM jsonb_populate_record(NULL::"Item", %L) RETURNING *
$fmt$, select_clause, med_votes, freebie, jitem) INTO item;
INSERT INTO "ItemForward" ("itemId", "userId", "pct")
SELECT item.id, "userId", "pct" FROM jsonb_populate_recordset(NULL::"ItemForward", forward);
-- Automatically subscribe to one's own posts
INSERT INTO "ThreadSubscription" ("itemId", "userId")
VALUES (item.id, item."userId");
-- Automatically subscribe forward recipients to the new post
INSERT INTO "ThreadSubscription" ("itemId", "userId")
SELECT item.id, "userId" FROM jsonb_populate_recordset(NULL::"ItemForward", forward);
INSERT INTO "PollOption" ("itemId", "option")
SELECT item.id, "option" FROM jsonb_array_elements_text(poll_options) o("option");
IF NOT freebie THEN
UPDATE users SET msats = msats - cost_msats WHERE id = item."userId";
INSERT INTO "ItemAct" (msats, "itemId", "userId", act)
VALUES (cost_msats, item.id, item."userId", 'FEE');
END IF;
-- if this item has boost
IF item.boost > 0 THEN
PERFORM item_act(item.id, item."userId", 'BOOST', item.boost);
END IF;
-- if this is a job
IF item."maxBid" IS NOT NULL THEN
PERFORM run_auction(item.id);
END IF;
-- if this is a bio
IF item.bio THEN
UPDATE users SET "bioId" = item.id WHERE id = item."userId";
END IF;
-- record attachments
IF upload_ids IS NOT NULL THEN
INSERT INTO "ItemUpload" ("itemId", "uploadId")
SELECT item.id, * FROM UNNEST(upload_ids);
END IF;
-- schedule imgproxy job
INSERT INTO pgboss.job (name, data, retrylimit, retrybackoff, startafter)
VALUES ('imgproxy', jsonb_build_object('id', item.id), 21, true, now() + interval '5 seconds');
RETURN item;
END;
$$;