Merge branch 'master' into lud18-fixes

This commit is contained in:
Keyan 2023-10-05 19:33:22 -05:00 committed by GitHub
commit 4595dfdda5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 139 additions and 4 deletions

View File

@ -40,15 +40,42 @@ export default forwardRef(function Reply ({ item, onSuccess, replyOpen, children
const parentId = item.id
const replyInput = useRef(null)
const formInnerRef = useRef()
// Start block to handle iOS Safari's weird selection clearing behavior
const savedRange = useRef()
const savedRangeNode = useRef()
const onTouchEnd = useCallback(() => {
const selection = document.getSelection()
if (!selection || selection.rangeCount === 0 || selection.getRangeAt(0).length === 0) {
return
}
const range = selection.getRangeAt(0)
savedRangeNode.current = range.commonAncestorContainer
savedRange.current = range.cloneContents()
}, [])
useEffect(() => {
document.addEventListener('touchend', onTouchEnd)
return () => document.removeEventListener('touchend', onTouchEnd)
}, [])
// End block to handle iOS Safari's weird selection clearing behavior
useImperativeHandle(ref, () => ({
quoteReply: ({ selectionOnly }) => {
if (!reply) {
setReply(true)
}
const selection = window.getSelection()
const selectedText = selection.isCollapsed ? undefined : selection.toString()
const isSelectedTextInTarget = contentContainerRef?.current?.contains(selection.anchorNode)
if ((selection.isCollapsed || !isSelectedTextInTarget) && selectionOnly) return
let selectedText = selection.isCollapsed ? undefined : selection.toString()
let isSelectedTextInTarget = contentContainerRef?.current?.contains(selection.anchorNode)
// Start block to handle iOS Safari's weird selection clearing behavior
if (!selectedText && savedRange.current && savedRangeNode.current) {
selectedText = savedRange.current.textContent
isSelectedTextInTarget = contentContainerRef?.current?.contains(savedRangeNode.current)
}
// End block to handle iOS Safari's weird selection clearing behavior
if ((selection.isCollapsed || !isSelectedTextInTarget || !selectedText) && selectionOnly) return
const textToQuote = isSelectedTextInTarget ? selectedText : item.text
let updatedValue
if (formInnerRef.current && formInnerRef.current.values && !formInnerRef.current.values.text) {

View File

@ -3,7 +3,7 @@
### `nvm use 18`
Switch to use nodejs version 18 in your current shell
### `docker-compose up -d`
### `docker-compose up --build -d`
Bring up stacker news app via local docker services
### `docker-compose down`

View File

@ -0,0 +1,108 @@
UPDATE "Item" SET freebie = true
WHERE NOT EXISTS (
SELECT 1
FROM "ItemAct"
WHERE "itemId" = "Item".id
AND "userId" = "Item"."userId"
AND act = 'FEE');
-- add freebie tag back to applicatable items
CREATE OR REPLACE FUNCTION create_item(
jitem JSONB, forward JSONB, poll_options JSONB, spam_within INTERVAL)
RETURNS "Item"
LANGUAGE plpgsql
AS $$
DECLARE
user_msats BIGINT;
cost_msats BIGINT;
freebie BOOLEAN;
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 item."maxBid" IS NOT NULL THEN
cost_msats := 1000000;
ELSE
cost_msats := 1000 * POWER(10, item_spam(item."parentId", item."userId", spam_within));
END IF;
-- it's only a freebie if it's a 1 sat cost, they have < 1 sat, and boost = 0
freebie := (cost_msats <= 1000) AND (user_msats < 1000) AND (item.boost IS NULL OR item.boost = 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" = 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 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;
-- 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;
$$;