Good news! Your account has been approved by the Student Government Association.
-Please click the link below to activate your account and set your password:
-Activate Account -If you did not request this account, please ignore this email.
-This link will expire in 3 days. If you do not activate your account within this time, you can request a password reset from the login page.
`, - subject: "Activate your Penmen Pride account", - to: targetUser.email, - }) - .then(() => { - console.log(`Sent approval email to ${targetUser.email}`); - }) - .catch(console.error); - - return { - user: User.parse(updatedUser[0]), - }; - }, -); diff --git a/src/lib/functions/new-users/block.remote.ts b/src/lib/functions/new-users/block.remote.ts deleted file mode 100644 index c6c0d14..0000000 --- a/src/lib/functions/new-users/block.remote.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { form, getRequestEvent } from "$app/server"; -import { User } from "$lib/models"; -import { sql } from "$lib/server/postgres"; -import { sgaOrAbove } from "$lib/utils/permissions"; -import { error } from "@sveltejs/kit"; -import z from "zod"; - -export const blockUser = form(z.object({ userId: z.string() }), async ({ userId }) => { - const { locals } = getRequestEvent(); - if (!locals.user) error(401, { message: "Unauthorized" }); - if (!sgaOrAbove(locals.user.role)) error(403, { message: "Forbidden" }); - - const users = await sql` - SELECT * - FROM users u - WHERE u.id = ${userId} - LIMIT 1 - `; - if (users.length === 0) error(404, { message: "User not found." }); - - const targetUser = User.parse(users[0]); - if (targetUser.role !== "unapproved") error(403, { message: "This account has already been approved." }); - - const updatedUser = await sql` - UPDATE users - SET role = 'blocked', updated_at = now() - WHERE id = ${targetUser.id} - RETURNING * - `; - if (updatedUser.count === 0) error(500, { message: "Failed to approve user." }); - - return User.parse(updatedUser[0]); -}); diff --git a/src/lib/functions/new-users/deny.remote.ts b/src/lib/functions/new-users/deny.remote.ts deleted file mode 100644 index 60c4ee6..0000000 --- a/src/lib/functions/new-users/deny.remote.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { form, getRequestEvent } from "$app/server"; -import { User } from "$lib/models"; -import { sql } from "$lib/server/postgres"; -import { sgaOrAbove } from "$lib/utils/permissions"; -import { error } from "@sveltejs/kit"; -import z from "zod"; - -export const denyUserRequest = form(z.object({ userId: z.string() }), async ({ userId }) => { - const { locals } = getRequestEvent(); - if (!locals.user) error(401, { message: "Unauthorized" }); - if (!sgaOrAbove(locals.user.role)) error(403, { message: "Forbidden" }); - - const users = await sql` - SELECT * - FROM users u - WHERE u.id = ${userId} - LIMIT 1 - `; - if (users.length === 0) error(404, { message: "User not found." }); - - const targetUser = User.parse(users[0]); - if (targetUser.role !== "unapproved") error(403, { message: "This account has already been approved." }); - - const updatedUser = await sql` - DELETE FROM users - WHERE id = ${targetUser.id} - `; - if (updatedUser.count === 0) error(500, { message: "Failed to deny user." }); - - return { success: true }; -}); diff --git a/src/lib/functions/onboarding.remote.ts b/src/lib/functions/onboarding.remote.ts index e0d22c2..44538d0 100644 --- a/src/lib/functions/onboarding.remote.ts +++ b/src/lib/functions/onboarding.remote.ts @@ -17,13 +17,12 @@ export const setPassword = form(SetPassword, async ({ _password, token }) => { if (users.length === 0) error(401, { message: "Invalid credentials" }); const user = User.parse(users[0]); - if (!user.pending) error(403, { message: "This account has already been activated." }); - - if (user.role === "unapproved") - error(403, { message: "Access denied. Please wait for approval email from SGA before logging in." }); + + if (user.role === "blocked") + error(403, { message: "Access denied. Your account has been blocked." }); if (user.role === "inactive") - error(401, { message: "Access denied. Your account has been marked as inactive. Contact SGA for assistance." }); + error(403, { message: "Access denied. Your account has been marked as inactive. Contact SGA for assistance." }); const passwordHash = await hashPassword(_password); diff --git a/src/lib/functions/register.remote.ts b/src/lib/functions/register.remote.ts index 837cbe2..d3a489a 100644 --- a/src/lib/functions/register.remote.ts +++ b/src/lib/functions/register.remote.ts @@ -1,18 +1,16 @@ import { form } from "$app/server"; import { Registration } from "$lib/models"; -import { createStudent, createUser, studentExists, userExists } from "$lib/server/postgres"; +import { createUser, userExists } from "$lib/server/postgres"; import { error } from "@sveltejs/kit"; export const register = form(Registration, async register => { - const [foundStudent, foundUser] = await Promise.all([ - studentExists(register.student_id), - userExists(register.student_id, register.email), + const [foundUser] = await Promise.all([ + userExists(register.email), ]); - if (foundUser) error(409, { message: "A user with that email or student ID already exists." }); + if (foundUser) error(409, { message: "A user with that email already exists." }); - if (!foundStudent) await createStudent(register); - await createUser(register.student_id, register.email, register.name, register.reason, "unapproved"); + await createUser(register.email, register.name); return { success: true }; }); diff --git a/src/lib/functions/reset-password.remote.ts b/src/lib/functions/reset-password.remote.ts index 255c310..39a20a2 100644 --- a/src/lib/functions/reset-password.remote.ts +++ b/src/lib/functions/reset-password.remote.ts @@ -18,11 +18,11 @@ export const resetPassword = form(SetPassword, async ({ _password, token }) => { const user = User.parse(users[0]); - if (user.role === "unapproved") - error(403, { message: "Access denied. Please wait for approval email from SGA before logging in." }); + if (user.role === "blocked") + error(403, { message: "Access denied. Your account has been blocked." }); if (user.role === "inactive") - error(401, { message: "Access denied. Your account has been marked as inactive. Contact SGA for assistance." }); + error(403, { message: "Access denied. Your account has been marked as inactive. Contact SGA for assistance." }); const passwordHash = await hashPassword(_password); diff --git a/src/lib/functions/scan.remote.ts b/src/lib/functions/scan.remote.ts new file mode 100644 index 0000000..4e712fa --- /dev/null +++ b/src/lib/functions/scan.remote.ts @@ -0,0 +1,45 @@ +import { form, getRequestEvent, command } from "$app/server"; +import { Event, Scan } from "$lib/models"; +import { sql } from "$lib/server/postgres"; +import { sgaOrAbove } from "$lib/utils/permissions"; +import { error } from "@sveltejs/kit"; + +export const scan = form(Scan.omit({ id: true, created_at: true }), async ({ wallet_pass_id, event_id }) => { + return await submitScan(wallet_pass_id, event_id); +}); + +export const manualScan = command(Scan.omit({ id: true, created_at: true }), async ({ wallet_pass_id, event_id }) => { + return await submitScan(wallet_pass_id, event_id); +}); + +async function submitScan(wallet_pass_id: string, event_id: string) { + const { locals } = getRequestEvent(); + if (!locals.user) error(401, { message: "Unauthorized" }); + if (!sgaOrAbove(locals.user.role)) error(403, { message: "Forbidden" }); + + // TODO: confirm pass here + // TODO: also try to get user if theres an attached one + + const [_event] = await sql` + SELECT * + FROM events + WHERE id = ${event_id} + LIMIT 1 +`; + if (!_event) error(404, { message: "Event not found." }); + + const event = Event.parse(_event); + + if (event.approval_status !== "accepted") error(403, { message: "Cannot tap into an event that is not accepted." }); + + const result = await sql` + INSERT INTO scans (wallet_pass_id, event_id) + VALUES (${wallet_pass_id}, ${event_id}) + ON CONFLICT (wallet_pass_id, event_id) DO NOTHING + RETURNING * +`; + if (result.length === 0) + error(500, { message: `${wallet_pass_id} has already been tapped for ${event.name}.` }); + + return { scan: Scan.parse(result[0]) }; +} diff --git a/src/lib/functions/tap.remote.ts b/src/lib/functions/tap.remote.ts deleted file mode 100644 index e841789..0000000 --- a/src/lib/functions/tap.remote.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { form, getRequestEvent, command } from "$app/server"; -import { Event, Student, Tap } from "$lib/models"; -import { sql } from "$lib/server/postgres"; -import { sgaOrAbove } from "$lib/utils/permissions"; -import { error } from "@sveltejs/kit"; - -export const tap = form(Tap.omit({ id: true, created_at: true }), async ({ student_id, event_id }) => { - return await submitTap(student_id, event_id); -}); - -export const manualTap = command(Tap.omit({ id: true, created_at: true }), async ({ student_id, event_id }) => { - return await submitTap(student_id, event_id); -}); - -async function submitTap(student_id: string, event_id: string) { - const { locals } = getRequestEvent(); - if (!locals.user) error(401, { message: "Unauthorized" }); - if (!sgaOrAbove(locals.user.role)) error(403, { message: "Forbidden" }); - - const [_student] = await sql` - INSERT INTO students (student_id) - VALUES (${student_id}) - ON CONFLICT (student_id) DO UPDATE - SET student_id = EXCLUDED.student_id - RETURNING * -`; - if (!_student) error(404, { message: "Failed to fetch student data." }); - - const student = Student.parse(_student); - - const [_event] = await sql` - SELECT * - FROM events - WHERE id = ${event_id} - LIMIT 1 -`; - if (!_event) error(404, { message: "Event not found." }); - - const event = Event.parse(_event); - - if (event.approval_status !== "accepted") error(403, { message: "Cannot tap into an event that is not accepted." }); - - const result = await sql` - INSERT INTO taps (student_id, event_id) - VALUES (${student_id}, ${event_id}) - ON CONFLICT (student_id, event_id) DO NOTHING - RETURNING * -`; - if (result.length === 0) - error(500, { message: `${student.student_id} has already been tapped for ${event.name}.` }); - - return { student, tap: Tap.parse(result[0]) }; -} diff --git a/src/lib/functions/user/points.remote.ts b/src/lib/functions/user/points.remote.ts index 6a15b7e..a984ec9 100644 --- a/src/lib/functions/user/points.remote.ts +++ b/src/lib/functions/user/points.remote.ts @@ -15,16 +15,16 @@ export const getPointsInActiveSemester = form(PointCheck, async check => { const [semesterResult, allTimeResult] = await Promise.all([ sql` SELECT COALESCE(SUM(e.point_value), 0) as total_points - FROM taps t - JOIN events e ON t.event_id = e.id - WHERE t.student_id = ${check.student_id} + FROM scans s + JOIN events e ON s.event_id = e.id + WHERE s.wallet_pass_id = ${check.wallet_pass_id} AND e.semester_id = ${semester.id} `, sql` SELECT COALESCE(SUM(e.point_value), 0) as total_points - FROM taps t - JOIN events e ON t.event_id = e.id - WHERE t.student_id = ${check.student_id} + FROM scans s + JOIN events e ON s.event_id = e.id + WHERE s.wallet_pass_id = ${check.wallet_pass_id} ` ]); @@ -37,9 +37,9 @@ export const getPointsInActiveSemester = form(PointCheck, async check => { export const getPointsAllTime = query(PointCheck, async check => { const points = await sql` SELECT COALESCE(SUM(e.point_value), 0) as total_points - FROM taps t - JOIN events e ON t.event_id = e.id - WHERE t.student_id = ${check.student_id} + FROM scans s + JOIN events e ON s.event_id = e.id + WHERE s.wallet_pass_id = ${check.wallet_pass_id} `; return { points: Number.parseInt(points.at(0)?.total_points) }; }); \ No newline at end of file diff --git a/src/lib/models.ts b/src/lib/models.ts index b6538c2..bfdec3e 100644 --- a/src/lib/models.ts +++ b/src/lib/models.ts @@ -10,14 +10,11 @@ export const Password = z .refine(val => /[0-9]/.test(val), { error: "Password must contain at least one number.", }) - .refine(val => /[^A-Za-z0-9].*[^A-Za-z0-9]/.test(val), { - error: "Password must contain at least two special characters.", + .refine(val => /[^A-Za-z0-9]/.test(val), { + error: "Password must contain at least one special character.", }); export type Password = z.inferNo swipes yet
+ {#if scanHistory.length === 0} +No scans yet
{:else}{record.studentId}
+{record.wallet_pass_id}
{record.eventName}