import { fail, redirect } from '@sveltejs/kit'; import { getRequestEvent } from '$app/server'; import type { Actions, PageServerLoad } from './$types'; import { db } from '$lib/server/db'; import * as table from '$lib/server/db/schema'; import { DirectMessageID, FriendRequestID, ServerID } from '$lib'; import { eq } from 'drizzle-orm'; import { and } from 'drizzle-orm'; import { type User } from '$lib/server/db/schema'; export const load: PageServerLoad = async () => { const user = requireLogin(); return { user }; }; export const actions = { addFriend: async ({ request, locals }) => { const data = await request.formData(); const username = data.get('username'); const userId = data.get('userId'); if (username && !userId) { if (typeof username !== 'string' || username.length < 3) { return fail(400, { error: 'Invalid username' }); } } let user: User[]; if (username) { user = await db .select() .from(table.user) .where(eq(table.user.username, username.toString())) .limit(1); } else if (userId) { user = await db .select() .from(table.user) .where(eq(table.user.id, userId.toString())) .limit(1); } else { return fail(400, { error: 'Missing username or userId' }); } if (locals.user?.friends.find((z) => z.id == user[0].id)) { return fail(400, { error: 'Already friends' }); } if (user?.length == 0) return fail(400, { error: 'User not found' }); const friendRequest = await db .select() .from(table.friendRequest) .where( and( eq(table.friendRequest.fromUser, user[0].id), eq(table.friendRequest.toUser, locals.user!.id) ) ) .limit(1); // user has already sent a request to us // means we want to accept it // if (friendRequest?.length != 0) { await db .delete(table.friendRequest) .where( and( eq(table.friendRequest.fromUser, user[0].id), eq(table.friendRequest.toUser, locals.user!.id) ) ) .limit(1); await db.insert(table.directMessage).values({ id: DirectMessageID.newV4(), firstMember: locals.user!.id, secondMember: user[0].id, messages: [] }); // add other guy to us await db.transaction(async (tx) => { await tx .update(table.user) .set({ friends: locals.user?.friends.map((z) => z.id).concat(user[0].id) }) .where(eq(table.user.id, locals.user!.id)); await tx .update(table.user) .set({ friends: (user[0].friends as string[]).concat(locals.user!.id) }) .where(eq(table.user.id, user[0].id)); }); return { success: true }; } // a request from us has already been sent to user if ( locals.user?.friendRequests.find( (z) => z.toUser == user[0].id && z.fromUser == locals.user!.id ) ) return fail(400, { error: 'Already sent request' }); await db.insert(table.friendRequest).values({ id: FriendRequestID.newV4(), fromUser: locals.user!.id, toUser: user[0].id, toUsername: user[0].username, fromUsername: locals.user!.username }); return { success: true }; }, cancelFriendRequest: async ({ request, locals }) => { const data = await request.formData(); const requestId = data.get('requestId'); if (typeof requestId !== 'string') { return fail(400, { error: 'Invalid request ID' }); } // fetch the friend request const friendRequest = await db .select() .from(table.friendRequest) .where(eq(table.friendRequest.id, requestId)) .limit(1); if (!friendRequest?.length) { return fail(404, { error: 'Friend request not found' }); } const fr = friendRequest[0]; // only allow cancelling if it's related to current user if (fr.fromUser !== locals.user!.id && fr.toUser !== locals.user!.id) { return fail(403, { error: 'Not allowed' }); } // delete the request await db.delete(table.friendRequest).where(eq(table.friendRequest.id, requestId)).limit(1); return { success: true }; }, createGroup: async ({ request, locals }) => { const data = await request.formData(); const members = data.getAll('member'); if (!members.length) { return fail(400, { error: 'No members selected' }); } return { success: true }; }, joinServer: async ({ request, locals }) => { const data = await request.formData(); const invite = data.get('invite'); if (typeof invite !== 'string') { return fail(400, { error: 'Invalid invite' }); } const inv = await db.select().from(table.invite).where(eq(table.invite.code, invite)).limit(1); if (inv?.length == 0) return fail(400, { error: 'Invalid invite' }); const server = await db .select() .from(table.server) .where(eq(table.server.id, inv[0].serverId)) .limit(1); if (server?.length == 0) return fail(400, { error: 'Invalid server' }); if (locals.user!.servers.some((z) => z.id == server[0].id)) return fail(400, { error: 'Already in server' }); await db.transaction(async (tx) => { await tx .update(table.user) .set({ servers: locals.user!.servers.map((z) => z.id).concat([server[0].id]) }) .where(eq(table.user.id, locals.user!.id)); await tx .update(table.server) .set({ members: (server[0].members as string[]).concat([locals.user!.id]) }) .where(eq(table.server.id, server[0].id)); }); return { success: true }; }, createServer: async ({ request, locals }) => { const data = await request.formData(); const name = data.get('name'); if (typeof name !== 'string' || name.length < 3) { return fail(400, { error: 'Server name too short' }); } const serverId = ServerID.newV4(); await db .insert(table.server) .values({ id: serverId, name, owner: locals.user!.id, members: [locals.user!.id] }); await db .update(table.user) .set({ servers: locals.user!.servers.map((z) => z.id).concat([serverId]) }) .where(eq(table.user.id, locals.user!.id)); redirect(303, `/app`); } } satisfies Actions; function requireLogin() { const { locals } = getRequestEvent(); if (!locals.user) { return redirect(302, '/login'); } return locals.user; }