workout tips functions etc
This commit is contained in:
parent
59cfc7660b
commit
28d684da73
@ -15,25 +15,6 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return me.name?.toUpperCase() === name?.toUpperCase() || !(await models.user.findUnique({ where: { name } }))
|
return me.name?.toUpperCase() === name?.toUpperCase() || !(await models.user.findUnique({ where: { name } }))
|
||||||
},
|
|
||||||
recentlyStacked: async (parent, args, { models, me }) => {
|
|
||||||
if (!me) {
|
|
||||||
throw new AuthenticationError('you must be logged in')
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = await models.user.findUnique({ where: { id: me.id } })
|
|
||||||
|
|
||||||
const [{ sum }] = await models.$queryRaw(`
|
|
||||||
SELECT sum("Vote".sats)
|
|
||||||
FROM "Vote"
|
|
||||||
JOIN "Item" on "Vote"."itemId" = "Item".id
|
|
||||||
WHERE "Vote"."userId" <> $1
|
|
||||||
AND ("Vote".created_at > $2 OR $2 IS NULL)
|
|
||||||
AND "Vote".boost = false
|
|
||||||
AND "Item"."userId" = $1`, user.id, user.checkedNotesAt)
|
|
||||||
|
|
||||||
await models.user.update({ where: { id: me.id }, data: { checkedNotesAt: new Date() } })
|
|
||||||
return sum || 0
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ export default gql`
|
|||||||
user(name: String!): User
|
user(name: String!): User
|
||||||
users: [User!]
|
users: [User!]
|
||||||
nameAvailable(name: String!): Boolean!
|
nameAvailable(name: String!): Boolean!
|
||||||
recentlyStacked: Int!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extend type Mutation {
|
extend type Mutation {
|
||||||
|
135
prisma/migrations/20210908193444_tips/migration.sql
Normal file
135
prisma/migrations/20210908193444_tips/migration.sql
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- You are about to drop the `Vote` table. If the table is not empty, all the data it contains will be lost.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "ItemAct" AS ENUM ('VOTE', 'BOOST', 'TIP');
|
||||||
|
|
||||||
|
-- DropForeignKey
|
||||||
|
ALTER TABLE "Vote" DROP CONSTRAINT "Vote_itemId_fkey";
|
||||||
|
|
||||||
|
-- DropForeignKey
|
||||||
|
ALTER TABLE "Vote" DROP CONSTRAINT "Vote_userId_fkey";
|
||||||
|
|
||||||
|
ALTER TABLE "Vote" RENAME TO "ItemAct";
|
||||||
|
|
||||||
|
ALTER TABLE "ItemAct" RENAME COLUMN "boost" TO "act";
|
||||||
|
|
||||||
|
ALTER TABLE "ItemAct"
|
||||||
|
ALTER COLUMN "act" DROP DEFAULT,
|
||||||
|
ALTER COLUMN "act" SET DATA TYPE "ItemActType"
|
||||||
|
USING (
|
||||||
|
CASE
|
||||||
|
WHEN "act" THEN 'VOTE'
|
||||||
|
ELSE 'BOOST'
|
||||||
|
END
|
||||||
|
)::"ItemActType";
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "ItemAct.itemId_index" ON "ItemAct"("itemId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "ItemAct.userId_index" ON "ItemAct"("userId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "ItemAct.act_index" ON "ItemAct"("act");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "ItemAct" ADD FOREIGN KEY ("itemId") REFERENCES "Item"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "ItemAct" ADD FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION item_act(item_id INTEGER, user_id INTEGER, act "ItemActType", act_sats INTEGER)
|
||||||
|
RETURNS INTEGER
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
DECLARE
|
||||||
|
user_sats INTEGER;
|
||||||
|
BEGIN
|
||||||
|
PERFORM ASSERT_SERIALIZED();
|
||||||
|
|
||||||
|
SELECT (msats / 1000) INTO user_sats FROM users WHERE id = user_id;
|
||||||
|
IF act_sats > user_sats THEN
|
||||||
|
RAISE EXCEPTION 'SN_INSUFFICIENT_FUNDS';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
UPDATE users SET msats = msats - (act_sats * 1000) WHERE id = user_id;
|
||||||
|
|
||||||
|
CASE act
|
||||||
|
when 'VOTE', 'BOOST' then
|
||||||
|
-- if we've already voted, then this is boost (doing this here prevents any potential
|
||||||
|
-- race)
|
||||||
|
IF EXISTS (SELECT 1 FROM "ItemAct" WHERE "itemId" = item_id AND "userId" = user_id) THEN
|
||||||
|
INSERT INTO "ItemAct" (sats, "itemId", "userId", act, created_at, updated_at)
|
||||||
|
VALUES (act_sats, item_id, user_id, 'BOOST', now_utc(), now_utc());
|
||||||
|
|
||||||
|
-- this is a vote
|
||||||
|
ELSE
|
||||||
|
-- only 1 sat votes are allowed
|
||||||
|
IF act_sats > 1 THEN
|
||||||
|
RAISE EXCEPTION 'SN_EXCEEDS_ACT_SAT_LIMIT';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
INSERT INTO "ItemAct" (sats, "itemId", "userId", act, created_at, updated_at)
|
||||||
|
VALUES (1, item_id, user_id, 'VOTE', now_utc(), now_utc());
|
||||||
|
|
||||||
|
-- give the item's user 1 sat
|
||||||
|
UPDATE users SET msats = msats + 1000 WHERE id = (SELECT "userId" FROM "Item" WHERE id = item_id);
|
||||||
|
END IF;
|
||||||
|
when 'TIP' then
|
||||||
|
INSERT INTO "ItemAct" (sats, "itemId", "userId", act, created_at, updated_at)
|
||||||
|
VALUES (act_sats, item_id, user_id, 'TIP', now_utc(), now_utc());
|
||||||
|
-- give the item's user act_sats
|
||||||
|
UPDATE users SET msats = msats + (act_sats * 1000) WHERE id = (SELECT "userId" FROM "Item" WHERE id = item_id);
|
||||||
|
END case;
|
||||||
|
|
||||||
|
RETURN act_sats;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
-- if user has free comments or posts, use that
|
||||||
|
CREATE OR REPLACE FUNCTION create_item(title TEXT, url TEXT, text TEXT, parent_id INTEGER, user_id INTEGER)
|
||||||
|
RETURNS "Item"
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
DECLARE
|
||||||
|
user_sats INTEGER;
|
||||||
|
free_posts INTEGER;
|
||||||
|
free_comments INTEGER;
|
||||||
|
freebie BOOLEAN;
|
||||||
|
item "Item";
|
||||||
|
BEGIN
|
||||||
|
PERFORM ASSERT_SERIALIZED();
|
||||||
|
|
||||||
|
SELECT (msats / 1000), "freePosts", "freeComments"
|
||||||
|
INTO user_sats, free_posts, free_comments
|
||||||
|
FROM users WHERE id = user_id;
|
||||||
|
|
||||||
|
freebie := (parent_id IS NULL AND free_posts > 0) OR (parent_id IS NOT NULL AND free_comments > 0);
|
||||||
|
|
||||||
|
IF NOT freebie AND 1 > user_sats THEN
|
||||||
|
RAISE EXCEPTION 'SN_INSUFFICIENT_FUNDS';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
INSERT INTO "Item" (title, url, text, "userId", "parentId", created_at, updated_at)
|
||||||
|
VALUES (title, url, text, user_id, parent_id, 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 - 1000 WHERE id = user_id;
|
||||||
|
|
||||||
|
INSERT INTO "ItemAct" (sats, "itemId", "userId", act, created_at, updated_at)
|
||||||
|
VALUES (1, item.id, user_id, 'VOTE', now_utc(), now_utc());
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
RETURN item;
|
||||||
|
END;
|
||||||
|
$$;
|
@ -1,65 +0,0 @@
|
|||||||
WITH RECURSIVE base AS (
|
|
||||||
SELECT "Item".id, "Item".created_at as "createdAt", "Item".updated_at as "updatedAt", "Item".title,
|
|
||||||
"Item".text, "Item".url, "Item"."userId", "Item"."parentId", ltree2text("Item"."path") AS "path",
|
|
||||||
ARRAY[row_number() OVER (ORDER BY (x.sats-1)/POWER(EXTRACT(EPOCH FROM ((NOW() AT TIME ZONE 'UTC') - "Item".created_at))/3600+2, 1.5) DESC NULLS LAST, "Item"."path")] AS sort_path
|
|
||||||
FROM "Item"
|
|
||||||
LEFT JOIN (SELECT i.id, SUM("Vote".sats) as sats
|
|
||||||
FROM "Item" i
|
|
||||||
JOIN "Vote" ON i.id = "Vote"."itemId"
|
|
||||||
WHERE i."parentId" IS NULL
|
|
||||||
GROUP BY i.id) x ON "Item".id = x.id
|
|
||||||
WHERE "parentId" IS NULL
|
|
||||||
UNION ALL
|
|
||||||
SELECT "Item".id, "Item".created_at as "createdAt", "Item".updated_at as "updatedAt", "Item".title,
|
|
||||||
"Item".text, "Item".url, "Item"."userId", "Item"."parentId", ltree2text("Item"."path") AS "path",
|
|
||||||
p.sort_path || row_number() OVER (ORDER BY (x.sats-1)/POWER(EXTRACT(EPOCH FROM ((NOW() AT TIME ZONE 'UTC') - "Item".created_at))/3600+2, 1.5) DESC NULLS LAST, "Item"."path")
|
|
||||||
FROM base p
|
|
||||||
JOIN "Item" ON ltree2text(subpath("Item"."path", 0, -1)) = p."path"
|
|
||||||
LEFT JOIN (SELECT i.id, SUM("Vote".sats) as sats
|
|
||||||
FROM "Item" i
|
|
||||||
JOIN "Vote" ON i.id = "Vote"."itemId"
|
|
||||||
WHERE i."parentId" IS NULL
|
|
||||||
GROUP BY i.id) x ON "Item".id = x.id
|
|
||||||
)
|
|
||||||
select * from base order by sort_path;
|
|
||||||
|
|
||||||
WITH RECURSIVE base AS (
|
|
||||||
SELECT "Item".id, "Item".created_at as "createdAt", "Item".updated_at as "updatedAt", "Item".title,
|
|
||||||
"Item".text, "Item".url, "Item"."userId", "Item"."parentId", ltree2text("Item"."path") AS "path",
|
|
||||||
ARRAY[row_number() OVER (ORDER BY "Item".created_at, "Item"."path")] AS sort_path
|
|
||||||
FROM "Item"
|
|
||||||
WHERE "parentId" IS NULL
|
|
||||||
UNION ALL
|
|
||||||
SELECT "Item".id, "Item".created_at as "createdAt", "Item".updated_at as "updatedAt", "Item".title,
|
|
||||||
"Item".text, "Item".url, "Item"."userId", "Item"."parentId", ltree2text("Item"."path") AS "path",
|
|
||||||
p.sort_path || row_number() OVER (ORDER BY "Item".created_at, "Item"."path")
|
|
||||||
FROM base p
|
|
||||||
JOIN "Item" ON ltree2text(subpath("Item"."path", 0, -1)) = p."path"
|
|
||||||
)
|
|
||||||
select * from base order by sort_path;
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION vote(item_id INTEGER, username TEXT, vote_sats INTEGER)
|
|
||||||
RETURNS INTEGER
|
|
||||||
LANGUAGE plpgsql
|
|
||||||
AS $$
|
|
||||||
DECLARE
|
|
||||||
user_id INTEGER
|
|
||||||
user_sats INTEGER
|
|
||||||
BEGIN
|
|
||||||
SELECT sats, id INTO user_sats, user_id FROM "User" WHERE name = username;
|
|
||||||
IF vote_sats > user_sats THEN
|
|
||||||
RAISE EXCEPTION 'insufficient funds';
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
UPDATE "User" SET sats = sats - vote_sats WHERE id = user_id;
|
|
||||||
|
|
||||||
IF EXISTS (SELECT 1 FROM "Vote" WHERE "itemId" = item_id AND "userId" = user_id) THEN
|
|
||||||
INSERT INTO "Vote" (sats, "itemId", "userId") VALUES (vote_sats, item_id, user_id);
|
|
||||||
UPDATE "User" SET sats = sats + vote_sats WHERE id = (SELECT "userId" FROM "Item" WHERE id = item_id);
|
|
||||||
ELSE
|
|
||||||
INSERT INTO "Vote" (sats, "itemId", "userId", boost) VALUES (vote_sats, item_id, user_id, true);
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RETURN sats
|
|
||||||
END;
|
|
||||||
$$;
|
|
@ -11,24 +11,24 @@ generator client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model User {
|
model User {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
createdAt DateTime @default(now()) @map(name: "created_at")
|
createdAt DateTime @default(now()) @map(name: "created_at")
|
||||||
updatedAt DateTime @default(now()) @updatedAt @map(name: "updated_at")
|
updatedAt DateTime @default(now()) @updatedAt @map(name: "updated_at")
|
||||||
name String? @unique @db.Citext
|
name String? @unique @db.Citext
|
||||||
email String? @unique
|
email String? @unique
|
||||||
emailVerified DateTime? @map(name: "email_verified")
|
emailVerified DateTime? @map(name: "email_verified")
|
||||||
image String?
|
image String?
|
||||||
items Item[]
|
items Item[]
|
||||||
mentions Mention[]
|
mentions Mention[]
|
||||||
messages Message[]
|
messages Message[]
|
||||||
votes Vote[]
|
itemActions ItemAction[]
|
||||||
invoices Invoice[]
|
invoices Invoice[]
|
||||||
withdrawls Withdrawl[]
|
withdrawls Withdrawl[]
|
||||||
msats Int @default(0)
|
msats Int @default(0)
|
||||||
freeComments Int @default(5)
|
freeComments Int @default(5)
|
||||||
freePosts Int @default(2)
|
freePosts Int @default(2)
|
||||||
checkedNotesAt DateTime?
|
checkedNotesAt DateTime?
|
||||||
pubkey String? @unique
|
pubkey String? @unique
|
||||||
|
|
||||||
@@map(name: "users")
|
@@map(name: "users")
|
||||||
}
|
}
|
||||||
@ -60,7 +60,7 @@ model Item {
|
|||||||
parent Item? @relation("ParentChildren", fields: [parentId], references: [id])
|
parent Item? @relation("ParentChildren", fields: [parentId], references: [id])
|
||||||
parentId Int?
|
parentId Int?
|
||||||
children Item[] @relation("ParentChildren")
|
children Item[] @relation("ParentChildren")
|
||||||
votes Vote[]
|
actions ItemAction[]
|
||||||
mentions Mention[]
|
mentions Mention[]
|
||||||
path Unsupported("LTREE")?
|
path Unsupported("LTREE")?
|
||||||
|
|
||||||
@ -68,19 +68,26 @@ model Item {
|
|||||||
@@index([parentId])
|
@@index([parentId])
|
||||||
}
|
}
|
||||||
|
|
||||||
model Vote {
|
enum ItemActionType {
|
||||||
id Int @id @default(autoincrement())
|
VOTE
|
||||||
createdAt DateTime @default(now()) @map(name: "created_at")
|
BOOST
|
||||||
updatedAt DateTime @updatedAt @map(name: "updated_at")
|
TIP
|
||||||
sats Int @default(1)
|
}
|
||||||
boost Boolean @default(false)
|
|
||||||
item Item @relation(fields: [itemId], references: [id])
|
model ItemAction {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
createdAt DateTime @default(now()) @map(name: "created_at")
|
||||||
|
updatedAt DateTime @updatedAt @map(name: "updated_at")
|
||||||
|
sats Int @default(1)
|
||||||
|
action ItemActionType @default(VOTE)
|
||||||
|
item Item @relation(fields: [itemId], references: [id])
|
||||||
itemId Int
|
itemId Int
|
||||||
user User @relation(fields: [userId], references: [id])
|
user User @relation(fields: [userId], references: [id])
|
||||||
userId Int
|
userId Int
|
||||||
|
|
||||||
@@index([itemId])
|
@@index([itemId])
|
||||||
@@index([userId])
|
@@index([userId])
|
||||||
|
@@index([action])
|
||||||
}
|
}
|
||||||
|
|
||||||
model Mention {
|
model Mention {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user