fix bugs + add a lot of endpoints

Co-authored-by: William Oldham <github@binaryoverload.co.uk>
This commit is contained in:
mrjvs
2023-10-28 21:08:01 +02:00
parent 8f503b9c5a
commit 542591342b
21 changed files with 369 additions and 29 deletions

39
src/routes/auth/login.ts Normal file
View File

@@ -0,0 +1,39 @@
import { formatSession } from '@/db/models/Session';
import { User } from '@/db/models/User';
import { StatusError } from '@/services/error';
import { handle } from '@/services/handler';
import { makeRouter } from '@/services/router';
import { makeSession, makeSessionToken } from '@/services/session';
import { z } from 'zod';
const loginSchema = z.object({
id: z.string(),
device: z.string().max(500).min(1),
});
export const loginAuthRouter = makeRouter((app) => {
app.post(
'/auth/login',
{ schema: { body: loginSchema } },
handle(async ({ em, body, req }) => {
const user = await em.findOne(User, { id: body.id });
if (user == null) {
throw new StatusError('User cannot be found', 401);
}
const session = makeSession(
user.id,
body.device,
req.headers['user-agent'],
);
await em.persistAndFlush(session);
return {
session: formatSession(session),
token: makeSessionToken(session),
};
}),
);
});

View File

@@ -8,6 +8,11 @@ import { z } from 'zod';
const registerSchema = z.object({
name: z.string().max(500).min(1),
device: z.string().max(500).min(1),
profile: z.object({
colorA: z.string(),
colorB: z.string(),
icon: z.string(),
}),
});
export const manageAuthRouter = makeRouter((app) => {
@@ -17,14 +22,15 @@ export const manageAuthRouter = makeRouter((app) => {
handle(async ({ em, body, req }) => {
const user = new User();
user.name = body.name;
user.profile = body.profile;
const session = makeSession(
user.id,
body.device,
req.headers['user-agent'],
);
em.persist([user, session]);
await em.flush();
await em.persistAndFlush([user, session]);
return {
user: formatUser(user),

View File

@@ -4,9 +4,9 @@ import { handle } from '@/services/handler';
import { makeRouter } from '@/services/router';
import { z } from 'zod';
export const sessionRouter = makeRouter((app) => {
export const authSessionRouter = makeRouter((app) => {
app.delete(
'/auth/session/:sid',
'/sessions/:sid',
{
schema: {
params: z.object({
@@ -15,16 +15,21 @@ export const sessionRouter = makeRouter((app) => {
},
},
handle(async ({ auth, params, em }) => {
auth.assert();
await auth.assert();
const targetedSession = await em.findOne(Session, { id: params.sid });
if (!targetedSession) return true; // already deleted
if (!targetedSession)
return {
id: params.sid,
};
if (targetedSession.user !== auth.user.id)
throw new StatusError('Cant delete sessions you dont own', 401);
throw new StatusError('Cannot delete sessions you do not own', 401);
await em.removeAndFlush(targetedSession);
return true;
return {
id: params.sid,
};
}),
);
});

28
src/routes/meta.ts Normal file
View File

@@ -0,0 +1,28 @@
import { conf } from '@/config';
import { handle } from '@/services/handler';
import { makeRouter } from '@/services/router';
export const metaRouter = makeRouter((app) => {
app.get(
'/healthcheck',
handle(async ({ em }) => {
const databaseConnected = await em.config
.getDriver()
.getConnection()
.isConnected();
return {
healthy: databaseConnected,
databaseConnected,
};
}),
);
app.get(
'/meta',
handle(async () => {
return {
name: conf.meta.name,
description: conf.meta.description,
};
}),
);
});

65
src/routes/sessions.ts Normal file
View File

@@ -0,0 +1,65 @@
import { Session, formatSession } from '@/db/models/Session';
import { StatusError } from '@/services/error';
import { handle } from '@/services/handler';
import { makeRouter } from '@/services/router';
import { z } from 'zod';
export const sessionsRouter = makeRouter((app) => {
app.patch(
'/sessions/:sid',
{
schema: {
params: z.object({
sid: z.string(),
}),
body: z.object({
name: z.string().max(500).min(1).optional(),
}),
},
},
handle(async ({ auth, params, em, body }) => {
await auth.assert();
const targetedSession = await em.findOne(Session, { id: params.sid });
if (!targetedSession)
throw new StatusError('Session cannot be found', 404);
if (targetedSession.user !== auth.user.id)
throw new StatusError('Cannot modify sessions you do not own', 401);
if (body.name) targetedSession.device = body.name;
await em.persistAndFlush(targetedSession);
return formatSession(targetedSession);
}),
);
app.delete(
'/sessions/:sid',
{
schema: {
params: z.object({
sid: z.string(),
}),
},
},
handle(async ({ auth, params, em }) => {
await auth.assert();
const targetedSession = await em.findOne(Session, { id: params.sid });
if (!targetedSession)
return {
id: params.sid,
};
if (targetedSession.user !== auth.user.id)
throw new StatusError('Cannot delete sessions you do not own', 401);
await em.removeAndFlush(targetedSession);
return {
id: params.sid,
};
}),
);
});

View File

@@ -0,0 +1,35 @@
import { Session } from '@/db/models/Session';
import { StatusError } from '@/services/error';
import { handle } from '@/services/handler';
import { makeRouter } from '@/services/router';
import { z } from 'zod';
export const sessionRouter = makeRouter((app) => {
app.delete(
'/sessions/:sid',
{
schema: {
params: z.object({
sid: z.string(),
}),
},
},
handle(async ({ auth, params, em }) => {
await auth.assert();
const targetedSession = await em.findOne(Session, { id: params.sid });
if (!targetedSession)
return {
id: params.sid,
};
if (targetedSession.user !== auth.user.id)
throw new StatusError('Cannot delete sessions you do not own', 401);
await em.removeAndFlush(targetedSession);
return {
id: params.sid,
};
}),
);
});

View File

@@ -0,0 +1,36 @@
import { Session } from '@/db/models/Session';
import { User } from '@/db/models/User';
import { StatusError } from '@/services/error';
import { handle } from '@/services/handler';
import { makeRouter } from '@/services/router';
import { z } from 'zod';
export const userDeleteRouter = makeRouter((app) => {
app.delete(
'/users/:uid',
{
schema: {
params: z.object({
uid: z.string(),
}),
},
},
handle(async ({ auth, params, em }) => {
await auth.assert();
const user = await em.findOne(User, { id: params.uid });
if (!user) throw new StatusError('User does not exist', 404);
if (auth.user.id !== user.id)
throw new StatusError('Cannot delete user other than yourself', 403);
const sessions = await em.find(Session, { user: user.id });
await em.remove([user, ...sessions]);
await em.flush();
return {
id: user.id,
};
}),
);
});

43
src/routes/users/edit.ts Normal file
View File

@@ -0,0 +1,43 @@
import { User, formatUser } from '@/db/models/User';
import { StatusError } from '@/services/error';
import { handle } from '@/services/handler';
import { makeRouter } from '@/services/router';
import { z } from 'zod';
export const userEditRouter = makeRouter((app) => {
app.patch(
'/users/:uid',
{
schema: {
params: z.object({
uid: z.string(),
}),
body: z.object({
profile: z
.object({
colorA: z.string(),
colorB: z.string(),
icon: z.string(),
})
.optional(),
name: z.string().max(500).min(1).optional(),
}),
},
},
handle(async ({ auth, params, body, em }) => {
await auth.assert();
const user = await em.findOne(User, { id: params.uid });
if (!user) throw new StatusError('User does not exist', 404);
if (auth.user.id !== user.id)
throw new StatusError('Cannot modify user other than yourself', 403);
if (body.name) user.name = body.name;
if (body.profile) user.profile = body.profile;
await em.persistAndFlush(user);
return formatUser(user);
}),
);
});

View File

@@ -0,0 +1,30 @@
import { Session, formatSession } from '@/db/models/Session';
import { StatusError } from '@/services/error';
import { handle } from '@/services/handler';
import { makeRouter } from '@/services/router';
import { z } from 'zod';
export const userSessionsRouter = makeRouter((app) => {
app.get(
'/users/:uid/sessions',
{
schema: {
params: z.object({
uid: z.string(),
}),
},
},
handle(async ({ auth, params, em }) => {
await auth.assert();
if (auth.user.id !== params.uid)
throw new StatusError('Cannot modify user other than yourself', 403);
const sessions = await em.find(Session, {
user: params.uid,
});
return sessions.map(formatSession);
}),
);
});