Skip to content

Commit

Permalink
Merge pull request #38 from MatheusSanchez/SFD-85-edit-project
Browse files Browse the repository at this point in the history
Edit Project Feature
  • Loading branch information
MatheusSanchez authored Feb 1, 2024
2 parents e994853 + 707eb6a commit a3df30d
Show file tree
Hide file tree
Showing 8 changed files with 254 additions and 0 deletions.
81 changes: 81 additions & 0 deletions src/controller/project/editProject.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
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 Project E2E', () => {
beforeAll(async () => {
userRepository = new PrismaUsersRepository()
await app.ready()
})

afterAll(async () => {
await app.close()
})

it('should be able to edit a project', async () => {
const createProjectBody = {
title: 'Squad40 Project',
tags: ['react', 'node'],
link: 'https://Squad40.com',
description: 'Squad40 description',
}

const newUser = await userRepository.create({
email: '[email protected]',
name: 'John',
surname: 'Doe',
password_hash: 'password',
})

const createProjectResponse = await request(app.server)
.post(`/user/${newUser.id}/project`)
.send(createProjectBody)

const editProjectResponse = await request(app.server)
.put(`/project/${createProjectResponse.body.project.id}/edit`)
.send({
title: 'EditedTitle',
tags: ['react', 'node', 'edit'],
link: 'https://editedlin.com',
description: 'EditedDescription',
})

expect(createProjectResponse.statusCode).toEqual(201)

expect(editProjectResponse.statusCode).toEqual(200)

expect(editProjectResponse.body.project.title).toEqual('EditedTitle')
expect(editProjectResponse.body.project.tags).toEqual([
'react',
'node',
'edit',
])
expect(editProjectResponse.body.project.description).toEqual(
'EditedDescription',
)
})

it('should not be able to edit a project that does not exist', async () => {
const editProjectResponse = await request(app.server)
.put(`/project/${randomUUID()}/edit`)
.send({
title: 'EditedTitle',
tags: ['react', 'node', 'edit'],
link: 'https://editedlin.com',
description: 'EditedDescription',
})

expect(editProjectResponse.statusCode).toEqual(404)

expect(editProjectResponse.body).toEqual(
expect.objectContaining({
error: 'Project was not Found !',
}),
)
})
})
45 changes: 45 additions & 0 deletions src/controller/project/editProjectById.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { FastifyReply, FastifyRequest } from 'fastify'
import { z } from 'zod'
import { PrismaProjectRepository } from '../../repositories/prisma/prisma-project-repository'
import { ResourceNotFoundError } from '../../use-cases/errors/ResourceNotFoundError'
import { EditProjectUseCase } from '../../use-cases/project/editProjectUseCase'

export async function editProject(
request: FastifyRequest,
response: FastifyReply,
) {
const editProjectBodySchema = z.object({
title: z.string(),
tags: z.array(z.string()),
link: z.string(),
description: z.string(),
})

const editProjectParamsSchema = z.object({
projectId: z.string().uuid(),
})

const { title, tags, link, description } = editProjectBodySchema.parse(
request.body,
)
const { projectId } = editProjectParamsSchema.parse(request.params)

const projectRepository = new PrismaProjectRepository()
const editProjectUseCase = new EditProjectUseCase(projectRepository)

try {
const { project } = await editProjectUseCase.execute({
projectId,
title,
tags,
link,
description,
})

return response.status(200).send({ project })
} catch (error) {
if (error instanceof ResourceNotFoundError) {
return response.status(404).send({ error: 'Project was not Found !' })
}
}
}
3 changes: 3 additions & 0 deletions src/controller/project/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import { createProject } from './createProject'
import { getProjectsByUserId } from './getProjectsByUserId'
import { getProjectsById } from './getProjectById'
import { getProjectsByTags } from './getProjectsByTags'
import { editProject } from './editProjectById'

export async function projectRoutes(app: FastifyInstance) {
app.post('/projects/tags', getProjectsByTags)
app.get('/projects/:userId', getProjectsByUserId)
app.get('/project/:projectId', getProjectsById)
app.post('/user/:userId/project', createProject)

app.put('/project/:projectId/edit', editProject)
}
10 changes: 10 additions & 0 deletions src/repositories/in-memory-db/inMemoryProjectRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ export class InMemoryProjectRepository implements ProjectRepository {
return project
}

