mirror of
https://github.com/michivonah/themepark-assistant.git
synced 2025-12-23 06:26:30 +01:00
Compare commits
No commits in common. "1729766d068e9f69618ed4b5dbb29bccb6f367b0" and "9a4fd29fa5e335b73d74ac52a1d4b97c18308163" have entirely different histories.
1729766d06
...
9a4fd29fa5
10 changed files with 50 additions and 255 deletions
|
|
@ -6,24 +6,24 @@ export const attraction = sqliteTable('attraction', {
|
||||||
id: integer().primaryKey({ autoIncrement: true }),
|
id: integer().primaryKey({ autoIncrement: true }),
|
||||||
name: text().notNull(),
|
name: text().notNull(),
|
||||||
apiCode: text('api_code').notNull().unique(),
|
apiCode: text('api_code').notNull().unique(),
|
||||||
themeparkId: integer('themepark_id').notNull().references(() => themepark.id, {onDelete: 'cascade'})
|
themeparkId: integer('themepark_id').notNull().references(() => themepark.id)
|
||||||
}, (t) => [
|
}, (t) => [
|
||||||
unique().on(t.apiCode, t.themeparkId)
|
unique().on(t.apiCode, t.themeparkId)
|
||||||
])
|
])
|
||||||
|
|
||||||
export const attractionNotification = sqliteTable('attraction_notification', {
|
export const attractionNotification = sqliteTable('attraction_notification', {
|
||||||
id: integer().primaryKey({ autoIncrement: true}),
|
id: integer().primaryKey({ autoIncrement: true}),
|
||||||
userId: integer('user_id').notNull().references(() => user.id, {onDelete: 'cascade'}),
|
userId: integer('user_id').notNull().references(() => user.id),
|
||||||
attractionId: integer('attraction_id').notNull().references(() => attraction.id, {onDelete: 'cascade'}),
|
attractionId: integer('attraction_id').notNull().references(() => attraction.id),
|
||||||
notificationMethodId: integer('notification_method_id').notNull().references(() => notificationMethod.id, {onDelete: 'cascade'})
|
notificationMethodId: integer('notification_method_id').notNull().references(() => notificationMethod.id)
|
||||||
}, (t) => [
|
}, (t) => [
|
||||||
unique().on(t.userId, t.attractionId, t.notificationMethodId)
|
unique().on(t.userId, t.attractionId, t.notificationMethodId)
|
||||||
])
|
])
|
||||||
|
|
||||||
export const logbook = sqliteTable('logbook', {
|
export const logbook = sqliteTable('logbook', {
|
||||||
id: integer().primaryKey({ autoIncrement: true }),
|
id: integer().primaryKey({ autoIncrement: true }),
|
||||||
userId: integer('user_id').notNull().references(() => user.id, {onDelete: 'cascade'}),
|
userId: integer('user_id').notNull().references(() => user.id),
|
||||||
attractionId: integer('attraction_id').notNull().references(() => attraction.id, {onDelete: 'cascade'}),
|
attractionId: integer('attraction_id').notNull().references(() => attraction.id),
|
||||||
timestamp: integer().notNull(), // unix timecode
|
timestamp: integer().notNull(), // unix timecode
|
||||||
expectedWaittime: integer(),
|
expectedWaittime: integer(),
|
||||||
realWaittime: integer()
|
realWaittime: integer()
|
||||||
|
|
@ -35,8 +35,8 @@ export const notificationMethod = sqliteTable('notification_method', {
|
||||||
id: integer().primaryKey({ autoIncrement: true }),
|
id: integer().primaryKey({ autoIncrement: true }),
|
||||||
webhookUrl: text('webhook_url').notNull(),
|
webhookUrl: text('webhook_url').notNull(),
|
||||||
shownName: text().notNull(),
|
shownName: text().notNull(),
|
||||||
userId: integer('user_id').notNull().references(() => user.id, {onDelete: 'cascade'}),
|
userId: integer('user_id').notNull().references(() => user.id),
|
||||||
notificationProviderId: integer('notification_provider_id').notNull().references(() => notificationProvider.id, {onDelete: 'cascade'}),
|
notificationProviderId: integer('notification_provider_id').notNull().references(() => notificationProvider.id),
|
||||||
}, (t) => [
|
}, (t) => [
|
||||||
unique().on(t.webhookUrl, t.userId, t.notificationProviderId)
|
unique().on(t.webhookUrl, t.userId, t.notificationProviderId)
|
||||||
])
|
])
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ export class InvalidParameter extends HTTPException{
|
||||||
super(400, { message:
|
super(400, { message:
|
||||||
paramName
|
paramName
|
||||||
? `Provided parameter '${paramName}' is invalid.`
|
? `Provided parameter '${paramName}' is invalid.`
|
||||||
: 'Provided invalid request parameter(s) or some required parameter is missing.'
|
: 'Provided invalid parameter.'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import attraction from './routes/attraction'
|
||||||
import notification from './routes/notification-method'
|
import notification from './routes/notification-method'
|
||||||
import logbook from './routes/logbook'
|
import logbook from './routes/logbook'
|
||||||
import themepark from './routes/themepark'
|
import themepark from './routes/themepark'
|
||||||
import user from './routes/user'
|
|
||||||
import cronRouter from './jobs/cron'
|
import cronRouter from './jobs/cron'
|
||||||
|
|
||||||
// create app
|
// create app
|
||||||
|
|
@ -38,7 +37,6 @@ app.route('/attraction', attraction)
|
||||||
app.route('/notification-method', notification)
|
app.route('/notification-method', notification)
|
||||||
app.route('/logbook', logbook)
|
app.route('/logbook', logbook)
|
||||||
app.route('/themepark', themepark)
|
app.route('/themepark', themepark)
|
||||||
app.route('/user', user)
|
|
||||||
export default {
|
export default {
|
||||||
fetch: app.fetch,
|
fetch: app.fetch,
|
||||||
scheduled: cronRouter,
|
scheduled: cronRouter,
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,9 @@
|
||||||
import { cache } from 'hono/cache'
|
import { cache } from 'hono/cache'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache unit to use for multiple endpoints as needed (TTL: 86400s)
|
* Cache unit to use for multiple endpoints as needed
|
||||||
*/
|
*/
|
||||||
export const responseCache = cache({
|
export const responseCache = cache({
|
||||||
cacheName: 'themepark-assistant',
|
cacheName: 'themepark-assistant',
|
||||||
cacheControl: 'max-age=86400'
|
cacheControl: 'max-age=86400'
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Cache for dynamic data (TTL: 30s)
|
|
||||||
*/
|
|
||||||
export const dynamicCache = cache({
|
|
||||||
cacheName: 'themepark-assistant-dynamic',
|
|
||||||
cacheControl: 'max-age=30s'
|
|
||||||
});
|
|
||||||
|
|
@ -8,23 +8,8 @@ import { InvalidParameter } from '../errors'
|
||||||
* @param schema Zod Validation scheme (docs: https://zod.dev/api)
|
* @param schema Zod Validation scheme (docs: https://zod.dev/api)
|
||||||
* @returns zValidator for running the validation
|
* @returns zValidator for running the validation
|
||||||
*/
|
*/
|
||||||
export function httpZValidator<T extends z.ZodTypeAny>(type: 'query' | 'json' | 'param' = 'query', schema: T){
|
export default function httpZValidator<T extends z.ZodTypeAny>(type: 'query' | 'json' | 'param' = 'query', schema: T){
|
||||||
return zValidator(type, schema, (result, c) => {
|
return zValidator(type, schema, (result, c) => {
|
||||||
if(!result.success) throw new InvalidParameter();
|
if(!result.success) throw new InvalidParameter();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Predefined validators
|
|
||||||
/**
|
|
||||||
* Validates if id is a number (using zod)
|
|
||||||
*/
|
|
||||||
export const idValidator = httpZValidator('param', z.strictObject({
|
|
||||||
id: z.coerce.number()
|
|
||||||
}));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates if notificationMethodId is number (using zod)
|
|
||||||
*/
|
|
||||||
export const notificationMethodIdValidator = httpZValidator('query', z.strictObject({
|
|
||||||
notificationMethodId: z.coerce.number()
|
|
||||||
}));
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Hono } from 'hono'
|
import { Hono, Context } from 'hono'
|
||||||
import { getDbContext } from '../db/client'
|
import { getDbContext } from '../db/client'
|
||||||
import { attractionNotification } from '../db/schema'
|
import { attractionNotification } from '../db/schema'
|
||||||
import { and, eq } from 'drizzle-orm'
|
import { and, eq } from 'drizzle-orm'
|
||||||
|
|
@ -6,14 +6,19 @@ import { DatabaseError, InvalidParameter, MissingParameter } from '../errors'
|
||||||
import { getUser } from '../lib/user-auth'
|
import { getUser } from '../lib/user-auth'
|
||||||
import { Message } from '../types/response'
|
import { Message } from '../types/response'
|
||||||
import { getNotificationMethodOwner } from '../lib/check-notification-method-owner'
|
import { getNotificationMethodOwner } from '../lib/check-notification-method-owner'
|
||||||
import { httpZValidator, idValidator, notificationMethodIdValidator } from '../lib/http-z-validator'
|
|
||||||
import * as z from 'zod'
|
|
||||||
|
|
||||||
const app = new Hono()
|
const app = new Hono()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if request has notificationMethodId parameter
|
||||||
|
* @param c Request context
|
||||||
|
* @returns if available notificationMethodId, else undefined
|
||||||
|
*/
|
||||||
|
function getNotificationMethodId(c: Context): number | undefined{
|
||||||
|
const str = c.req.query('notificationMethodId');
|
||||||
|
if(!str) return undefined;
|
||||||
|
return parseInt(str);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if drizzle db error has a message cause
|
* Checks if drizzle db error has a message cause
|
||||||
|
|
@ -32,12 +37,13 @@ function hasMessageCause(e: unknown): e is Error & { cause: { message: string }}
|
||||||
/**
|
/**
|
||||||
* Subscribe to waittime notifications from a specified attraction
|
* Subscribe to waittime notifications from a specified attraction
|
||||||
*/
|
*/
|
||||||
app.post('/:id/subscribe', idValidator, notificationMethodIdValidator, async (c) => {
|
app.post('/:id/subscribe', async (c) => {
|
||||||
const attractionId = c.req.valid('param').id;
|
const attractionId = parseInt(c.req.param('id'));
|
||||||
const db = getDbContext(c)
|
const db = getDbContext(c)
|
||||||
const user = await getUser(c);
|
const user = await getUser(c);
|
||||||
|
|
||||||
const notificationMethodId = c.req.valid('query').notificationMethodId;
|
const notificationMethodId = getNotificationMethodId(c);
|
||||||
|
if(!notificationMethodId) throw new MissingParameter('notificationMethodId');
|
||||||
|
|
||||||
const method = await getNotificationMethodOwner(db, notificationMethodId, user.id);
|
const method = await getNotificationMethodOwner(db, notificationMethodId, user.id);
|
||||||
|
|
||||||
|
|
@ -67,12 +73,12 @@ app.post('/:id/subscribe', idValidator, notificationMethodIdValidator, async (c)
|
||||||
/**
|
/**
|
||||||
* Unsubscribe to waittime notifications from a specified attraction
|
* Unsubscribe to waittime notifications from a specified attraction
|
||||||
*/
|
*/
|
||||||
app.post('/:id/unsubscribe', idValidator, notificationMethodIdValidator, async (c) => {
|
app.post('/:id/unsubscribe', async (c) => {
|
||||||
const attractionId = c.req.valid('param').id;
|
const attractionId = parseInt(c.req.param('id'));
|
||||||
const db = getDbContext(c)
|
const db = getDbContext(c)
|
||||||
const user = await getUser(c);
|
const user = await getUser(c);
|
||||||
|
|
||||||
const notificationMethodId = c.req.valid('query').notificationMethodId;
|
const notificationMethodId = getNotificationMethodId(c);
|
||||||
const methodOwner = notificationMethodId ? await getNotificationMethodOwner(db, notificationMethodId, user.id): false;
|
const methodOwner = notificationMethodId ? await getNotificationMethodOwner(db, notificationMethodId, user.id): false;
|
||||||
|
|
||||||
const queryConditions = [
|
const queryConditions = [
|
||||||
|
|
|
||||||
|
|
@ -1,150 +1,13 @@
|
||||||
import { Hono } from 'hono'
|
import { Hono } from 'hono'
|
||||||
import { DatabaseError } from '../errors'
|
|
||||||
import { getDbContext } from '../db/client'
|
|
||||||
import { logbook } from '../db/schema'
|
|
||||||
import { and, eq } from 'drizzle-orm'
|
|
||||||
import { getUser } from '../lib/user-auth'
|
|
||||||
import { Message } from '../types/response'
|
|
||||||
import { httpZValidator } from '../lib/http-z-validator'
|
|
||||||
import * as z from 'zod'
|
|
||||||
|
|
||||||
const app = new Hono()
|
const app = new Hono()
|
||||||
|
|
||||||
/**
|
app.get('/list', (c) => {
|
||||||
* Lists all logbook entries of the logged in user
|
return c.json(
|
||||||
*/
|
{
|
||||||
app.get('/list', async (c) => {
|
message: 'List all logbook entries'
|
||||||
const db = getDbContext(c);
|
|
||||||
const user = await getUser(c);
|
|
||||||
|
|
||||||
try{
|
|
||||||
const logbookEntries = await db.select({
|
|
||||||
entryId: logbook.id,
|
|
||||||
attractionId: logbook.attractionId,
|
|
||||||
timestamp: logbook.timestamp,
|
|
||||||
expectedWaittime: logbook.expectedWaittime,
|
|
||||||
realWaittime: logbook.realWaittime
|
|
||||||
}).from(logbook)
|
|
||||||
.where(eq(logbook.userId, user.id));
|
|
||||||
|
|
||||||
return c.json(logbookEntries);
|
|
||||||
}
|
}
|
||||||
catch{
|
|
||||||
throw new DatabaseError();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds new entry to the logbook of the current user
|
|
||||||
*/
|
|
||||||
app.post('/add-entry', httpZValidator('query', z.strictObject({
|
|
||||||
attractionId: z.coerce.number(),
|
|
||||||
timestamp: z.coerce.number().min(0).positive(),
|
|
||||||
expectedWaittime: z.coerce.number().optional(),
|
|
||||||
realWaittime: z.coerce.number().optional()
|
|
||||||
})),
|
|
||||||
async (c) => {
|
|
||||||
const db = getDbContext(c);
|
|
||||||
const user = await getUser(c);
|
|
||||||
|
|
||||||
const params = c.req.valid('query');
|
|
||||||
|
|
||||||
try{
|
|
||||||
const res = await db.insert(logbook).values({
|
|
||||||
userId: user.id,
|
|
||||||
attractionId: params.attractionId,
|
|
||||||
timestamp: params.timestamp,
|
|
||||||
expectedWaittime: params.expectedWaittime,
|
|
||||||
realWaittime: params.realWaittime
|
|
||||||
}).onConflictDoNothing().returning();
|
|
||||||
|
|
||||||
const newEntry = res[0];
|
|
||||||
|
|
||||||
const message = res.length > 0
|
|
||||||
? 'Added new entry to logbook.'
|
|
||||||
: 'Entry already exists. No changes made.';
|
|
||||||
|
|
||||||
return c.json(new Message(message, {
|
|
||||||
entryId: newEntry.id,
|
|
||||||
attractionId: newEntry.attractionId,
|
|
||||||
timestamp: newEntry.timestamp,
|
|
||||||
expectedWaittime: newEntry.expectedWaittime,
|
|
||||||
realWaittime: newEntry.realWaittime
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
catch{
|
|
||||||
throw new DatabaseError();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates waittime information of specified entry (by entryId)
|
|
||||||
*/
|
|
||||||
app.put('update-entry', httpZValidator('query', z.strictObject({
|
|
||||||
entryId: z.coerce.number(),
|
|
||||||
expectedWaittime: z.coerce.number().optional(),
|
|
||||||
realWaittime: z.coerce.number().optional()
|
|
||||||
}).refine((data) => data.expectedWaittime || data.realWaittime)),
|
|
||||||
async (c) => {
|
|
||||||
const db = getDbContext(c);
|
|
||||||
const user = await getUser(c);
|
|
||||||
const params = c.req.valid('query');
|
|
||||||
|
|
||||||
try{
|
|
||||||
const res = await db.update(logbook).set({
|
|
||||||
expectedWaittime: params.expectedWaittime,
|
|
||||||
realWaittime: params.realWaittime
|
|
||||||
}).where(and(
|
|
||||||
eq(logbook.userId, user.id),
|
|
||||||
eq(logbook.id, params.entryId)
|
|
||||||
)).returning();
|
|
||||||
|
|
||||||
const modifiedEntry = res[0];
|
|
||||||
|
|
||||||
return c.json(res.length > 0
|
|
||||||
? new Message('Updated logbook entry.', {
|
|
||||||
entryId: modifiedEntry.id,
|
|
||||||
attractionId: modifiedEntry.attractionId,
|
|
||||||
timestamp: modifiedEntry.timestamp,
|
|
||||||
expectedWaittime: modifiedEntry.expectedWaittime,
|
|
||||||
realWaittime: modifiedEntry.realWaittime
|
|
||||||
})
|
|
||||||
: new Message('Requested entry does not exist. No changes made.')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
catch{
|
|
||||||
throw new DatabaseError();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes specified logbook entry by entryId
|
|
||||||
*/
|
|
||||||
app.delete('remove-entry', httpZValidator('query', z.strictObject({
|
|
||||||
entryId: z.coerce.number()
|
|
||||||
})),
|
|
||||||
async (c) => {
|
|
||||||
const db = getDbContext(c);
|
|
||||||
const user = await getUser(c);
|
|
||||||
const params = c.req.valid('query');
|
|
||||||
|
|
||||||
try{
|
|
||||||
const res = await db.delete(logbook).where(
|
|
||||||
and(
|
|
||||||
eq(logbook.userId, user.id),
|
|
||||||
eq(logbook.id, params.entryId)
|
|
||||||
)
|
)
|
||||||
).returning();
|
|
||||||
|
|
||||||
const message = res.length > 0
|
|
||||||
? `Logbook entry with id ${params.entryId} was removed.`
|
|
||||||
: `No logbook entry with id ${params.entryId} found. No changes made.`;
|
|
||||||
|
|
||||||
return c.json(new Message(message));
|
|
||||||
}
|
|
||||||
catch{
|
|
||||||
throw new DatabaseError();
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export default app
|
export default app
|
||||||
|
|
@ -5,9 +5,6 @@ import { eq, and } from 'drizzle-orm'
|
||||||
import { getUser } from '../lib/user-auth'
|
import { getUser } from '../lib/user-auth'
|
||||||
import { DatabaseError, InvalidParameter, MissingParameter } from '../errors'
|
import { DatabaseError, InvalidParameter, MissingParameter } from '../errors'
|
||||||
import { Message } from '../types/response'
|
import { Message } from '../types/response'
|
||||||
import { responseCache, dynamicCache } from '../lib/cache'
|
|
||||||
import { httpZValidator, idValidator } from '../lib/http-z-validator'
|
|
||||||
import * as z from 'zod'
|
|
||||||
|
|
||||||
const app = new Hono()
|
const app = new Hono()
|
||||||
|
|
||||||
|
|
@ -54,7 +51,7 @@ app.get('/list', async (c) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
/** Lists all available notification providers */
|
/** Lists all available notification providers */
|
||||||
app.get('/list-providers', responseCache, async (c) => {
|
app.get('/list-providers', async (c) => {
|
||||||
const db = getDbContext(c);
|
const db = getDbContext(c);
|
||||||
|
|
||||||
try{
|
try{
|
||||||
|
|
@ -71,24 +68,21 @@ app.get('/list-providers', responseCache, async (c) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
/** Creates a new notification method from url, name & provider */
|
/** Creates a new notification method from url, name & provider */
|
||||||
app.post('/add-method', httpZValidator('query', z.strictObject({
|
app.post('/add-method', async (c) => {
|
||||||
url: z.string(),
|
|
||||||
name: z.string(),
|
|
||||||
provider: z.string()
|
|
||||||
})),
|
|
||||||
async (c) => {
|
|
||||||
const db = getDbContext(c);
|
const db = getDbContext(c);
|
||||||
const user = await getUser(c);
|
const user = await getUser(c);
|
||||||
|
|
||||||
const params = c.req.valid('query');
|
const { url, name, provider } = c.req.query();
|
||||||
|
|
||||||
const providerId = await getProviderId(db, params.provider);
|
if(!url || !name || !provider) throw new MissingParameter();
|
||||||
|
|
||||||
|
const providerId = await getProviderId(db, provider);
|
||||||
if(!providerId) throw new InvalidParameter('provider');
|
if(!providerId) throw new InvalidParameter('provider');
|
||||||
|
|
||||||
try{
|
try{
|
||||||
const newMethod = await db.insert(notificationMethod).values({
|
const newMethod = await db.insert(notificationMethod).values({
|
||||||
webhookUrl: params.url,
|
webhookUrl: url,
|
||||||
shownName: params.name,
|
shownName: name,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
notificationProviderId: providerId
|
notificationProviderId: providerId
|
||||||
}).returning().onConflictDoNothing().get();
|
}).returning().onConflictDoNothing().get();
|
||||||
|
|
@ -109,10 +103,12 @@ async (c) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
/** Removes a existing notification method by id (has to be owned by the current user) */
|
/** Removes a existing notification method by id (has to be owned by the current user) */
|
||||||
app.delete('/remove-method/:id', idValidator, async (c) => {
|
app.delete('/remove-method/:id', async (c) => {
|
||||||
const db = getDbContext(c);
|
const db = getDbContext(c);
|
||||||
const user = await getUser(c);
|
const user = await getUser(c);
|
||||||
const methodId = c.req.valid('param').id;
|
const methodId = parseInt(c.req.param('id'));
|
||||||
|
|
||||||
|
if(!methodId) throw new InvalidParameter('id');
|
||||||
|
|
||||||
try{
|
try{
|
||||||
const res = await db.delete(notificationMethod).where(
|
const res = await db.delete(notificationMethod).where(
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import { themepark, attraction } from '../db/schema'
|
||||||
import { responseCache } from '../lib/cache'
|
import { responseCache } from '../lib/cache'
|
||||||
import { eq } from 'drizzle-orm'
|
import { eq } from 'drizzle-orm'
|
||||||
import { DatabaseError } from '../errors'
|
import { DatabaseError } from '../errors'
|
||||||
import { idValidator } from '../lib/http-z-validator'
|
|
||||||
|
|
||||||
const app = new Hono()
|
const app = new Hono()
|
||||||
|
|
||||||
|
|
@ -31,8 +30,8 @@ app.get('/list', responseCache, async (c) => {
|
||||||
/**
|
/**
|
||||||
* Lists all attractions from a themepark with their id & name
|
* Lists all attractions from a themepark with their id & name
|
||||||
*/
|
*/
|
||||||
app.get('/list/:id/attraction', responseCache, idValidator, async (c) => {
|
app.get('/list/:id/attraction', responseCache, async (c) => {
|
||||||
const parkId = c.req.valid('param').id;
|
const parkId = parseInt(c.req.param('id'));
|
||||||
const db = getDbContext(c)
|
const db = getDbContext(c)
|
||||||
|
|
||||||
try{
|
try{
|
||||||
|
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
import { Hono } from 'hono'
|
|
||||||
import { DatabaseError } from '../errors'
|
|
||||||
import { getDbContext } from '../db/client'
|
|
||||||
import { getUser } from '../lib/user-auth'
|
|
||||||
import { user } from '../db/schema'
|
|
||||||
import { eq } from 'drizzle-orm'
|
|
||||||
import { Message } from '../types/response'
|
|
||||||
import { httpZValidator } from '../lib/http-z-validator'
|
|
||||||
import * as z from 'zod'
|
|
||||||
|
|
||||||
const app = new Hono()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes user account with all associated data (requires parameter 'confirm' to be true)
|
|
||||||
* Be careful when using (once your data is delete it cannot be restored)
|
|
||||||
*/
|
|
||||||
app.delete('delete-account', httpZValidator('query', z.strictObject({
|
|
||||||
confirm: z.literal('true') // to prevent unwanted account deletion when hitting the endpoint unintentionally
|
|
||||||
})),
|
|
||||||
async (c) => {
|
|
||||||
const db = getDbContext(c);
|
|
||||||
const currentUser = await getUser(c);
|
|
||||||
const params = c.req.valid('query');
|
|
||||||
|
|
||||||
try{
|
|
||||||
const res = await db.delete(user).where(
|
|
||||||
eq(user.id, currentUser.id)
|
|
||||||
).returning();
|
|
||||||
|
|
||||||
const deletedUser = res[0];
|
|
||||||
|
|
||||||
const message = res.length > 0
|
|
||||||
? `User account ${deletedUser.mail} with all associated data deleted.`
|
|
||||||
: 'User account does not exist. No changes made.';
|
|
||||||
|
|
||||||
return c.json(new Message(message));
|
|
||||||
}
|
|
||||||
catch(e){
|
|
||||||
console.error(e);
|
|
||||||
throw new DatabaseError();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
export default app
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue