let tips affect ranking
This commit is contained in:
parent
c86d865fb9
commit
5746160893
@ -34,7 +34,7 @@ export default {
|
|||||||
return await models.$queryRaw(
|
return await models.$queryRaw(
|
||||||
`SELECT date_trunc('month', "ItemAct".created_at) AS time,
|
`SELECT date_trunc('month', "ItemAct".created_at) AS time,
|
||||||
floor(sum(CASE WHEN act = 'STREAM' THEN "ItemAct".msats ELSE 0 END)/1000) as jobs,
|
floor(sum(CASE WHEN act = 'STREAM' THEN "ItemAct".msats ELSE 0 END)/1000) as jobs,
|
||||||
floor(sum(CASE WHEN act IN ('VOTE', 'POLL') AND "Item"."userId" = "ItemAct"."userId" THEN "ItemAct".msats ELSE 0 END)/1000) as fees,
|
floor(sum(CASE WHEN act NOT IN ('BOOST', 'TIP', 'STREAM') THEN "ItemAct".msats ELSE 0 END)/1000) as fees,
|
||||||
floor(sum(CASE WHEN act = 'BOOST' THEN "ItemAct".msats ELSE 0 END)/1000) as boost,
|
floor(sum(CASE WHEN act = 'BOOST' THEN "ItemAct".msats ELSE 0 END)/1000) as boost,
|
||||||
floor(sum(CASE WHEN act = 'TIP' THEN "ItemAct".msats ELSE 0 END)/1000) as tips
|
floor(sum(CASE WHEN act = 'TIP' THEN "ItemAct".msats ELSE 0 END)/1000) as tips
|
||||||
FROM "ItemAct"
|
FROM "ItemAct"
|
||||||
@ -68,7 +68,7 @@ export default {
|
|||||||
FROM "ItemAct"
|
FROM "ItemAct"
|
||||||
JOIN "Item" on "ItemAct"."itemId" = "Item".id AND "Item"."userId" <> "ItemAct"."userId"
|
JOIN "Item" on "ItemAct"."itemId" = "Item".id AND "Item"."userId" <> "ItemAct"."userId"
|
||||||
WHERE date_trunc('month', now_utc()) <> date_trunc('month', "ItemAct".created_at) AND
|
WHERE date_trunc('month', now_utc()) <> date_trunc('month', "ItemAct".created_at) AND
|
||||||
"ItemAct".act IN ('VOTE', 'TIP'))
|
"ItemAct".act = 'TIP')
|
||||||
UNION ALL
|
UNION ALL
|
||||||
(SELECT date_trunc('month', created_at) AS time, msats as airdrop, 0 as post, 0 as comment
|
(SELECT date_trunc('month', created_at) AS time, msats as airdrop, 0 as post, 0 as comment
|
||||||
FROM "Earn"
|
FROM "Earn"
|
||||||
@ -122,7 +122,7 @@ export default {
|
|||||||
const [stats] = await models.$queryRaw(
|
const [stats] = await models.$queryRaw(
|
||||||
`SELECT json_build_array(
|
`SELECT json_build_array(
|
||||||
json_build_object('name', 'jobs', 'value', floor(sum(CASE WHEN act = 'STREAM' THEN "ItemAct".msats ELSE 0 END)/1000)),
|
json_build_object('name', 'jobs', 'value', floor(sum(CASE WHEN act = 'STREAM' THEN "ItemAct".msats ELSE 0 END)/1000)),
|
||||||
json_build_object('name', 'fees', 'value', floor(sum(CASE WHEN act in ('VOTE', 'POLL') AND "Item"."userId" = "ItemAct"."userId" THEN "ItemAct".msats ELSE 0 END)/1000)),
|
json_build_object('name', 'fees', 'value', floor(sum(CASE WHEN act NOT IN ('BOOST', 'TIP', 'STREAM') THEN "ItemAct".msats ELSE 0 END)/1000)),
|
||||||
json_build_object('name', 'boost', 'value',floor(sum(CASE WHEN act = 'BOOST' THEN "ItemAct".msats ELSE 0 END)/1000)),
|
json_build_object('name', 'boost', 'value',floor(sum(CASE WHEN act = 'BOOST' THEN "ItemAct".msats ELSE 0 END)/1000)),
|
||||||
json_build_object('name', 'tips', 'value', floor(sum(CASE WHEN act = 'TIP' THEN "ItemAct".msats ELSE 0 END)/1000))) as array
|
json_build_object('name', 'tips', 'value', floor(sum(CASE WHEN act = 'TIP' THEN "ItemAct".msats ELSE 0 END)/1000))) as array
|
||||||
FROM "ItemAct"
|
FROM "ItemAct"
|
||||||
@ -145,7 +145,7 @@ export default {
|
|||||||
FROM "ItemAct"
|
FROM "ItemAct"
|
||||||
JOIN "Item" on "ItemAct"."itemId" = "Item".id AND "Item"."userId" <> "ItemAct"."userId"
|
JOIN "Item" on "ItemAct"."itemId" = "Item".id AND "Item"."userId" <> "ItemAct"."userId"
|
||||||
WHERE "ItemAct".created_at >= now_utc() - interval '1 week' AND
|
WHERE "ItemAct".created_at >= now_utc() - interval '1 week' AND
|
||||||
"ItemAct".act IN ('VOTE', 'TIP'))
|
"ItemAct".act = 'TIP')
|
||||||
UNION ALL
|
UNION ALL
|
||||||
(SELECT msats as airdrop, 0 as post, 0 as comment
|
(SELECT msats as airdrop, 0 as post, 0 as comment
|
||||||
FROM "Earn"
|
FROM "Earn"
|
||||||
|
@ -778,15 +778,10 @@ export default {
|
|||||||
return comments(me, models, item.id, 'hot')
|
return comments(me, models, item.id, 'hot')
|
||||||
},
|
},
|
||||||
upvotes: async (item, args, { models }) => {
|
upvotes: async (item, args, { models }) => {
|
||||||
const count = await models.itemAct.count({
|
const [{ count }] = await models.$queryRaw(`
|
||||||
where: {
|
SELECT COUNT(DISTINCT "userId") as count
|
||||||
itemId: Number(item.id),
|
FROM "ItemAct"
|
||||||
userId: {
|
WHERE act = 'TIP' AND "itemId" = $1`, Number(item.id))
|
||||||
not: Number(item.userId)
|
|
||||||
},
|
|
||||||
act: 'VOTE'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return count
|
return count
|
||||||
},
|
},
|
||||||
@ -821,7 +816,7 @@ export default {
|
|||||||
act: 'TIP'
|
act: 'TIP'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
act: 'VOTE'
|
act: 'FEE'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ export default {
|
|||||||
JOIN "ItemAct" ON "ItemAct"."itemId" = "Item".id
|
JOIN "ItemAct" ON "ItemAct"."itemId" = "Item".id
|
||||||
WHERE "ItemAct"."userId" <> $1
|
WHERE "ItemAct"."userId" <> $1
|
||||||
AND "ItemAct".created_at <= $2
|
AND "ItemAct".created_at <= $2
|
||||||
AND "ItemAct".act in ('VOTE', 'TIP')
|
AND "ItemAct".act IN ('TIP', 'FEE')
|
||||||
AND "Item"."userId" = $1
|
AND "Item"."userId" = $1
|
||||||
GROUP BY "Item".id
|
GROUP BY "Item".id
|
||||||
ORDER BY "sortTime" DESC
|
ORDER BY "sortTime" DESC
|
||||||
|
@ -26,6 +26,12 @@ async function serialize (models, call) {
|
|||||||
if (error.message.includes('SN_INELIGIBLE')) {
|
if (error.message.includes('SN_INELIGIBLE')) {
|
||||||
bail(new Error('user ineligible for gift'))
|
bail(new Error('user ineligible for gift'))
|
||||||
}
|
}
|
||||||
|
if (error.message.includes('SN_UNSUPPORTED')) {
|
||||||
|
bail(new Error('unsupported action'))
|
||||||
|
}
|
||||||
|
if (error.message.includes('SN_DUPLICATE')) {
|
||||||
|
bail(new Error('duplicate not allowed'))
|
||||||
|
}
|
||||||
if (error.message.includes('SN_REVOKED_OR_EXHAUSTED')) {
|
if (error.message.includes('SN_REVOKED_OR_EXHAUSTED')) {
|
||||||
bail(new Error('faucet has been revoked or is exhausted'))
|
bail(new Error('faucet has been revoked or is exhausted'))
|
||||||
}
|
}
|
||||||
|
@ -166,7 +166,7 @@ export default {
|
|||||||
WHERE "ItemAct"."userId" <> $1
|
WHERE "ItemAct"."userId" <> $1
|
||||||
AND "ItemAct".created_at > $2
|
AND "ItemAct".created_at > $2
|
||||||
AND "Item"."userId" = $1
|
AND "Item"."userId" = $1
|
||||||
AND "ItemAct".act IN ('VOTE', 'TIP')
|
AND "ItemAct".act = 'TIP'
|
||||||
LIMIT 1`, me.id, lastChecked)
|
LIMIT 1`, me.id, lastChecked)
|
||||||
if (votes.length > 0) {
|
if (votes.length > 0) {
|
||||||
return true
|
return true
|
||||||
|
@ -98,7 +98,7 @@ export default {
|
|||||||
0 as "msatsFee", NULL as status, 'stacked' as type
|
0 as "msatsFee", NULL as status, 'stacked' as type
|
||||||
FROM "ItemAct"
|
FROM "ItemAct"
|
||||||
JOIN "Item" on "ItemAct"."itemId" = "Item".id
|
JOIN "Item" on "ItemAct"."itemId" = "Item".id
|
||||||
WHERE "ItemAct"."userId" <> $1 AND "ItemAct".act <> 'BOOST'
|
WHERE act = 'TIP'
|
||||||
AND (("Item"."userId" = $1 AND "Item"."fwdUserId" IS NULL)
|
AND (("Item"."userId" = $1 AND "Item"."fwdUserId" IS NULL)
|
||||||
OR ("Item"."fwdUserId" = $1 AND "ItemAct"."userId" <> "Item"."userId"))
|
OR ("Item"."fwdUserId" = $1 AND "ItemAct"."userId" <> "Item"."userId"))
|
||||||
AND "ItemAct".created_at <= $2
|
AND "ItemAct".created_at <= $2
|
||||||
|
@ -15,6 +15,7 @@ import { useRouter } from 'next/router'
|
|||||||
import Item from '../components/item'
|
import Item from '../components/item'
|
||||||
import Comment from '../components/comment'
|
import Comment from '../components/comment'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import Info from '../components/info'
|
||||||
|
|
||||||
export const getServerSideProps = getGetServerSideProps(WALLET_HISTORY)
|
export const getServerSideProps = getGetServerSideProps(WALLET_HISTORY)
|
||||||
|
|
||||||
@ -199,7 +200,13 @@ export default function Satistics ({ data: { me, walletHistory: { facts, cursor
|
|||||||
<tr>
|
<tr>
|
||||||
<th className={styles.type}>type</th>
|
<th className={styles.type}>type</th>
|
||||||
<th>detail</th>
|
<th>detail</th>
|
||||||
<th className={styles.sats}>sats</th>
|
<th className={styles.sats}>
|
||||||
|
<div>sats
|
||||||
|
<Info>
|
||||||
|
<div className='font-weight-bold'>Sats are rounded down from millisats to the nearest sat, so the actual amount might be slightly larger.</div>
|
||||||
|
</Info>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
3
prisma/migrations/20221116223041_tipcut/migration.sql
Normal file
3
prisma/migrations/20221116223041_tipcut/migration.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
-- AlterEnum
|
||||||
|
ALTER TYPE "ItemActType" ADD VALUE 'FEE';
|
||||||
|
|
225
prisma/migrations/20221118202137_tipcut_funcs/migration.sql
Normal file
225
prisma/migrations/20221118202137_tipcut_funcs/migration.sql
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
-- convert all self-votes to FEEs
|
||||||
|
UPDATE "ItemAct"
|
||||||
|
SET act = 'FEE'
|
||||||
|
FROM "Item"
|
||||||
|
WHERE act = 'VOTE'
|
||||||
|
AND "Item".id = "ItemAct"."itemId"
|
||||||
|
AND "Item"."userId" = "ItemAct"."userId";
|
||||||
|
|
||||||
|
-- convert all votes to TIPs
|
||||||
|
UPDATE "ItemAct"
|
||||||
|
SET act = 'TIP'
|
||||||
|
WHERE act = 'VOTE';
|
||||||
|
|
||||||
|
-- change vote on creation to act type FEE
|
||||||
|
CREATE OR REPLACE FUNCTION create_item(
|
||||||
|
title TEXT, url TEXT, text TEXT, boost INTEGER,
|
||||||
|
parent_id INTEGER, user_id INTEGER, fwd_user_id INTEGER,
|
||||||
|
spam_within INTERVAL)
|
||||||
|
RETURNS "Item"
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
DECLARE
|
||||||
|
user_msats BIGINT;
|
||||||
|
cost_msats BIGINT;
|
||||||
|
free_posts INTEGER;
|
||||||
|
free_comments INTEGER;
|
||||||
|
freebie BOOLEAN;
|
||||||
|
item "Item";
|
||||||
|
med_votes FLOAT;
|
||||||
|
BEGIN
|
||||||
|
PERFORM ASSERT_SERIALIZED();
|
||||||
|
|
||||||
|
SELECT msats, "freePosts", "freeComments"
|
||||||
|
INTO user_msats, free_posts, free_comments
|
||||||
|
FROM users WHERE id = user_id;
|
||||||
|
|
||||||
|
cost_msats := 1000 * POWER(10, item_spam(parent_id, user_id, spam_within));
|
||||||
|
-- it's only a freebie if it's a 1 sat cost, they have < 1 sat, boost = 0, and they have freebies left
|
||||||
|
freebie := (cost_msats <= 1000) AND (user_msats < 1000) AND (boost = 0) AND ((parent_id IS NULL AND free_posts > 0) OR (parent_id IS NOT NULL AND free_comments > 0));
|
||||||
|
|
||||||
|
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" = user_id;
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
IF med_votes >= 0 THEN
|
||||||
|
med_votes := 0;
|
||||||
|
ELSE
|
||||||
|
med_votes := ABS(med_votes);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
INSERT INTO "Item" (title, url, text, "userId", "parentId", "fwdUserId", freebie, "weightedDownVotes", created_at, updated_at)
|
||||||
|
VALUES (title, url, text, user_id, parent_id, fwd_user_id, freebie, med_votes, now_utc(), now_utc()) RETURNING * INTO item;
|
||||||
|
|
||||||
|
IF freebie THEN
|
||||||
|
IF parent_id IS NULL THEN
|
||||||
|
UPDATE users SET "freePosts" = "freePosts" - 1 WHERE id = user_id;
|
||||||
|
ELSE
|
||||||
|
UPDATE users SET "freeComments" = "freeComments" - 1 WHERE id = user_id;
|
||||||
|
END IF;
|
||||||
|
ELSE
|
||||||
|
UPDATE users SET msats = msats - cost_msats WHERE id = user_id;
|
||||||
|
|
||||||
|
INSERT INTO "ItemAct" (msats, "itemId", "userId", act, created_at, updated_at)
|
||||||
|
VALUES (cost_msats, item.id, user_id, 'FEE', now_utc(), now_utc());
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF boost > 0 THEN
|
||||||
|
PERFORM item_act(item.id, user_id, 'BOOST', boost);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
RETURN item;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- change item_act to take FEE and remove VOTE
|
||||||
|
CREATE OR REPLACE FUNCTION item_act(item_id INTEGER, user_id INTEGER, act "ItemActType", act_sats INTEGER)
|
||||||
|
RETURNS INTEGER
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
DECLARE
|
||||||
|
user_msats BIGINT;
|
||||||
|
act_msats BIGINT;
|
||||||
|
fee_msats BIGINT;
|
||||||
|
BEGIN
|
||||||
|
PERFORM ASSERT_SERIALIZED();
|
||||||
|
|
||||||
|
act_msats := act_sats * 1000;
|
||||||
|
SELECT msats INTO user_msats FROM users WHERE id = user_id;
|
||||||
|
IF act_msats > user_msats THEN
|
||||||
|
RAISE EXCEPTION 'SN_INSUFFICIENT_FUNDS';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- deduct msats from actor
|
||||||
|
UPDATE users SET msats = msats - act_msats WHERE id = user_id;
|
||||||
|
|
||||||
|
IF act = 'VOTE' THEN
|
||||||
|
RAISE EXCEPTION 'SN_UNSUPPORTED';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF act = 'TIP' THEN
|
||||||
|
-- call to influence weightedVotes ... we need to do this before we record the acts because
|
||||||
|
-- the priors acts are taken into account
|
||||||
|
PERFORM weighted_votes_after_tip(item_id, user_id, act_sats);
|
||||||
|
|
||||||
|
-- take 10% and insert as FEE
|
||||||
|
fee_msats := CEIL(act_msats * 0.1);
|
||||||
|
act_msats := act_msats - fee_msats;
|
||||||
|
|
||||||
|
INSERT INTO "ItemAct" (msats, "itemId", "userId", act, created_at, updated_at)
|
||||||
|
VALUES (fee_msats, item_id, user_id, 'FEE', now_utc(), now_utc());
|
||||||
|
|
||||||
|
-- add sats to actee's balance and stacked count
|
||||||
|
UPDATE users
|
||||||
|
SET msats = msats + act_msats, "stackedMsats" = "stackedMsats" + act_msats
|
||||||
|
WHERE id = (SELECT COALESCE("fwdUserId", "userId") FROM "Item" WHERE id = item_id);
|
||||||
|
|
||||||
|
-- leave the rest as a tip
|
||||||
|
INSERT INTO "ItemAct" (msats, "itemId", "userId", act, created_at, updated_at)
|
||||||
|
VALUES (act_msats, item_id, user_id, 'TIP', now_utc(), now_utc());
|
||||||
|
|
||||||
|
-- call to denormalize sats and commentSats
|
||||||
|
PERFORM sats_after_tip(item_id, user_id, act_msats + fee_msats);
|
||||||
|
ELSE -- BOOST, POLL, DONT_LIKE_THIS
|
||||||
|
-- call to influence if DONT_LIKE_THIS weightedDownVotes
|
||||||
|
IF act = 'DONT_LIKE_THIS' THEN
|
||||||
|
-- make sure they haven't done this before
|
||||||
|
IF EXISTS (SELECT 1 FROM "ItemAct" WHERE "itemId" = item_id AND "userId" = user_id AND "ItemAct".act = 'DONT_LIKE_THIS') THEN
|
||||||
|
RAISE EXCEPTION 'SN_DUPLICATE';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
PERFORM weighted_downvotes_after_act(item_id, user_id, act_sats);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
INSERT INTO "ItemAct" (msats, "itemId", "userId", act, created_at, updated_at)
|
||||||
|
VALUES (act_msats, item_id, user_id, act, now_utc(), now_utc());
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
RETURN 0;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- remove triggers for weightedVotes and weightedDownVotes, replacing with functions called directly
|
||||||
|
DROP TRIGGER IF EXISTS weighted_votes_after_act ON "ItemAct";
|
||||||
|
DROP FUNCTION weighted_votes_after_act();
|
||||||
|
CREATE OR REPLACE FUNCTION weighted_votes_after_tip(item_id INTEGER, user_id INTEGER, sats INTEGER) RETURNS INTEGER AS $$
|
||||||
|
DECLARE
|
||||||
|
user_trust DOUBLE PRECISION;
|
||||||
|
sats_past INTEGER;
|
||||||
|
multiplier DOUBLE PRECISION;
|
||||||
|
BEGIN
|
||||||
|
-- grab user's trust who is upvoting
|
||||||
|
SELECT trust INTO user_trust FROM users WHERE id = user_id;
|
||||||
|
|
||||||
|
-- in order to add this to weightedVotes, we need to do log((satsN+satsPrior)/satsPrior)
|
||||||
|
-- so compute sats prior
|
||||||
|
SELECT SUM(msats) / 1000 INTO sats_past
|
||||||
|
FROM "ItemAct"
|
||||||
|
WHERE "userId" = user_id AND "itemId" = item_id AND act IN ('TIP', 'FEE');
|
||||||
|
|
||||||
|
IF sats_past IS NULL OR sats_past = 0 THEN
|
||||||
|
multiplier := LOG(sats);
|
||||||
|
ELSE
|
||||||
|
multiplier := LOG((sats+sats_past)/sats_past::FLOAT);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- update item
|
||||||
|
UPDATE "Item"
|
||||||
|
SET "weightedVotes" = "weightedVotes" + (user_trust * multiplier)
|
||||||
|
WHERE id = item_id AND "userId" <> user_id;
|
||||||
|
|
||||||
|
RETURN 0;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
-- TODO: maybe let sats affect downvoting as well
|
||||||
|
DROP TRIGGER IF EXISTS weighted_downvotes_after_act ON "ItemAct";
|
||||||
|
DROP FUNCTION weighted_downvotes_after_act();
|
||||||
|
CREATE OR REPLACE FUNCTION weighted_downvotes_after_act(item_id INTEGER, user_id INTEGER, sats INTEGER) RETURNS INTEGER AS $$
|
||||||
|
DECLARE
|
||||||
|
user_trust DOUBLE PRECISION;
|
||||||
|
sats_past INTEGER;
|
||||||
|
multiplier DOUBLE PRECISION;
|
||||||
|
BEGIN
|
||||||
|
-- grab user's trust
|
||||||
|
SELECT trust INTO user_trust FROM users WHERE id = user_id;
|
||||||
|
|
||||||
|
-- update item
|
||||||
|
UPDATE "Item"
|
||||||
|
SET "weightedDownVotes" = "weightedDownVotes" + user_trust
|
||||||
|
WHERE id = item_id AND "userId" <> user_id;
|
||||||
|
|
||||||
|
RETURN 0;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
|
||||||
|
-- remove triggers to ItemAct sats and replace with functions called directly
|
||||||
|
DROP TRIGGER IF EXISTS sats_after_act_trigger ON "ItemAct";
|
||||||
|
DROP FUNCTION sats_after_act();
|
||||||
|
CREATE OR REPLACE FUNCTION sats_after_tip(item_id INTEGER, user_id INTEGER, tip_msats BIGINT) RETURNS INTEGER AS $$
|
||||||
|
DECLARE
|
||||||
|
item "Item";
|
||||||
|
BEGIN
|
||||||
|
SELECT * FROM "Item" WHERE id = item_id INTO item;
|
||||||
|
IF item."userId" = user_id THEN
|
||||||
|
RETURN 0;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
UPDATE "Item"
|
||||||
|
SET "msats" = "msats" + tip_msats
|
||||||
|
WHERE id = item.id;
|
||||||
|
|
||||||
|
UPDATE "Item"
|
||||||
|
SET "commentMsats" = "commentMsats" + tip_msats
|
||||||
|
WHERE id <> item.id and path @> item.path;
|
||||||
|
|
||||||
|
RETURN 1;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
@ -311,6 +311,7 @@ enum ItemActType {
|
|||||||
STREAM
|
STREAM
|
||||||
POLL
|
POLL
|
||||||
DONT_LIKE_THIS
|
DONT_LIKE_THIS
|
||||||
|
FEE
|
||||||
}
|
}
|
||||||
|
|
||||||
model ItemAct {
|
model ItemAct {
|
||||||
|
@ -9,6 +9,11 @@
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sats>div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.failed {
|
.failed {
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,7 @@ function earn ({ models }) {
|
|||||||
SELECT sum("ItemAct".msats)
|
SELECT sum("ItemAct".msats)
|
||||||
FROM "ItemAct"
|
FROM "ItemAct"
|
||||||
JOIN "Item" on "ItemAct"."itemId" = "Item".id
|
JOIN "Item" on "ItemAct"."itemId" = "Item".id
|
||||||
WHERE ("ItemAct".act in ('BOOST', 'STREAM')
|
WHERE "ItemAct".act <> 'TIP'
|
||||||
OR ("ItemAct".act IN ('VOTE','POLL') AND "Item"."userId" = "ItemAct"."userId"))
|
|
||||||
AND "ItemAct".created_at > now_utc() - INTERVAL '1 day'`
|
AND "ItemAct".created_at > now_utc() - INTERVAL '1 day'`
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -42,8 +41,8 @@ function earn ({ models }) {
|
|||||||
CASE WHEN "weightedVotes" > 0 THEN "weightedVotes"/(sum("weightedVotes") OVER (PARTITION BY "parentId" IS NULL)) ELSE 0 END AS ratio
|
CASE WHEN "weightedVotes" > 0 THEN "weightedVotes"/(sum("weightedVotes") OVER (PARTITION BY "parentId" IS NULL)) ELSE 0 END AS ratio
|
||||||
FROM (
|
FROM (
|
||||||
SELECT *,
|
SELECT *,
|
||||||
NTILE(100) OVER (PARTITION BY "parentId" IS NULL ORDER BY "weightedVotes" desc) AS percentile,
|
NTILE(100) OVER (PARTITION BY "parentId" IS NULL ORDER BY ("weightedVotes"-"weightedDownVotes") desc) AS percentile,
|
||||||
ROW_NUMBER() OVER (PARTITION BY "parentId" IS NULL ORDER BY "weightedVotes" desc) AS rank
|
ROW_NUMBER() OVER (PARTITION BY "parentId" IS NULL ORDER BY ("weightedVotes"-"weightedDownVotes") desc) AS rank
|
||||||
FROM
|
FROM
|
||||||
"Item"
|
"Item"
|
||||||
WHERE created_at >= now_utc() - interval '36 hours'
|
WHERE created_at >= now_utc() - interval '36 hours'
|
||||||
@ -56,8 +55,7 @@ function earn ({ models }) {
|
|||||||
sum("ItemAct".msats) as tipped, min("ItemAct".created_at) as acted_at
|
sum("ItemAct".msats) as tipped, min("ItemAct".created_at) as acted_at
|
||||||
FROM item_ratios
|
FROM item_ratios
|
||||||
JOIN "ItemAct" on "ItemAct"."itemId" = item_ratios.id
|
JOIN "ItemAct" on "ItemAct"."itemId" = item_ratios.id
|
||||||
WHERE act IN ('VOTE','TIP')
|
WHERE act = 'TIP'
|
||||||
AND "ItemAct"."userId" <> item_ratios."userId"
|
|
||||||
GROUP BY "ItemAct"."userId", item_ratios.id, item_ratios.ratio, item_ratios."parentId"
|
GROUP BY "ItemAct"."userId", item_ratios.id, item_ratios.ratio, item_ratios."parentId"
|
||||||
),
|
),
|
||||||
upvoter_ratios AS (
|
upvoter_ratios AS (
|
||||||
|
@ -13,6 +13,9 @@ function trust ({ boss, models }) {
|
|||||||
const MAX_DEPTH = 6
|
const MAX_DEPTH = 6
|
||||||
const MAX_TRUST = 0.9
|
const MAX_TRUST = 0.9
|
||||||
const MIN_SUCCESS = 5
|
const MIN_SUCCESS = 5
|
||||||
|
// increasing disgree_mult increases distrust when there's disagreement, at 1x we double count disagreement,
|
||||||
|
// at 2x we triple count, etc ... this count is reflected/added in the number of total "trials" between users
|
||||||
|
const DISAGREE_MULT = 1
|
||||||
// https://en.wikipedia.org/wiki/Normal_distribution#Quantile_function
|
// https://en.wikipedia.org/wiki/Normal_distribution#Quantile_function
|
||||||
const Z_CONFIDENCE = 2.326347874041 // 98% confidence
|
const Z_CONFIDENCE = 2.326347874041 // 98% confidence
|
||||||
|
|
||||||
@ -207,22 +210,24 @@ async function getGraph (models) {
|
|||||||
SELECT id, json_agg(json_build_object('node', oid, 'trust', trust)) AS hops
|
SELECT id, json_agg(json_build_object('node', oid, 'trust', trust)) AS hops
|
||||||
FROM (
|
FROM (
|
||||||
WITH user_votes AS (
|
WITH user_votes AS (
|
||||||
SELECT "ItemAct"."userId" AS user_id, users.name AS name, "ItemAct"."itemId" AS item_id, "ItemAct".created_at AS act_at,
|
SELECT "ItemAct"."userId" AS user_id, users.name AS name, "ItemAct"."itemId" AS item_id, min("ItemAct".created_at) AS act_at,
|
||||||
users.created_at AS user_at, "Item".created_at AS item_at, count(*) OVER (partition by "ItemAct"."userId") AS user_vote_count
|
users.created_at AS user_at, "ItemAct".act = 'DONT_LIKE_THIS' AS against, count(*) OVER (partition by "ItemAct"."userId") AS user_vote_count
|
||||||
FROM "ItemAct"
|
FROM "ItemAct"
|
||||||
JOIN "Item" ON "Item".id = "ItemAct"."itemId" AND "ItemAct".act = 'VOTE' AND "Item"."parentId" IS NULL
|
JOIN "Item" ON "Item".id = "ItemAct"."itemId" AND "ItemAct".act IN ('FEE', 'TIP', 'DONT_LIKE_THIS') AND "Item"."parentId" IS NULL
|
||||||
JOIN users ON "ItemAct"."userId" = users.id
|
JOIN users ON "ItemAct"."userId" = users.id
|
||||||
|
GROUP BY user_id, name, item_id, user_at, against
|
||||||
),
|
),
|
||||||
user_pair AS (
|
user_pair AS (
|
||||||
SELECT a.user_id AS a_id, a.name AS a_name, b.user_id AS b_id, b.name AS b_name,
|
SELECT a.user_id AS a_id, a.name AS a_name, b.user_id AS b_id, b.name AS b_name,
|
||||||
count(*) FILTER(WHERE a.act_at > b.act_at) AS before,
|
count(*) FILTER(WHERE a.act_at > b.act_at AND a.against = b.against) AS before,
|
||||||
count(*) FILTER(WHERE b.act_at > a.act_at) AS after,
|
count(*) FILTER(WHERE b.act_at > a.act_at AND a.against = b.against) AS after,
|
||||||
|
count(*) FILTER(WHERE a.against <> b.against)*${DISAGREE_MULT} AS disagree,
|
||||||
CASE WHEN b.user_at > a.user_at THEN b.user_vote_count ELSE a.user_vote_count END AS total
|
CASE WHEN b.user_at > a.user_at THEN b.user_vote_count ELSE a.user_vote_count END AS total
|
||||||
FROM user_votes a
|
FROM user_votes a
|
||||||
JOIN user_votes b ON a.item_id = b.item_id
|
JOIN user_votes b ON a.item_id = b.item_id
|
||||||
GROUP BY a.user_id, a.name, a.user_at, a.user_vote_count, b.user_id, b.name, b.user_at, b.user_vote_count
|
GROUP BY a.user_id, a.name, a.user_at, a.user_vote_count, b.user_id, b.name, b.user_at, b.user_vote_count
|
||||||
)
|
)
|
||||||
SELECT a_id AS id, a_name, b_id AS oid, b_name, confidence(before, total - after, ${Z_CONFIDENCE}) AS trust, before, after, total
|
SELECT a_id AS id, a_name, b_id AS oid, b_name, confidence(before, total + disagree - after, ${Z_CONFIDENCE}) AS trust, before, after, disagree, total
|
||||||
FROM user_pair
|
FROM user_pair
|
||||||
WHERE before >= ${MIN_SUCCESS}
|
WHERE before >= ${MIN_SUCCESS}
|
||||||
) a
|
) a
|
||||||
|
Loading…
x
Reference in New Issue
Block a user