async edit(data: Prisma.ProjectUncheckedCreateInput): Promise<Project> {
const indexToUpdate = this.dbProject.findIndex(
(project) => project.id === data.id,
)

this.dbProject[indexToUpdate] = data as Project

return this.dbProject[indexToUpdate]
}

async fetchProjectsByUserId(userId: string): Promise<Project[]> {
const projects = this.dbProject.filter(
(project) => project.user_id === userId,
Expand Down
9 changes: 9 additions & 0 deletions src/repositories/prisma/prisma-project-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,13 @@ export class PrismaProjectRepository implements ProjectRepository {

return project
}

async edit(data: Prisma.ProjectUncheckedCreateInput): Promise<Project> {
const project = await prisma.project.update({
where: { id: data.id },
data,
})

return project
}
}
1 change: 1 addition & 0 deletions src/repositories/project-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export interface ProjectRepository {
fetchProjectsByUserId(userId: string): Promise<Project[]>
fetchProjectById(projectId: string): Promise<Project | null>
fetchProjectByTags(tags: string[]): Promise<Project[]>
edit(data: Prisma.ProjectUncheckedCreateInput): Promise<Project>
}
56 changes: 56 additions & 0 deletions src/use-cases/project/editProjectUseCase.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { expect, describe, it, beforeEach } from 'vitest'

import { InMemoryProjectRepository } from '../../repositories/in-memory-db/inMemoryProjectRepository'
import { ProjectRepository } from '../../repositories/project-repository'
import { ResourceNotFoundError } from '../errors/ResourceNotFoundError'
import { EditProjectUseCase } from './editProjectUseCase'

let projectRepository: ProjectRepository
let editProjectUseCase: EditProjectUseCase

describe('Edit Project By Id Use Case', () => {
beforeEach(() => {
projectRepository = new InMemoryProjectRepository()
editProjectUseCase = new EditProjectUseCase(projectRepository)
})

it('should be able edit one project by ID', async () => {
const projectWithoutEditing = await projectRepository.create({
title: 'React Typescript 1',
description: 'Best Project',
tags: ['react', 'node'],
link: 'https://github.com/luiseduardo3/nodets-petcanil',
user_id: 'user_id',
})

const { project: projectEdited } = await editProjectUseCase.execute({
title: 'New Title',
description: projectWithoutEditing.description,
tags: projectWithoutEditing.tags,
link: projectWithoutEditing.link,
projectId: projectWithoutEditing.id,
})

expect(projectEdited).toEqual(
expect.objectContaining({
title: 'New Title',
description: projectWithoutEditing.description,
tags: projectWithoutEditing.tags,
link: projectWithoutEditing.link,
id: projectWithoutEditing.id,
}),
)
})

it('should not be able to edit a project that does not exist', async () => {
await expect(() =>
editProjectUseCase.execute({
title: 'title',
description: 'description',
tags: ['tags'],
link: 'link',
projectId: 'projectThatDoesNotExist',
}),
).rejects.toBeInstanceOf(ResourceNotFoundError)
})
})
49 changes: 49 additions & 0 deletions src/use-cases/project/editProjectUseCase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Project } from '@prisma/client'

import { ProjectRepository } from '../../repositories/project-repository'

import { ResourceNotFoundError } from '../errors/ResourceNotFoundError'

interface EditProjectUseCaseRequest {
title: string
description: string
tags: string[]
link: string
projectId: string
}

interface EditProjectUseCaseResponse {
project: Project
}

export class EditProjectUseCase {
constructor(private projectRepository: ProjectRepository) {}

async execute({
title,
description,
link,
tags,
projectId,
}: EditProjectUseCaseRequest): Promise<EditProjectUseCaseResponse> {
const projectToBeUpdated =
await this.projectRepository.fetchProjectById(projectId)

if (!projectToBeUpdated) {
throw new ResourceNotFoundError()
}

const project = await this.projectRepository.edit({
id: projectId,
title,
tags,
link,
description,
user_id: projectToBeUpdated.user_id,
})

return {
project,
}
}
}

0 comments on commit a3df30d

Please sign in to comment.