make anon fees consistent
This commit is contained in:
parent
c8bca3ef63
commit
ca02d627c1
|
@ -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"`,
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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;
|
||||||
|
$$;
|
Loading…
Reference in New Issue