Skip to content

Commit

Permalink
Complete Professionals endpoint (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
mateusfg7 authored Jan 11, 2023
2 parents 0e95e91 + c823426 commit adb554a
Show file tree
Hide file tree
Showing 23 changed files with 557 additions and 195 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ PROJECT_ID=
CLIENT_EMAIL=
PRIVATE_KEY=
BUCKET_NAME=

# Prisma
DISABLE_ERD=true
23 changes: 16 additions & 7 deletions controllers/professionals/createProfessional.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { z } from 'zod'
import { File } from 'formidable'

import { prismaClient } from '@lib/prisma'
import { getUserFromHeader } from '@lib/getUserFromHeader'
import { uploadFileToGCS } from '@utils/uploadFileToGcs'
import { form } from '@utils/form'
import { generateUid } from '@utils/uid'
Expand All @@ -21,7 +22,6 @@ export async function createProfessional(
}

const fieldsSchema = z.object({
user_owner_id: z.string(),
name: z.string(),
email: z.string().email().optional(),
phone: z.string().optional(),
Expand All @@ -38,7 +38,6 @@ export async function createProfessional(
return res.status(400).json({ error: parsedFields.error.issues })

const {
user_owner_id,
name,
email,
phone,
Expand Down Expand Up @@ -68,38 +67,47 @@ export async function createProfessional(
.json({ message: 'File was not sent or parameter is invalid.' })
}

const user = getUserFromHeader(req)

try {
const registeredProfessional = await prismaClient.professional.findMany(
{
where: {
user_owner_id,
User: {
email: user.email,
},
},
}
)

if (registeredProfessional.length > 0)
if (registeredProfessional.length > 0) {
return res
.status(409)
.json({ message: 'User already registered as a professional.' })
}
} catch (err) {
console.error(err)
return res
.status(500)
.json({ error: err, message: 'Internal server error' })
}

const code = generateUid()

const parsedProfessionalName = name.toLowerCase().replaceAll(' ', '-')
const parsedFileType = file.mimetype?.split('/')[1]
const newFileName = `${generateUid()}_${parsedProfessionalName}.${parsedFileType}`
const newFileName = `${code}_${parsedProfessionalName}.${parsedFileType}`

const localFilePath = file.filepath
const gcsFilePath = `assets/profile-picture/${newFileName}`
const gcsFilePath = `assets/professionals/picture/${newFileName}`

try {
const fileUrlOnGCS = await uploadFileToGCS(localFilePath, gcsFilePath)

const professional = await prismaClient.professional.create({
data: {
name,
code,
email,
phone,
state_uf,
Expand All @@ -111,7 +119,7 @@ export async function createProfessional(
profile_picture_gcs_path: gcsFilePath,
User: {
connect: {
id: user_owner_id,
email: user.email,
},
},
services: {
Expand All @@ -125,6 +133,7 @@ export async function createProfessional(
services: true,
},
})

return res.status(201).json({ professional })
} catch (err) {
console.error(err)
Expand Down
42 changes: 28 additions & 14 deletions controllers/professionals/deleteProfessional.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,59 @@ import { NextApiRequest, NextApiResponse } from 'next'
import { z } from 'zod'

import { prismaClient } from '@lib/prisma'
import { getUserFromHeader } from '@lib/getUserFromHeader'
import { deleteFileFromGcs } from '@utils/deleteFileFromGcs'

export async function deleteProfessional(
req: NextApiRequest,
res: NextApiResponse
) {
const { body } = req
const { code } = req.query

const professionalDataSchema = z.object({
professional_id: z.string(),
})
const parsedProfessionalData = professionalDataSchema.safeParse(body)
const professionalCodeSchema = z.string()
const parsedProfessionalCode = professionalCodeSchema.safeParse(code)

if (!parsedProfessionalData.success)
return res.status(400).json({ error: parsedProfessionalData.error.issues })
if (!parsedProfessionalCode.success)
return res.status(400).json({ error: parsedProfessionalCode.error.issues })

const { professional_id } = parsedProfessionalData.data
const professionalCode = parsedProfessionalCode.data

try {
const professional = await prismaClient.professional.findMany({
const professional = await prismaClient.professional.findUnique({
where: {
id: professional_id,
code: professionalCode,
},
include: {
User: {
select: {
email: true,
},
},
},
})

if (professional.length === 0)
if (!professional)
return res.status(404).json({ message: 'Professional not found.' })

const user = getUserFromHeader(req)

if (user.email != professional.User.email) {
return res.status(401).json({
message: 'You do not have permission to delete this professional',
})
}

const deleteFromGcsResponse = await deleteFileFromGcs(
professional[0].profile_picture_gcs_path
professional.profile_picture_gcs_path
)
if (deleteFromGcsResponse.statusCode !== 204)
return res
.status(500)
.json({ message: 'Error while deleting professional.' })

await prismaClient.professional.deleteMany({
await prismaClient.professional.delete({
where: {
id: professional_id,
code: professionalCode,
},
})
res.status(204).end()
Expand Down
78 changes: 64 additions & 14 deletions controllers/professionals/findProfessional.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,86 @@ import { NextApiRequest, NextApiResponse } from 'next'
import { z } from 'zod'

import { prismaClient } from '@lib/prisma'
import { getUserFromHeader } from '@lib/getUserFromHeader'
import { getArrayAverage } from '@utils/arrayAverage'

export async function findProfessional(
req: NextApiRequest,
res: NextApiResponse
) {
const { body } = req
const { code } = req.query

const requestBodySchema = z.object({
professional_id: z.string(),
})
const parsedRequestBody = requestBodySchema.safeParse(body)
const professionalCodeSchema = z.string()
const parsedProfessionalCode = professionalCodeSchema.safeParse(code)

if (!parsedRequestBody.success)
return res.status(405).json({ error: parsedRequestBody.error.issues[0] })
if (!parsedProfessionalCode.success)
return res.status(400).json({ error: parsedProfessionalCode.error.issues })

const professionalCode = parsedProfessionalCode.data

const { professional_id } = parsedRequestBody.data
try {
const professional = await prismaClient.professional.findUnique({
where: {
id: professional_id,
code: professionalCode,
},
include: {
services: true,
services: {
select: {
service_name: true,
},
},
Rates: {
include: {
user: {
select: {
email: true,
},
},
},
},
saved_users: {
select: {
email: true,
},
},
},
})
if (professional) {
res.status(200).json({ professional })
} else {
res.status(404).json({ message: 'Professional not found.' })

if (!professional) {
return res.status(404).json({ message: 'Professional not found.' })
}

const user = getUserFromHeader(req)

const isSaved = professional.saved_users.includes({ email: user.email })

const ratedByUser = professional.Rates.find(
(rate) => rate.user.email === user.email
)
const isRated = ratedByUser != undefined ? true : false

const ratings = professional.Rates.map((rate) => rate.rate_value)
const averageRate = getArrayAverage(ratings)

const {
Rates,
saved_users,
id,
user_owner_id,
profile_picture_gcs_path,
createdAt,
updatedAt,
services,
...rest
} = professional

return res.status(200).json({
...rest,
isSaved,
isRated,
averageRate,
services: services.map((service) => service.service_name),
})
} catch (err) {
console.error(err)
return res
Expand Down
79 changes: 79 additions & 0 deletions controllers/professionals/saveProfessional.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { z } from 'zod'

import { prismaClient } from '@lib/prisma'
import { getUserFromHeader } from '@lib/getUserFromHeader'

export async function saveProfessional(
req: NextApiRequest,
res: NextApiResponse
) {
const { code } = req.body

const codeSchema = z.string()

const parsedCode = codeSchema.safeParse(code)

if (!parsedCode.success) {
return res.status(400).json({
message: 'Invalid professional code',
error: parsedCode.error.issues,
})
}

const { email } = getUserFromHeader(req)

try {
const professional = await prismaClient.professional.findUnique({
where: {
code: parsedCode.data,
},
include: {
saved_users: {
select: {
email: true,
},
},
},
})

if (!professional) {
return res.status(404).json({ message: 'Professional not found' })
}

const isProfessionalSaved = professional.saved_users.includes({ email })

if (isProfessionalSaved) {
await prismaClient.user.update({
where: {
email,
},
data: {
saved_professionals: {
disconnect: {
code: parsedCode.data,
},
},
},
})
} else {
await prismaClient.user.update({
where: {
email,
},
data: {
saved_professionals: {
connect: {
code: parsedCode.data,
},
},
},
})
}

return res.status(204).end()
} catch (error) {
console.log(error)
return res.status(500).json({ message: 'Internal server error.' })
}
}
Loading

1 comment on commit adb554a

@vercel
Copy link

@vercel vercel bot commented on adb554a Jan 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

formatch – ./

formatch.vercel.app
formatch-mateusfg7.vercel.app
formatch-git-main-mateusfg7.vercel.app

Please sign in to comment.