Skip to content

Commit

Permalink
feat(api): event routes (#1)
Browse files Browse the repository at this point in the history
Co-authored-by: Qin Guan <[email protected]>
  • Loading branch information
Ethan-Chew and qin-guan authored Sep 24, 2023
1 parent 58343a3 commit 1271638
Show file tree
Hide file tree
Showing 9 changed files with 194 additions and 70 deletions.
2 changes: 1 addition & 1 deletion nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export default defineNuxtConfig({
debug: process.env.FIREBASE_APP_CHECK_DEBUG_TOKEN || isDevelopment,
provider: 'ReCaptchaEnterprise' || process.env.FIREBASE_APP_CHECK_PROVIDER,
key: '6LfNWy8oAAAAAG9GdaqR-X8t8721YyHyILD_C6Pu' || process.env.FIREBASE_APP_CHECK_KEY,
isTokenAutoRefreshEnabled: false,
isTokenAutoRefreshEnabled: true,
},
},

Expand Down
29 changes: 12 additions & 17 deletions server/api/event/[id].delete.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
import dayjs from 'dayjs'
import { eq } from 'drizzle-orm'
import { events } from '~/server/db/schema'

export default defineProtectedEventHandler(event => ({
id: event.context.params!.id,
name: 'SST Homecoming 2024',
description: 'SST Homecoming 2024',
location: 'SST',
badgeImage: 'https://www.sst.edu.sg/images/default-source/album/2019-2020/2020-01-24-homecoming/20200124_182000.jpg?sfvrsn=2',
startDateTime: dayjs(Date.now()).valueOf(),
endDateTime: dayjs(Date.now()).valueOf(),
attendees: [
{
id: '123',
name: 'Qin Guan',
admissionKey: '123',
},
],
}))
export default defineProtectedEventHandler(async (event) => {
const eventId = event.context.params!.id

await event.context.database.delete(events)
.where(eq(events.id, eventId))

return sendNoContent(event)
}, {
restrictTo: ['exco'],
})
53 changes: 37 additions & 16 deletions server/api/event/[id].get.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,39 @@
import dayjs from 'dayjs'
export default defineProtectedEventHandler(async (event) => {
const eventId = event.context.params!.id

export default defineProtectedEventHandler(event => ({
id: event.context.params!.id,
name: 'SST Homecoming 2024',
description: 'SST Homecoming 2024',
location: 'SST',
badgeImage: 'https://www.sst.edu.sg/images/default-source/album/2019-2020/2020-01-24-homecoming/20200124_182000.jpg?sfvrsn=2',
startDateTime: dayjs(Date.now()).valueOf(),
endDateTime: dayjs(Date.now()).valueOf(),
attendees: [
{
id: '123',
name: 'Qin Guan',
admissionKey: '123',
const result = await event.context.database.query.events.findFirst({
where: (events, { eq }) => eq(events.id, eventId),
with: {
usersToEvents: {
with: {
user: {
columns: {
id: true,
name: true,
},
},
},
columns: {
admissionKey: true,
},
},
},
],
}))
})

if (!result) {
throw createError({
status: 400,
statusMessage: 'Bad request',
})
}

const { usersToEvents, ...data } = result

return {
...data,
attendees: usersToEvents.map(({ admissionKey, user }) => ({
...user,
admissionKey,
})),
}
})
65 changes: 48 additions & 17 deletions server/api/event/[id].post.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,49 @@
import dayjs from 'dayjs'
import { eq } from 'drizzle-orm'
import { z } from 'zod'
import { events } from '~/server/db/schema'

export default defineProtectedEventHandler(event => ({
id: event.context.params!.id,
name: 'SST Homecoming 2024',
description: 'SST Homecoming 2024',
location: 'SST',
badgeImage: 'https://www.sst.edu.sg/images/default-source/album/2019-2020/2020-01-24-homecoming/20200124_182000.jpg?sfvrsn=2',
startDateTime: dayjs(Date.now()).valueOf(),
endDateTime: dayjs(Date.now()).valueOf(),
attendees: [
{
id: '123',
name: 'Qin Guan',
admissionKey: '123',
},
],
}))
const updateEventRequestBody = z.object({
name: z.string(),
description: z.string(),
location: z.string(),
badgeImage: z.string().url(),
startDateTime: z.string().datetime(),
endDateTime: z.string().datetime(),
})

export default defineProtectedEventHandler(async (event) => {
const eventId = event.context.params!.id

const result = await updateEventRequestBody.safeParseAsync(await readBody(event))
if (!result.success) {
throw createError({
status: 400,
statusMessage: 'Bad request',
})
}

const { data } = result

const updatedEvent = await event.context.database.update(events)
.set({
name: data.name,
description: data.description,
location: data.location,
badgeImage: data.badgeImage,
startDateTime: data.startDateTime,
endDateTime: data.endDateTime,
})
.where(eq(events.id, eventId))
.returning()

if (updatedEvent.length > 1) {
throw createError({
status: 500,
statusMessage: 'Internal server error',
})
}

return updatedEvent[0]
}, {
restrictTo: ['exco'],
})
56 changes: 39 additions & 17 deletions server/api/event/index.get.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,40 @@
import dayjs from 'dayjs'

export default defineProtectedEventHandler(event => [{
id: event.context.params!.id,
name: 'SST Homecoming 2024',
description: 'SST Homecoming 2024',
location: 'SST',
badgeImage: 'https://www.sst.edu.sg/images/default-source/album/2019-2020/2020-01-24-homecoming/20200124_182000.jpg?sfvrsn=2',
startDateTime: dayjs(Date.now()).valueOf(),
endDateTime: dayjs(Date.now()).valueOf(),
attendees: [
{
id: '123',
name: 'Qin Guan',
admissionKey: '123',
export default defineProtectedEventHandler(async (event) => {
const result = await event.context.database.query.events.findMany({
with: {
usersToEvents: {
with: {
user: {
columns: {
id: true,
name: true,
},
},
},
columns: {
admissionKey: true,
},
},
},
],
}])
})

if (!result) {
throw createError({
status: 400,
statusMessage: 'Bad request',
})
}

return result.map((item) => {
const { usersToEvents, ...data } = item

return {
...data,
attendees: usersToEvents.map(({ admissionKey, user }) => ({
...user,
admissionKey,
})),
}
})
}, {
restrictTo: ['exco'],
})
45 changes: 45 additions & 0 deletions server/api/event/index.post.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { z } from 'zod'
import { events } from '~/server/db/schema'

const createEventRequestBody = z.object({
name: z.string(),
description: z.string(),
location: z.string(),
badgeImage: z.string().url(),
startDateTime: z.string().datetime(),
endDateTime: z.string().datetime(),
})

export default defineProtectedEventHandler(async (event) => {
const result = await createEventRequestBody.safeParseAsync(await readBody(event))
if (!result.success) {
throw createError({
status: 400,
statusMessage: 'Bad request',
})
}

const { data } = result

const createdEvent = await event.context.database.insert(events)
.values({
name: data.name,
description: data.description,
location: data.location,
badgeImage: data.badgeImage,
startDateTime: data.startDateTime,
endDateTime: data.endDateTime,
})
.returning()

if (createdEvent.length > 1) {
throw createError({
status: 500,
statusMessage: 'Internal server error',
})
}

return createdEvent[0]
}, {
restrictTo: ['exco'],
})
2 changes: 1 addition & 1 deletion server/api/user/[id].delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ export default defineProtectedEventHandler(async (event) => {
eq(users.id, event.context.params!.id),
)

return { ok: true }
return sendNoContent(event)
})
2 changes: 1 addition & 1 deletion server/db/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const users = sqliteTable('users', {
})

export const events = sqliteTable('events', {
id: text('id').primaryKey(),
id: text('id').primaryKey().$defaultFn(() => createId()),
name: text('name').notNull(),
description: text('description').notNull(),
location: text('location').notNull(),
Expand Down
10 changes: 10 additions & 0 deletions server/utils/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ declare module 'h3' {
export interface DefineProtectedEventHandlerOptions {
cache?: Pick<CachedEventHandlerOptions, 'maxAge'>
allowUnlinkedUser?: boolean // Allow users which do not have a `firebaseId` linked in database
restrictTo?: Array<User['memberType']>
}

const defaultOptions: DefineProtectedEventHandlerOptions = {
Expand Down Expand Up @@ -61,6 +62,15 @@ export function defineProtectedEventHandler<T extends EventHandlerRequest, D>(
})
}

if (options.restrictTo) {
if (!user?.memberType || !options.restrictTo.includes(user.memberType)) {
throw createError({
status: 403,
statusMessage: 'Forbidden',
})
}
}

event.context.user = user
event.context.firebaseId = sub

Expand Down

0 comments on commit 1271638

Please sign in to comment.