chat.sad.ovh/src/routes/app/+page.server.ts

226 lines
6.4 KiB
TypeScript

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;
}