diff --git a/src/controller/user/editUserById.spec.ts b/src/controller/user/editUserById.spec.ts new file mode 100644 index 0000000..ed632f1 --- /dev/null +++ b/src/controller/user/editUserById.spec.ts @@ -0,0 +1,71 @@ +import { afterAll, beforeAll, describe, expect, it } from 'vitest' +import request from 'supertest' +import { app } from '../../app' +import { randomUUID } from 'crypto' +import { PrismaUsersRepository } from '../../repositories/prisma/prisma-users-repository' +import { UserRepository } from '../../repositories/user-repository' + +let userRepository: UserRepository + +describe('edit User E2E', () => { + beforeAll(async () => { + userRepository = new PrismaUsersRepository() + await app.ready() + }) + + afterAll(async () => { + await app.close() + }) + + it('should be able to edit a user', async () => { + const email = 'john_doe@email.com' + const name = 'John' + const surname = 'Doe' + const password_hash = 'password_hash' + + const newUser = await userRepository.create({ + email, + name, + surname, + password_hash, + }) + + const editUserResponse = await request(app.server) + .put(`/user/${newUser.id}/edit`) + .send({ + name: 'newName', + surname: 'surname', + country: 'country', + }) + + expect(editUserResponse.statusCode).toEqual(200) + expect(editUserResponse.body.user).toEqual( + expect.objectContaining({ + name: 'newName', + surname: 'surname', + country: 'country', + id: newUser.id, + email, + password_hash, + }), + ) + }) + + it('should not be able to edit a user that does not exist', async () => { + const editUserResponse = await request(app.server) + .put(`/user/${randomUUID()}/edit`) + .send({ + name: 'newName', + surname: 'surname', + country: 'country', + }) + + expect(editUserResponse.statusCode).toEqual(404) + + expect(editUserResponse.body).toEqual( + expect.objectContaining({ + error: 'User was not Found !', + }), + ) + }) +}) diff --git a/src/controller/user/editUserById.ts b/src/controller/user/editUserById.ts new file mode 100644 index 0000000..f6d6ec4 --- /dev/null +++ b/src/controller/user/editUserById.ts @@ -0,0 +1,41 @@ +import { FastifyReply, FastifyRequest } from 'fastify' +import { z } from 'zod' +import { ResourceNotFoundError } from '../../use-cases/errors/ResourceNotFoundError' +import { PrismaUsersRepository } from '../../repositories/prisma/prisma-users-repository' +import { EditUserUseCase } from '../../use-cases/user/editUserUseCase' + +export async function editUserById( + request: FastifyRequest, + response: FastifyReply, +) { + const editUserBodySchema = z.object({ + name: z.string(), + surname: z.string(), + country: z.string(), + }) + + const editUserParamsSchema = z.object({ + userId: z.string().uuid(), + }) + + const { name, surname, country } = editUserBodySchema.parse(request.body) + const { userId } = editUserParamsSchema.parse(request.params) + + const userRepository = new PrismaUsersRepository() + const editUserUseCase = new EditUserUseCase(userRepository) + + try { + const { user } = await editUserUseCase.execute({ + name, + surname, + country, + userId, + }) + + return response.status(200).send({ user }) + } catch (error) { + if (error instanceof ResourceNotFoundError) { + return response.status(404).send({ error: 'User was not Found !' }) + } + } +} diff --git a/src/controller/user/routes.ts b/src/controller/user/routes.ts index 210da29..c5387ce 100644 --- a/src/controller/user/routes.ts +++ b/src/controller/user/routes.ts @@ -2,6 +2,7 @@ import { FastifyInstance } from 'fastify' import { getUserById } from './getUserById' import { getUserByEmail } from './getUserByEmail' import { registerUser } from './registerUser' +import { editUserById } from './editUserById' import { addImageUser } from './addImageToUser' import FastifyMultipart from '@fastify/multipart' @@ -15,6 +16,6 @@ export async function userRoutes(app: FastifyInstance) { app.post('/user', registerUser) app.get('/user/:id', getUserById) app.get('/user', getUserByEmail) - + app.put('/user/:userId/edit', editUserById) app.post('/user/:userId/photo', addImageUser) } diff --git a/src/repositories/in-memory-db/inMemoryUserRepository.ts b/src/repositories/in-memory-db/inMemoryUserRepository.ts index 8a735f9..2b8ce67 100644 --- a/src/repositories/in-memory-db/inMemoryUserRepository.ts +++ b/src/repositories/in-memory-db/inMemoryUserRepository.ts @@ -1,10 +1,9 @@ import { Prisma, User } from '@prisma/client' -import { UserRepository } from '../user-repository' +import { UserRepository, editUserRequestPrisma } from '../user-repository' import { randomUUID } from 'crypto' export class InMemoryUserRepository implements UserRepository { public db: User[] = [] - constructor() {} async findByEmail(email: string): Promise { @@ -53,6 +52,24 @@ export class InMemoryUserRepository implements UserRepository { return user } + + async edit({ + name, + surname, + country, + userId, + }: editUserRequestPrisma): Promise { + const indexToUpdate = this.db.findIndex((user) => user.id === userId) + + this.db[indexToUpdate] = { + ...this.db[indexToUpdate], + name, + surname, + country, + } + + return this.db[indexToUpdate] + } async addPhotoUrl(projectId: string, photoUrl: string): Promise { throw new Error('Method not implemented.') } diff --git a/src/repositories/prisma/prisma-users-repository.ts b/src/repositories/prisma/prisma-users-repository.ts index 468e366..aad6112 100644 --- a/src/repositories/prisma/prisma-users-repository.ts +++ b/src/repositories/prisma/prisma-users-repository.ts @@ -1,6 +1,6 @@ import { Prisma, User } from '@prisma/client' import { prisma } from '../../lib/prisma' -import { UserRepository } from '../user-repository' +import { UserRepository, editUserRequestPrisma } from '../user-repository' export class PrismaUsersRepository implements UserRepository { async findByEmail(email: string): Promise { @@ -31,6 +31,22 @@ export class PrismaUsersRepository implements UserRepository { return user } + + async edit({ + name, + surname, + country, + userId, + }: editUserRequestPrisma): Promise { + const user = await prisma.user.update({ + where: { id: userId }, + data: { name, surname, country }, + }) + + return user + } + + async addPhotoUrl(userId: string, photoUrl: string): Promise { const user = await prisma.user.update({ where: { diff --git a/src/repositories/user-repository.ts b/src/repositories/user-repository.ts index e6419b2..a91d34c 100644 --- a/src/repositories/user-repository.ts +++ b/src/repositories/user-repository.ts @@ -1,8 +1,16 @@ import { Prisma, User } from '@prisma/client' +export interface editUserRequestPrisma { + name: string + surname: string + country: string + userId: string +} + export interface UserRepository { create(data: Prisma.UserCreateInput): Promise findByEmail(email: string): Promise findById(id: string): Promise + edit({ name, surname, country, userId }: editUserRequestPrisma): Promise addPhotoUrl(userId: string, photoUrl: string): Promise } diff --git a/src/use-cases/user/editUserUseCase.spec.ts b/src/use-cases/user/editUserUseCase.spec.ts new file mode 100644 index 0000000..7f4bb2d --- /dev/null +++ b/src/use-cases/user/editUserUseCase.spec.ts @@ -0,0 +1,54 @@ +import { expect, describe, it, beforeEach } from 'vitest' + +import { ResourceNotFoundError } from '../errors/ResourceNotFoundError' +import { InMemoryUserRepository } from '../../repositories/in-memory-db/inMemoryUserRepository' +import { EditUserUseCase } from './editUserUseCase' + +let userRepository: InMemoryUserRepository + +let editUserUseCase: EditUserUseCase + +describe('Edit Project By Id Use Case', () => { + beforeEach(async () => { + userRepository = new InMemoryUserRepository() + editUserUseCase = new EditUserUseCase(userRepository) + }) + + it('should be able edit one user by ID', async () => { + const userToBeEdited = await userRepository.create({ + name: 'John', + surname: 'Doe', + email: 'johndoe@email.com', + password_hash: '123456', + }) + + const { user } = await editUserUseCase.execute({ + name: 'newCoolName', + surname: 'newSurCoolName', + country: 'differentCountry', + userId: userToBeEdited.id, + }) + + expect(user).toEqual( + expect.objectContaining({ + name: 'newCoolName', + surname: 'newSurCoolName', + country: 'differentCountry', + email: 'johndoe@email.com', + password_hash: '123456', + id: userToBeEdited.id, + }), + ) + }) + + it('should not be able to edit a user that does not exist', async () => { + await expect(() => + editUserUseCase.execute({ + name: 'newCoolName', + surname: 'newSurCoolName', + country: 'differentCountry', + userId: 'not-exist-id', + }), + ).rejects.toBeInstanceOf(ResourceNotFoundError) + }) +}) diff --git a/src/use-cases/user/editUserUseCase.ts b/src/use-cases/user/editUserUseCase.ts new file mode 100644 index 0000000..9a753ec --- /dev/null +++ b/src/use-cases/user/editUserUseCase.ts @@ -0,0 +1,43 @@ +import { User } from '@prisma/client' + +import { ResourceNotFoundError } from '../errors/ResourceNotFoundError' +import { UserRepository } from '../../repositories/user-repository' + +interface EditUserUseCaseRequest { + name: string + surname: string + country: string + userId: string +} + +interface EditUserUseCaseResponse { + user: User +} + +export class EditUserUseCase { + constructor(private userRepository: UserRepository) {} + + async execute({ + name, + surname, + country, + userId, + }: EditUserUseCaseRequest): Promise { + const userToBeUpdated = await this.userRepository.findById(userId) + + if (!userToBeUpdated) { + throw new ResourceNotFoundError() + } + + const user = await this.userRepository.edit({ + name, + surname, + country, + userId, + }) + + return { + user, + } + } +}