diff --git a/server/src/controller/project.controller.ts b/server/src/controller/project.controller.ts index d03abf0..a8c785b 100644 --- a/server/src/controller/project.controller.ts +++ b/server/src/controller/project.controller.ts @@ -4,21 +4,20 @@ import { ProjectService } from "../service/project.service"; const router = Router(); -const BASE_PATH = "/projects"; +export const apiNamespace = "/projects"; -export const getAllPath = BASE_PATH; -router.get(getAllPath, async (req, res) => { +router.get(apiNamespace, async (req, res) => { const projects = await ProjectService.listAllByUserId(req.userId) const response: ProjectDto[] = projects.map(project => ({ + id: project.id, name: project.name })) res.json(response) }); -export const createPath = BASE_PATH; -router.post(createPath, (req, res) => { +router.post(apiNamespace, (req, res) => { const { name } = req.body; ProjectService.create({ @@ -26,6 +25,7 @@ router.post(createPath, (req, res) => { userId: req.userId }).then(project => { const respose: ProjectDto = { + id: project.id, name: project.name } @@ -37,4 +37,28 @@ router.post(createPath, (req, res) => { }) }); +router.delete(`${apiNamespace}/:id`, async (req, res, next) => { + const { id } = req.params; + const projectId = parseInt(id) + + const userProjects = await ProjectService.listAllByUserId(req.userId) + const projecToBeDeleted = userProjects.find(project => project.id === projectId) + + if (projecToBeDeleted) { + const success = await ProjectService.destroyProject(projecToBeDeleted) + + if (success) { + res.json({ success }) + } else { + res.status(422).json({ + error: "Could not delete project" + }) + } + } else { + res.status(404).json({ + error: "Project not found" + }) + } +}); + export const ProjectRoutes = router; diff --git a/server/src/controller/user.controller.ts b/server/src/controller/user.controller.ts index d9c3579..6512a4f 100644 --- a/server/src/controller/user.controller.ts +++ b/server/src/controller/user.controller.ts @@ -2,15 +2,12 @@ import { Router } from 'express'; import { UserDto } from '../dto/user.dto'; import { AuthService } from '../service/auth.service'; import { UserService } from '../service/user.service'; -import { createPath as buildPath } from '../utils/createPath'; const router = Router(); -const BASE_PATH = '/users' +export const apiNamespace = '/users' -export const createPath = BASE_PATH - -router.post(createPath, (req, res) => { +router.post(apiNamespace, (req, res) => { const { email, password } = req.body; UserService.create({ @@ -30,8 +27,7 @@ router.post(createPath, (req, res) => { }) }) -export const signInPath = buildPath(BASE_PATH, 'sign_in') -router.post(signInPath, async (req, res) => { +router.post(`${apiNamespace}/sign_in`, async (req, res) => { const { email, password } = req.body; const user = await UserService.findByEmail(email) @@ -53,8 +49,7 @@ router.post(signInPath, async (req, res) => { } }) -export const signOutPath = buildPath(BASE_PATH, 'sign_out') -router.delete(signOutPath, async (req, res) => { +router.delete(`${apiNamespace}/sign_out`, async (req, res) => { const token = req.headers['x-access-token'] if (typeof token === 'string') { diff --git a/server/src/dto/poject.dto.ts b/server/src/dto/poject.dto.ts index 7e6ee1f..b7c996c 100644 --- a/server/src/dto/poject.dto.ts +++ b/server/src/dto/poject.dto.ts @@ -1,3 +1,4 @@ export type ProjectDto = { + id: number name: string } \ No newline at end of file diff --git a/server/src/entity/__test__/project.entity.spec.ts b/server/src/entity/__test__/project.entity.spec.ts index a8ddb2e..3ddc9fd 100644 --- a/server/src/entity/__test__/project.entity.spec.ts +++ b/server/src/entity/__test__/project.entity.spec.ts @@ -6,8 +6,12 @@ import { cleanDataSource } from "../../utils/cleanDataSource"; describe("Project", () => { beforeAll(async () => { await AppDataSource.initialize(); - await cleanDataSource(AppDataSource, ["project", "user"]); + await cleanDataSource(AppDataSource); }); + afterAll(async () => { + await cleanDataSource(AppDataSource); + await AppDataSource.destroy() + }) describe("relations", () => { it("should have many projects", async () => { diff --git a/server/src/entity/__test__/user.entity.spec.ts b/server/src/entity/__test__/user.entity.spec.ts index cefe1f3..ee4ca83 100644 --- a/server/src/entity/__test__/user.entity.spec.ts +++ b/server/src/entity/__test__/user.entity.spec.ts @@ -7,8 +7,12 @@ import { User } from "../user.entity"; describe("User", () => { beforeAll(async () => { await AppDataSource.initialize(); - await cleanDataSource(AppDataSource, ["project", "user"]); + await cleanDataSource(AppDataSource); }); + afterAll(async () => { + await cleanDataSource(AppDataSource); + await AppDataSource.destroy() + }) describe("relations", () => { it("should have many projects", async () => { diff --git a/server/src/middleware/__test__/unprotectedRoutes.spec.ts b/server/src/middleware/__test__/unprotectedRoutes.spec.ts index 47a1d95..15cd666 100644 --- a/server/src/middleware/__test__/unprotectedRoutes.spec.ts +++ b/server/src/middleware/__test__/unprotectedRoutes.spec.ts @@ -1,8 +1,9 @@ -import { signInPath, createPath } from '../../controller/users.controller'; -import { UNPROTECTED_ROUTES } from '../session.middleware' - -describe('Unprotected Routes', () => { - it('check content', () => { - expect(UNPROTECTED_ROUTES.sort()).toEqual([createPath, signInPath].sort()); +import {isRouteUnprotected} from '../session.middleware' +describe('isRouteUnprotected', () => { + it('validate unprotected routes', () => { + expect(isRouteUnprotected('/users')).toBeTruthy() + expect(isRouteUnprotected('/users/sign_in')).toBeTruthy() + expect(isRouteUnprotected('/users/sign_out')).toBeTruthy() + expect(isRouteUnprotected('/projects')).toBeFalsy() }) }) \ No newline at end of file diff --git a/server/src/middleware/session.middleware.ts b/server/src/middleware/session.middleware.ts index 4e39006..5b4ec57 100644 --- a/server/src/middleware/session.middleware.ts +++ b/server/src/middleware/session.middleware.ts @@ -1,14 +1,16 @@ -import { Handler, Request, Response } from 'express'; +import { RequestHandler } from 'express'; import { verify } from 'jsonwebtoken'; -import { signInPath, createPath } from '../controller/user.controller'; +import { apiNamespace as userControllerNamespace } from '../controller/user.controller'; import { AuthService } from '../service/auth.service'; -export const UNPROTECTED_ROUTES = [signInPath, createPath]; +export const isRouteUnprotected = (path: string) => { + return path.startsWith(userControllerNamespace) +} -export const sessionMiddleware: Handler = (req: Request, res: Response, next) => { +export const sessionMiddleware: RequestHandler = (req, res, next) => { const token = req.headers['x-access-token']; - if (UNPROTECTED_ROUTES.includes(req.url)) { + if (isRouteUnprotected(req.url)) { next(); } else if (typeof token === 'string') { AuthService.isSessionValid(token).then(valid => { diff --git a/server/src/service/__test__/auth.service.spec.ts b/server/src/service/__test__/auth.service.spec.ts index f60f474..67a27df 100644 --- a/server/src/service/__test__/auth.service.spec.ts +++ b/server/src/service/__test__/auth.service.spec.ts @@ -44,8 +44,6 @@ describe('AuthService', () => { }); }) - const currentUserEncryptedPassowrd = user.encryptedPassword - const result = await AuthService.isUserPasswordValid(user, 'example'); expect(result).toBeTruthy() @@ -66,8 +64,6 @@ describe('AuthService', () => { }); }) - const currentUserEncryptedPassowrd = user.encryptedPassword - const result = await AuthService.isUserPasswordValid(user, 'example2'); expect(result).toBeFalsy() diff --git a/server/src/service/project.service.ts b/server/src/service/project.service.ts index cbd0f42..6ba4f45 100644 --- a/server/src/service/project.service.ts +++ b/server/src/service/project.service.ts @@ -28,7 +28,17 @@ async function listAllByUserId(userId: User["id"]): Promise { return query.getMany(); } +async function destroyProject(project: Project): Promise{ + const query = projectRepository.createQueryBuilder(); + query.where('"id" = :projectId', { projectId: project.id }); + + const result = await query.delete().execute() + + return result.affected > 0; +} + export const ProjectService = { create, listAllByUserId, + destroyProject }; diff --git a/server/src/utils/cleanDataSource.ts b/server/src/utils/cleanDataSource.ts index ca7763d..ee28839 100644 --- a/server/src/utils/cleanDataSource.ts +++ b/server/src/utils/cleanDataSource.ts @@ -2,7 +2,7 @@ import { DataSource } from "typeorm"; export const cleanDataSource = async ( dataSource: DataSource, - entityNames: string[] + entityNames: string[] = ["project", "user"] ) => { if (process.env.NODE_ENV !== "test") { throw new Error( diff --git a/server/src/utils/createPath.ts b/server/src/utils/createPath.ts deleted file mode 100644 index 1f5dbed..0000000 --- a/server/src/utils/createPath.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const createPath = (...args: string[]): string => { - return args.join('/') -} \ No newline at end of file