Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"dotenv": "^16.4.5",
"express": "^4.21.2",
"express-asyncify": "^2.1.2",
"express-cargo": "^0.4.0",
"express-winston": "^4.2.0",
"firebase-admin": "^13.4.0",
"helmet": "^8.0.0",
Expand All @@ -33,6 +34,7 @@
"mongoose-paginate-v2": "^1.8.5",
"node-fetch": "^2.7.0",
"node-schedule": "^2.1.1",
"reflect-metadata": "^0.2.2",
"winston": "^3.16.0",
"winston-daily-rotate-file": "^5.0.0"
},
Expand Down
10 changes: 7 additions & 3 deletions apps/server/src/controllers/v1/enquiries.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import express, { Request, Response, Router } from 'express'
import asyncify from 'express-asyncify'
import { bindingCargo, getCargo } from 'express-cargo'

import { EnquiryModel } from '@/models'
import { verifyToken } from '@/middlewares/auth'
import { PostEnquiryPayload } from '@/types/payload/enquiry'

const router: Router = asyncify(express.Router())

router.post('/', verifyToken, async (req: Request, res: Response) => {
router.post('/', verifyToken, bindingCargo(PostEnquiryPayload), async (req: Request, res: Response) => {
const { title, body } = getCargo<PostEnquiryPayload>(req)

const enquiry = await EnquiryModel.create({
userId: req.user._id,
title: req.body.title,
body: req.body.body,
title,
body,
})
res.status(200).json({
enquiryId: enquiry._id,
Expand Down
231 changes: 116 additions & 115 deletions apps/server/src/controllers/v1/events.ts

Large diffs are not rendered by default.

21 changes: 13 additions & 8 deletions apps/server/src/controllers/v1/notifications.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import express, { Router } from 'express'
import asyncify from 'express-asyncify'
import { bindingCargo, getCargo } from 'express-cargo'

import { NotificationModel, NotificationTokenModel } from '@/models'
import { verifyToken } from '@/middlewares/auth'
import { GetNotificationPayload, PostNotificationReadPayload, PutNotificationTokenPayload } from '@/types/payload'

const router: Router = asyncify(express.Router())

router.get('/', verifyToken, async (req, res) => {
const options = { sort: { createdAt: -1 }, page: Number(req.query.page) || 1, limit: Number(req.query.limit) || 10 }
router.get('/', verifyToken, bindingCargo(GetNotificationPayload), async (req, res) => {
const { page, limit } = getCargo<GetNotificationPayload>(req)
const options = { sort: { createdAt: -1 }, page, limit }
const result = await NotificationModel.findByUserId(req.user._id, options)
res.status(200).json({
notifications: result.docs,
Expand All @@ -22,12 +25,13 @@ router.get('/', verifyToken, async (req, res) => {
})
})

router.put('/token', verifyToken, async (req, res) => {
router.put('/token', verifyToken, bindingCargo(PutNotificationTokenPayload), async (req, res) => {
const { deviceId, token, platform } = getCargo<PutNotificationTokenPayload>(req)
await NotificationTokenModel.findOneAndUpdate(
{ deviceId: req.body.deviceId },
{ deviceId: deviceId },
{
token: req.body.token,
platform: req.body.platform,
token: token,
platform: platform,
userId: req.user._id,
},
{
Expand All @@ -37,8 +41,9 @@ router.put('/token', verifyToken, async (req, res) => {
res.sendStatus(204)
})

router.post('/:id/read', verifyToken, async (req, res) => {
await NotificationModel.updateOne({ _id: req.params.id }, { isRead: true })
router.post('/:id/read', verifyToken, bindingCargo(PostNotificationReadPayload), async (req, res) => {
const { id } = getCargo<PostNotificationReadPayload>(req)
await NotificationModel.updateOne({ _id: id }, { isRead: true })
res.sendStatus(204)
})

Expand Down
11 changes: 7 additions & 4 deletions apps/server/src/controllers/v1/s3.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import express, { Router } from 'express'
import asyncify from 'express-asyncify'
import { bindingCargo, getCargo } from 'express-cargo'

import { s3 } from '@/services/aws'
import { AWS_S3_BUCKET } from '@/config'
import { GetS3UploadUrlPayload, GetS3ViewUrlPayload } from '@/types/payload'

const router: Router = asyncify(express.Router())

router.get('/upload-url', async (req, res) => {
const fileName = String(req.query.fileName)
router.get('/upload-url', bindingCargo(GetS3UploadUrlPayload), async (req, res) => {
const { fileName } = getCargo<GetS3UploadUrlPayload>(req)

const params = {
Bucket: AWS_S3_BUCKET!,
Expand All @@ -18,8 +21,8 @@ router.get('/upload-url', async (req, res) => {
res.json({ presignedUrl })
})

router.get('/view-url', async (req, res) => {
const key = req.query.key as string
router.get('/view-url', bindingCargo(GetS3ViewUrlPayload), async (req, res) => {
const { key } = getCargo<GetS3ViewUrlPayload>(req)

const params = {
Bucket: AWS_S3_BUCKET!,
Expand Down
52 changes: 18 additions & 34 deletions apps/server/src/controllers/v1/schedules.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import asyncify from 'express-asyncify'
import express, { Request, Response, Router } from 'express'
import { bindingCargo, getCargo } from 'express-cargo'

import { ScheduleModel } from '@/models'
import middlewares from '@/middlewares'
import { getUserDailyScheduleCount } from '@/services/schedule'
import { GetScheduleDailyCountPayload, GetSchedulePayload, IdPayload, PostSchedulePayload, PutSchedulePayload } from '@/types/payload'

const router: Router = asyncify(express.Router())
router.use(middlewares.auth.verifyToken)

router.post('/', middlewares.schedules.addScheduleMiddleware, async (req: Request, res: Response) => {
const { name, eventId, startDate, endDate, address, location, description, isAllDay } = req.body
router.post('/', bindingCargo(PostSchedulePayload), middlewares.schedules.addScheduleMiddleware, async (req: Request, res: Response) => {
const { name, eventId, startDate, endDate, address, location, description, isAllDay } = getCargo<PostSchedulePayload>(req)
const schedule = await ScheduleModel.create({
name: name,
eventId: eventId,
Expand All @@ -26,55 +28,37 @@ router.post('/', middlewares.schedules.addScheduleMiddleware, async (req: Reques
})
})

router.get('/', async (req: Request, res: Response) => {
const options = {
page: Number(req.query.page) || 0,
limit: Number(req.query.limit) || 100,
}

const filterOption = {
from: new Date(req.query.from as string) || new Date(0),
to: new Date(req.query.to as string) || new Date(),
}

router.get('/', bindingCargo(GetSchedulePayload), async (req: Request, res: Response) => {
const { from, to, page, limit } = getCargo<GetSchedulePayload>(req)
const userId = req.user?._id.toString()
const schedules = await ScheduleModel.findByUserId(userId, filterOption, options)
const schedules = await ScheduleModel.findByUserId(userId, { from, to }, { page, limit })

res.status(200).json(schedules)
})

router.get('/dailyCount', async (req: Request, res: Response) => {
const from = new Date(req.query.from as string) || new Date(0)
const to = new Date(req.query.to as string) || new Date()
const timezone = (req.query.timezone as string) || 'Asia/Seoul'

router.get('/dailyCount', bindingCargo(GetScheduleDailyCountPayload), async (req: Request, res: Response) => {
const { from, to, timezone } = getCargo<GetScheduleDailyCountPayload>(req)
const dailyScheduleCount = await getUserDailyScheduleCount(req.user, from, to, timezone)
res.status(200).json(dailyScheduleCount)
})

router.get('/:id', middlewares.schedules.verifyAuthorMiddleware, async (req: Request, res: Response) => {
const schedule = await ScheduleModel.findOne({ _id: req.params.id })
router.get('/:id', bindingCargo(IdPayload), middlewares.schedules.verifyAuthorMiddleware, async (req: Request, res: Response) => {
const { id } = getCargo<IdPayload>(req)
const schedule = await ScheduleModel.findOne({ _id: id })
res.status(200).json(schedule)
})

router.delete('/:id', middlewares.schedules.verifyAuthorMiddleware, async (req: Request, res: Response) => {
await ScheduleModel.deleteOne({ _id: req.params.id })
router.delete('/:id', bindingCargo(IdPayload), middlewares.schedules.verifyAuthorMiddleware, async (req: Request, res: Response) => {
const { id } = getCargo<IdPayload>(req)
await ScheduleModel.deleteOne({ _id: id })
res.sendStatus(204)
})

router.put('/:id', middlewares.schedules.verifyAuthorMiddleware, async (req: Request, res: Response) => {
const { id } = req.params
const { name, startDate, endDate, description, location, address } = req.body
router.put('/:id', bindingCargo(PutSchedulePayload), middlewares.schedules.verifyAuthorMiddleware, async (req: Request, res: Response) => {
const { id, name, startDate, endDate, isAllDay, description, location, address } = getCargo<PutSchedulePayload>(req)
const updated = await ScheduleModel.findOneAndUpdate(
{ _id: id },
{
name: name,
startDate: startDate,
endDate: endDate,
description: description,
address: address,
location: location,
},
{ name, startDate, endDate, isAllDay, description, address, location },
{ new: true },
)
res.status(200).json(updated)
Expand Down
30 changes: 15 additions & 15 deletions apps/server/src/controllers/v1/users.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import asyncify from 'express-asyncify'
import express, { Request, Response, Router } from 'express'

import { loginRequest, loginResponse, refreshResponse, registerRequest, registerResponse } from '@fienmee/types'
import asyncify from 'express-asyncify'
import { bindingCargo, getCargo } from 'express-cargo'
import { loginResponse, refreshResponse, registerResponse } from '@fienmee/types'

import { DeletedUserError, UnknownUserError } from '@/types/errors/oauth'
import { InvalidTokenTypeError } from '@/types/errors'
import { UserModel } from '@/models'
import { issueAccessToken, getOAuthUser, expireJwt, issueRefreshToken, unlinkUser } from '@/services/oauth'
import { verifyToken } from '@/middlewares/auth'
import { registerUser } from '@/services/user'
import { PostRegisterPayload, PostUserGoogleTokenPayload, PostUserInterestPayload, PostUserLoginPayload } from '@/types/payload'

const router: Router = asyncify(express.Router())

router.post('/login', async (req: Request, res: Response) => {
const request: loginRequest = req.body
router.post('/login', bindingCargo(PostUserLoginPayload), async (req: Request, res: Response) => {
const request = getCargo<PostUserLoginPayload>(req)

const oauthUser = await getOAuthUser(request)
const user = await UserModel.findByProviderId(oauthUser.providerId)
Expand Down Expand Up @@ -41,11 +42,9 @@ router.delete('/logout', async (req: Request, res: Response) => {
res.sendStatus(204)
})

router.post('/register', async (req: Request, res: Response) => {
const request: registerRequest = req.body

router.post('/register', bindingCargo(PostRegisterPayload), async (req: Request, res: Response) => {
const request = getCargo<PostRegisterPayload>(req)
const oauthUser = await getOAuthUser(request)

const user = await registerUser(oauthUser)

const accessToken = issueAccessToken(user)
Expand Down Expand Up @@ -92,8 +91,8 @@ router.delete('/', verifyToken, async (req: Request, res: Response) => {
res.sendStatus(204)
})

router.post('/google-token', async (req: Request, res: Response) => {
const serverAuthCode = req.body.code as string
router.post('/google-token', bindingCargo(PostUserGoogleTokenPayload), async (req: Request, res: Response) => {
const { code: serverAuthCode } = getCargo<PostUserGoogleTokenPayload>(req)

const params = new URLSearchParams()
params.append('code', serverAuthCode)
Expand All @@ -114,13 +113,14 @@ router.post('/google-token', async (req: Request, res: Response) => {
res.json(data.refresh_token)
})

router.put('/interest', verifyToken, async (req: Request, res: Response) => {
const isInterested = req.user.interests.some(category => category._id === req.body.interest)
router.put('/interest', verifyToken, bindingCargo(PostUserInterestPayload), async (req: Request, res: Response) => {
const { interest } = getCargo<PostUserInterestPayload>(req)
const isInterested = req.user.interests.some(category => category._id === interest)

if (isInterested) {
await UserModel.removeInterest(req.user._id, req.body.interest)
await UserModel.removeInterest(req.user._id, interest)
} else {
await UserModel.addInterest(req.user._id, req.body.interest)
await UserModel.addInterest(req.user._id, interest)
}

res.sendStatus(204)
Expand Down
27 changes: 27 additions & 0 deletions apps/server/src/types/payload/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { array, body, defaultValue, equal, params, query, validate } from 'express-cargo'

export class LocationType {
@body()
@equal('Point')
type: string

@body()
@array(Number)
@validate(value => Array.isArray(value) && value.length === 2)
coordinates: number[]
}

export class PaginationPayload {
@query()
@defaultValue(1)
page!: number

@query()
@defaultValue(10)
limit!: number
}

export class IdPayload {
@params()
id: string
}
10 changes: 10 additions & 0 deletions apps/server/src/types/payload/enquiry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { body } from 'express-cargo'
import { IEnquiryFormInputs } from '@fienmee/types'

export class PostEnquiryPayload implements IEnquiryFormInputs {
@body()
title: string

@body()
body: string
}
Loading