From 1a53b3dee62ebeb65e611fa6b024164dbf6b4071 Mon Sep 17 00:00:00 2001 From: Andrew Tapper Date: Sun, 20 Nov 2022 07:22:18 -0600 Subject: [PATCH] :goal_net: add error handler --- .../20221120122140_uniques/migration.sql | 20 +++++ prisma/schema.prisma | 8 ++ src/handlers/herd.ts | 83 +++++++++++++++++++ src/handlers/user.ts | 27 +++--- src/router.ts | 23 +++-- src/server.ts | 10 +++ 6 files changed, 155 insertions(+), 16 deletions(-) create mode 100644 prisma/migrations/20221120122140_uniques/migration.sql create mode 100644 src/handlers/herd.ts diff --git a/prisma/migrations/20221120122140_uniques/migration.sql b/prisma/migrations/20221120122140_uniques/migration.sql new file mode 100644 index 0000000..28c72d6 --- /dev/null +++ b/prisma/migrations/20221120122140_uniques/migration.sql @@ -0,0 +1,20 @@ +/* + Warnings: + + - A unique constraint covering the columns `[id,organizerId]` on the table `Feast` will be added. If there are existing duplicate values, this will fail. + - A unique constraint covering the columns `[id,shepherdId]` on the table `Herd` will be added. If there are existing duplicate values, this will fail. + - A unique constraint covering the columns `[id,feastId,googleId]` on the table `Place` will be added. If there are existing duplicate values, this will fail. + - A unique constraint covering the columns `[id,userId,placeId]` on the table `Vote` will be added. If there are existing duplicate values, this will fail. + +*/ +-- CreateIndex +CREATE UNIQUE INDEX "Feast_id_organizerId_key" ON "Feast"("id", "organizerId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Herd_id_shepherdId_key" ON "Herd"("id", "shepherdId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Place_id_feastId_googleId_key" ON "Place"("id", "feastId", "googleId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Vote_id_userId_placeId_key" ON "Vote"("id", "userId", "placeId"); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index b940385..08c61ce 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -45,6 +45,8 @@ model Feast { closed Boolean @default(false) winner Place? @relation(name: "winner", fields: [winnerId], references: [id]) winnerId String? + + @@unique([id, organizerId]) } model Herd { @@ -58,6 +60,8 @@ model Herd { members User[] @relation(name: "herds") feasts Feast[] + + @@unique([id, shepherdId]) } model Place { @@ -79,6 +83,8 @@ model Place { votes Vote[] wonFeasts Feast[] @relation(name: "winner") + + @@unique([id, feastId, googleId]) } model Vote { @@ -91,6 +97,8 @@ model Vote { place Place @relation(fields: [placeId], references: [id]) placeId String voteType VoteType + + @@unique([id, userId, placeId]) } enum VoteType { diff --git a/src/handlers/herd.ts b/src/handlers/herd.ts new file mode 100644 index 0000000..3917ec4 --- /dev/null +++ b/src/handlers/herd.ts @@ -0,0 +1,83 @@ +import prisma from '../db' + +// Get all herds +export const getAllHerds = async (req, res) => { + const user = await prisma.user.findUnique({ + where: { + id: req.user.id, + }, + include: { + herds: true, + }, + }) + + res.json({ ok: true, herds: user.herds }) +} + +// Get created herds +export const getShepHerds = async (req, res) => { + const user = await prisma.user.findUnique({ + where: { + id: req.user.id, + }, + include: { + shepHerds: true, + }, + }) + + res.json({ ok: true, data: { shepHerds: user.shepHerds } }) +} + +// Get one herd +export const getHerd = async (req, res) => { + const id = req.params.id + const herd = await prisma.herd.findFirst({ + where: { + id, + members: { + some: { + id: req.user.id, + }, + }, + }, + }) + res.json({ ok: true, data: { herd } }) +} + +// Create a herd +export const createHerd = async (req, res) => { + const herd = await prisma.herd.create({ + data: { + name: req.body.name, + shepherdId: req.user.id, + }, + }) + res.json({ ok: true, data: { herd } }) +} + +// Update a herd +export const updateHerd = async (req, res) => { + const updated = await prisma.herd.update({ + where: { + id_shepherdId: { + id: req.params.id, + shepherdId: req.user.id, + }, + }, + data: req.body, + }) + res.json({ ok: true, data: { updated } }) +} + +// Delete a herd +export const deleteHerd = async (req, res) => { + const deleted = await prisma.herd.delete({ + where: { + id_shepherdId: { + id: req.params.id, + shepherdId: req.user.id, + }, + }, + }) + res.json({ ok: true, data: { deleted } }) +} diff --git a/src/handlers/user.ts b/src/handlers/user.ts index 9bdcaa1..a95b2e1 100644 --- a/src/handlers/user.ts +++ b/src/handlers/user.ts @@ -1,18 +1,23 @@ import prisma from '../db' import { comparePwds, hashPwd, createJWT } from '../modules/auth' -export const signup = async (req, res) => { - const hashedPwd = await hashPwd(req.body.password) - const user = await prisma.user.create({ - data: { - username: req.body.username, - email: req.body.email, - password: hashedPwd, - }, - }) +export const signup = async (req, res, next) => { + try { + const hashedPwd = await hashPwd(req.body.password) + const user = await prisma.user.create({ + data: { + username: req.body.username, + email: req.body.email, + password: hashedPwd, + }, + }) - const token = createJWT(user) - res.json({ ok: true, token }) + const token = createJWT(user) + res.json({ ok: true, token }) + } catch (err) { + err.type = 'input' + next(err) + } } export const login = async (req, res) => { diff --git a/src/router.ts b/src/router.ts index 110204e..422f68e 100644 --- a/src/router.ts +++ b/src/router.ts @@ -1,27 +1,35 @@ import { Router } from 'express' import { body, oneOf, validationResult } from 'express-validator' +import { + createHerd, + deleteHerd, + getAllHerds, + getHerd, + getShepHerds, + updateHerd, +} from './handlers/herd' import { handleInputErrors } from './modules/middleware' const router = Router() // HERD -router.get('/herd', () => {}) -router.get('/herd/:id', () => {}) +router.get('/herd', getShepHerds) +router.get('/herd/:id', getHerd) router.put( '/herd/:id', body('name').optional(), body('members').optional(), body('feasts').optional(), handleInputErrors, - () => {}, + updateHerd, ) router.post( '/herd', body('name').exists().isString(), handleInputErrors, - () => {}, + createHerd, ) -router.delete('/herd/:id', () => {}) +router.delete('/herd/:id', deleteHerd) // FEAST router.get('/feast', (req, res) => { @@ -64,4 +72,9 @@ router.put('/vote/:id', () => {}) router.post('/vote', () => {}) router.delete('/vote/:id', () => {}) +router.use((err, req, res, next) => { + console.log(err) + res.json({ ok: false, message: 'Oops, DB error' }) +}) + export default router diff --git a/src/server.ts b/src/server.ts index 5bc6f7f..f85092a 100644 --- a/src/server.ts +++ b/src/server.ts @@ -22,4 +22,14 @@ app.use('/api', protect, router) app.post('/user', signup) app.post('/login', login) +app.use((err, req, res, next) => { + if (err.type === 'auth') { + res.json({ ok: false, message: 'Unauthorized' }) + } else if (err.type === 'input') { + res.json({ ok: false, message: 'Invalid input' }) + } else { + res.json({ ok: false, message: 'Something went wrong' }) + } +}) + export default app