From 6bb828d5416328dd68ed60c29dc3449b7ca33bf3 Mon Sep 17 00:00:00 2001 From: TBHGodPro Date: Tue, 2 Jul 2024 13:35:04 -0500 Subject: [PATCH 1/5] Provide `messageTs` in more places in the api --- src/extensions/api/index.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/extensions/api/index.ts b/src/extensions/api/index.ts index 6c5d91be..1732db1f 100644 --- a/src/extensions/api/index.ts +++ b/src/extensions/api/index.ts @@ -369,7 +369,7 @@ express.get('/api/goals/:slackId', readLimit, async (req, res) => { data: result.map(r => { return { name: r.name, - minutes: r.minutes + minutes: r.minutes, } }), } @@ -430,6 +430,7 @@ express.get('/api/history/:slackId', readLimit, async (req, res) => { ended: r.completed || r.cancelled, work: r.metadata?.work, + messageTs: r.messageTs, } }) } @@ -573,6 +574,7 @@ express.post('/api/start/:slackId', limiter, async (req, res) => { id: session.id, slackId: user.slackUser?.slackId, createdAt: session.createdAt, + messageTs: assertVal(topLevel!.ts), }, }); }); @@ -634,6 +636,7 @@ express.post('/api/cancel/:slackId', limiter, async (req, res) => { id: session.id, slackId: session.user.slackUser?.slackId, createdAt: session.createdAt, + messageTs: session.messageTs, }, }); } catch (error) { @@ -699,6 +702,7 @@ express.post('/api/pause/:slackId', limiter, async (req, res) => { slackId: session.user.slackUser?.slackId, createdAt: session.createdAt, paused: updatedSession.paused, + messageTs: session.messageTs, }, }); } catch (error) { From e1b2cb4ddcba42de7f663e2f9310df5051e0b151 Mon Sep 17 00:00:00 2001 From: TBHGodPro Date: Tue, 2 Jul 2024 13:55:10 -0500 Subject: [PATCH 2/5] add changing goals + send goal id in /api/goals endpoint --- src/extensions/api/index.ts | 80 ++++++++++++++++++++++++++++++++++++- src/lib/corelib.ts | 13 ++++++ 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/src/extensions/api/index.ts b/src/extensions/api/index.ts index 1732db1f..23273634 100644 --- a/src/extensions/api/index.ts +++ b/src/extensions/api/index.ts @@ -359,6 +359,7 @@ express.get('/api/goals/:slackId', readLimit, async (req, res) => { userId: slackUser.userId, }, select: { + id: true, name: true, minutes: true, }, @@ -368,6 +369,7 @@ express.get('/api/goals/:slackId', readLimit, async (req, res) => { ok: true, data: result.map(r => { return { + id: r.id, name: r.name, minutes: r.minutes, } @@ -708,4 +710,80 @@ express.post('/api/pause/:slackId', limiter, async (req, res) => { } catch (error) { emitter.emit('error', { error }); } -}); \ No newline at end of file +}); + +express.post('/api/goals/:slackId', limiter, async (req, res) => { + try { + if (!req.apiKey) { + return res.status(401).send({ + ok: false, + error: 'Unauthorized', + }); + } + + const apiKey = scryptSync(req.apiKey, 'salt', 64).toString('hex'); + + const session = await prisma.session.findFirst({ + where: { + user: { + apiKey + }, + completed: false, + cancelled: false, + }, + include: { + user: { + select: { + slackUser: { + select: { + slackId: true + } + } + } + } + } + }); + + if (!session || !session.user.slackUser?.slackId) { + return res.status(401).send({ + ok: false, + error: 'Invalid user or no active session found', + }); + } + + const result = await prisma.goal.findMany({ + where: { + userId: session.user.slackUser.slackId, + }, + select: { + id: true, + name: true, + minutes: true + }, + }); + + if (typeof req.body.id !== 'string' || !result.find(i => i.id === req.body.id)) { + return res.status(400).send({ + ok: false, + error: "Invalid Goal ID" + }) + } + + const updatedSession = await Session.changeGoal(session, req.body.id); + + await updateTopLevel(updatedSession); + + return res.status(200).send({ + ok: true, + data: { + id: session.id, + slackId: session.user.slackUser?.slackId, + createdAt: session.createdAt, + goal: result.find(i => i.id === req.body.id), + messageTs: session.messageTs, + }, + }); + } catch (error) { + emitter.emit('error', { error }); + } +}) \ No newline at end of file diff --git a/src/lib/corelib.ts b/src/lib/corelib.ts index cbcd786c..328dd258 100644 --- a/src/lib/corelib.ts +++ b/src/lib/corelib.ts @@ -75,6 +75,19 @@ export class Session { return updatedSession; } + + public static async changeGoal(session: SessionType, goalId: string) { + const updatedSession = await prisma.session.update({ + where: { + id: session.id + }, + data: { + goalId: goalId + } + }) + + return updatedSession; + } } // TODO: Metadata management From cf49d41f051cb7fabd632d432c9147742aa8842f Mon Sep 17 00:00:00 2001 From: TBHGodPro Date: Tue, 2 Jul 2024 14:06:36 -0500 Subject: [PATCH 3/5] add shop info viewer on api --- src/extensions/api/index.ts | 57 +++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/extensions/api/index.ts b/src/extensions/api/index.ts index 23273634..4ac4bdd5 100644 --- a/src/extensions/api/index.ts +++ b/src/extensions/api/index.ts @@ -440,6 +440,60 @@ express.get('/api/history/:slackId', readLimit, async (req, res) => { return res.status(200).send(response); }); +/** + * Get shop info of a user + */ +express.get('/api/shop/:slackId', readLimit, async (req, res) => { + if (!req.apiKey) { + return res.status(401).send({ + ok: false, + error: 'Unauthorized', + }); + } + + const apiKey = scryptSync(req.apiKey, 'salt', 64).toString('hex'); + + + const user = await prisma.user.findUnique({ + where: { + apiKey + }, + include: { + slackUser: { + select: { + slackId: true + } + } + } + }); + + if (!user || !user.slackUser?.slackId) { + return res.status(401).send({ + ok: false, + error: 'Unauthorized', + }); + } + + const airtableUser = await AirtableAPI.User.lookupBySlack(user.slackUser.slackId); + + if (!airtableUser) { + return res.status(401).send({ + ok: false, + error: 'Unauthorized', + }); + } + + return res.status(200).send({ + ok: true, + data: { + spendable: airtableUser.fields["Balance (Hours)"], + awaitingApproval: airtableUser.fields["Minutes (Pending Approval)"] / 60, + inOrders: airtableUser.fields["In Pending (Minutes)"] / 60, + spent: airtableUser.fields["Spent Fulfilled (Minutes)"] / 60, + } + }) +}) + /* Write API */ @@ -712,6 +766,9 @@ express.post('/api/pause/:slackId', limiter, async (req, res) => { } }); +/** + * Change the goal of an active session + */ express.post('/api/goals/:slackId', limiter, async (req, res) => { try { if (!req.apiKey) { From ffc7cdb5fa6bcd45107f3c54200ab7f8cf7f3758 Mon Sep 17 00:00:00 2001 From: TBHGodPro Date: Tue, 2 Jul 2024 14:14:02 -0500 Subject: [PATCH 4/5] fix up message updating --- src/extensions/api/index.ts | 10 +++++----- src/lib/corelib.ts | 6 ++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/extensions/api/index.ts b/src/extensions/api/index.ts index 4ac4bdd5..6e8aa990 100644 --- a/src/extensions/api/index.ts +++ b/src/extensions/api/index.ts @@ -613,8 +613,10 @@ express.post('/api/start/:slackId', limiter, async (req, res) => { } }); - await updateController(session); - await updateTopLevel(session); + await Promise.all([ + updateController(session), + updateTopLevel(session) + ]) emitter.emit('start', session); @@ -826,9 +828,7 @@ express.post('/api/goals/:slackId', limiter, async (req, res) => { }) } - const updatedSession = await Session.changeGoal(session, req.body.id); - - await updateTopLevel(updatedSession); + await Session.changeGoal(session, req.body.id); return res.status(200).send({ ok: true, diff --git a/src/lib/corelib.ts b/src/lib/corelib.ts index 328dd258..1758f5fe 100644 --- a/src/lib/corelib.ts +++ b/src/lib/corelib.ts @@ -3,6 +3,7 @@ import type { Session as SessionType } from "@prisma/client"; import { prisma } from "./prisma.js"; import { emitter } from "./emitter.js"; +import { updateController, updateTopLevel } from "../extensions/slack/lib/lib.js"; interface SessionAction { userId?: string; @@ -85,6 +86,11 @@ export class Session { goalId: goalId } }) + + await Promise.all([ + updateController(updatedSession), + updateTopLevel(updatedSession) + ]) return updatedSession; } From 2d23141e9c0d330972d59de726b2175275d14f2c Mon Sep 17 00:00:00 2001 From: TBHGodPro Date: Tue, 2 Jul 2024 17:23:41 -0500 Subject: [PATCH 5/5] fix goal changing --- src/extensions/slack/functions/goals.ts | 56 +------------------------ src/lib/corelib.ts | 49 ++++++++++++++++++++-- 2 files changed, 48 insertions(+), 57 deletions(-) diff --git a/src/extensions/slack/functions/goals.ts b/src/extensions/slack/functions/goals.ts index 3eb15c21..8bd45ce0 100644 --- a/src/extensions/slack/functions/goals.ts +++ b/src/extensions/slack/functions/goals.ts @@ -7,6 +7,7 @@ import { informUser, updateController, updateTopLevel } from "../lib/lib.js"; import { emitter } from "../../../lib/emitter.js"; import { t } from "../../../lib/templates.js"; import { Loading } from "../views/loading.js"; +import { Session } from "../../../lib/corelib.js"; Slack.action(Actions.OPEN_GOAL, async ({ body, client }) => { try { @@ -74,60 +75,7 @@ Slack.action(Actions.SELECT_GOAL, async ({ body, client }) => { } }); - const oldGoal = await prisma.goal.findUniqueOrThrow({ - where: { - id: session?.goalId as string - } - }); - - const newGoal = await prisma.goal.findUniqueOrThrow({ - where: { - id: goalId - } - }); - - session = await prisma.session.update({ - where: { - id: sessionId, - goal: { - completed: false - }, - }, - data: { - goal: { - connect: { - id: newGoal.id - } - } - } - }); - - if (session.completed || session.cancelled) { - await prisma.goal.update({ - where: { - id: oldGoal.id - }, - data: { - minutes: { - decrement: session.elapsed - } - } - }); - - await prisma.goal.update({ - where: { - id: newGoal.id - }, - data: { - minutes: { - increment: session.elapsed - } - } - }); - } - - updateTopLevel(session); - updateController(session); + session = await Session.changeGoal(session, goalId); await client.views.update({ view_id: (body as any).view.root_view_id, diff --git a/src/lib/corelib.ts b/src/lib/corelib.ts index 1758f5fe..93b316c5 100644 --- a/src/lib/corelib.ts +++ b/src/lib/corelib.ts @@ -78,14 +78,57 @@ export class Session { } public static async changeGoal(session: SessionType, goalId: string) { + const oldGoal = await prisma.goal.findUniqueOrThrow({ + where: { + id: session?.goalId as string + } + }); + + const newGoal = await prisma.goal.findUniqueOrThrow({ + where: { + id: goalId + } + }); + const updatedSession = await prisma.session.update({ where: { - id: session.id + id: session.id, + goal: { + completed: false + }, }, data: { - goalId: goalId + goal: { + connect: { + id: newGoal.id + } + } } - }) + }); + + if (session.completed || session.cancelled) { + await prisma.goal.update({ + where: { + id: oldGoal.id + }, + data: { + minutes: { + decrement: session.elapsed + } + } + }); + + await prisma.goal.update({ + where: { + id: newGoal.id + }, + data: { + minutes: { + increment: session.elapsed + } + } + }); + } await Promise.all([ updateController(updatedSession),