From 6d1ad8c36eb040f42c3c7f1ce90fcbaad08fd030 Mon Sep 17 00:00:00 2001 From: ArnaudTa <33383276+ArnaudTA@users.noreply.github.com> Date: Wed, 27 Dec 2023 22:33:32 +0100 Subject: [PATCH 01/25] refactor: :art: unify router and handlers in same files --- .vscode/settings.json | 3 +- apps/server/package.json | 3 +- apps/server/src/__mocks__/app.ts | 6 +- apps/server/src/app.ts | 9 +- ...e-ci-files.spec.ts => controllers.spec.ts} | 0 apps/server/src/generate-files/controllers.ts | 74 +++++ .../src/generate-files/generate-ci-files.ts | 69 ---- .../src/resources/cluster/admin/business.ts | 66 ++-- .../cluster/admin/controllers.spec.ts} | 6 +- .../resources/cluster/admin/controllers.ts | 154 +++++---- .../src/resources/cluster/controllers.ts | 31 +- .../src/resources/environment/business.ts | 4 +- .../environment/controllers.spec.ts} | 6 +- .../src/resources/environment/controllers.ts | 243 +++++++------- .../index.ts => resources/index-admin.ts} | 16 +- .../server/src/{routes => resources}/index.ts | 16 +- .../log/admin/controllers.spec.ts} | 6 +- .../src/resources/log/admin/controllers.ts | 22 +- .../organization/admin/controllers.spec.ts} | 8 +- .../organization/admin/controllers.ts | 119 ++++--- .../src/resources/organization/business.ts | 4 +- .../src/resources/organization/controllers.ts | 32 +- .../organization}/organization.spec.ts | 6 +- .../resources/organization/organization.ts | 0 .../permission/controllers.spec.ts} | 6 +- .../src/resources/permission/controllers.ts | 177 +++++----- .../project/admin/controllers.spec.ts} | 6 +- .../resources/project/admin/controllers.ts | 59 ++-- .../project/controllers.spec.ts} | 6 +- .../src/resources/project/controllers.ts | 267 +++++++++------- .../quota/admin/controllers.spec.ts} | 6 +- .../src/resources/quota/admin/controllers.ts | 210 ++++++------ .../server/src/resources/quota/admin/quota.ts | 0 .../server/src/resources/quota/controllers.ts | 31 +- apps/server/src/resources/quota/quota.ts | 0 .../repository/controllers.spec.ts} | 6 +- .../src/resources/repository/controllers.ts | 273 ++++++++-------- .../repository/project-repository.ts | 0 apps/server/src/resources/service/business.ts | 4 +- .../service/controllers.spec.ts} | 6 +- .../src/resources/service/controllers.ts | 21 +- .../src/resources/stage/admin/business.ts | 9 +- .../stage/admin/controllers.spec.ts} | 10 +- .../src/resources/stage/admin/controllers.ts | 170 ++++++---- .../server/src/resources/stage/controllers.ts | 31 +- apps/server/src/resources/stage/stage.ts | 0 .../src/resources/system/db/controllers.ts | 19 +- .../user/admin/controllers.spec.ts} | 6 +- .../src/resources/user/admin/controllers.ts | 28 +- apps/server/src/resources/user/admin/user.ts | 0 .../user/controllers.spec.ts} | 6 +- apps/server/src/resources/user/controllers.ts | 302 ++++++++++-------- apps/server/src/routes/admin/cluster.ts | 40 --- apps/server/src/routes/admin/db.ts | 8 - apps/server/src/routes/admin/log.ts | 11 - apps/server/src/routes/admin/organization.ts | 40 --- apps/server/src/routes/admin/project.ts | 20 -- apps/server/src/routes/admin/quota.ts | 48 --- apps/server/src/routes/admin/stage.ts | 51 --- apps/server/src/routes/admin/user.ts | 16 - apps/server/src/routes/ci-files.ts | 8 - apps/server/src/routes/cluster.ts | 16 - apps/server/src/routes/organization.ts | 15 - apps/server/src/routes/project-environment.ts | 40 --- apps/server/src/routes/project-permission.ts | 40 --- apps/server/src/routes/project-repository.ts | 48 --- apps/server/src/routes/project-user.ts | 49 --- apps/server/src/routes/project.ts | 83 ----- apps/server/src/routes/quota.ts | 16 - apps/server/src/routes/service.ts | 8 - apps/server/src/routes/stage.ts | 16 - apps/server/src/types/index.ts | 24 +- apps/server/src/utils/controller.ts | 6 +- apps/server/src/utils/keycloak.ts | 13 +- apps/server/src/utils/logger.ts | 9 +- .../src/resources/cluster/openApiSchema.ts | 1 + .../src/resources/project/openApiSchema.ts | 16 + pnpm-lock.yaml | 175 ++-------- 78 files changed, 1527 insertions(+), 1852 deletions(-) rename apps/server/src/generate-files/{generate-ci-files.spec.ts => controllers.spec.ts} (100%) create mode 100644 apps/server/src/generate-files/controllers.ts delete mode 100644 apps/server/src/generate-files/generate-ci-files.ts rename apps/server/src/{routes/admin/cluster.spec.ts => resources/cluster/admin/controllers.spec.ts} (93%) rename apps/server/src/{routes/project-environment.spec.ts => resources/environment/controllers.spec.ts} (98%) rename apps/server/src/{routes/admin/index.ts => resources/index-admin.ts} (68%) rename apps/server/src/{routes => resources}/index.ts (68%) rename apps/server/src/{routes/admin/log.spec.ts => resources/log/admin/controllers.spec.ts} (91%) rename apps/server/src/{routes/admin/organization.spec.ts => resources/organization/admin/controllers.spec.ts} (96%) rename apps/server/src/{routes => resources/organization}/organization.spec.ts (90%) create mode 100644 apps/server/src/resources/organization/organization.ts rename apps/server/src/{routes/project-permission.spec.ts => resources/permission/controllers.spec.ts} (98%) rename apps/server/src/{routes/admin/project.spec.ts => resources/project/admin/controllers.spec.ts} (94%) rename apps/server/src/{routes/project.spec.ts => resources/project/controllers.spec.ts} (98%) rename apps/server/src/{routes/admin/quota.spec.ts => resources/quota/admin/controllers.spec.ts} (97%) create mode 100644 apps/server/src/resources/quota/admin/quota.ts create mode 100644 apps/server/src/resources/quota/quota.ts rename apps/server/src/{routes/project-repository.spec.ts => resources/repository/controllers.spec.ts} (97%) create mode 100644 apps/server/src/resources/repository/project-repository.ts rename apps/server/src/{routes/service.spec.ts => resources/service/controllers.spec.ts} (86%) rename apps/server/src/{routes/admin/stage.spec.ts => resources/stage/admin/controllers.spec.ts} (96%) create mode 100644 apps/server/src/resources/stage/stage.ts rename apps/server/src/{routes/admin/user.spec.ts => resources/user/admin/controllers.spec.ts} (91%) create mode 100644 apps/server/src/resources/user/admin/user.ts rename apps/server/src/{routes/project-user.spec.ts => resources/user/controllers.spec.ts} (98%) delete mode 100644 apps/server/src/routes/admin/cluster.ts delete mode 100644 apps/server/src/routes/admin/db.ts delete mode 100644 apps/server/src/routes/admin/log.ts delete mode 100644 apps/server/src/routes/admin/organization.ts delete mode 100644 apps/server/src/routes/admin/project.ts delete mode 100644 apps/server/src/routes/admin/quota.ts delete mode 100644 apps/server/src/routes/admin/stage.ts delete mode 100644 apps/server/src/routes/admin/user.ts delete mode 100644 apps/server/src/routes/ci-files.ts delete mode 100644 apps/server/src/routes/cluster.ts delete mode 100644 apps/server/src/routes/organization.ts delete mode 100644 apps/server/src/routes/project-environment.ts delete mode 100644 apps/server/src/routes/project-permission.ts delete mode 100644 apps/server/src/routes/project-repository.ts delete mode 100644 apps/server/src/routes/project-user.ts delete mode 100644 apps/server/src/routes/project.ts delete mode 100644 apps/server/src/routes/quota.ts delete mode 100644 apps/server/src/routes/service.ts delete mode 100644 apps/server/src/routes/stage.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index b1e83b785..0fb777997 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,7 +2,7 @@ // Format "editor.wordWrap": "on", "editor.codeActionsOnSave": { - "source.fixAll": true, + "source.fixAll": "explicit" }, "eslint.packageManager": "pnpm", "eslint.enable": true, @@ -34,6 +34,7 @@ "scss.validate": false, // JS "javascript.preferences.importModuleSpecifierEnding": "js", + "typescript.preferences.importModuleSpecifierEnding": "js", "javascript.preferences.quoteStyle": "single", "[javascript]": { "editor.defaultFormatter": "dbaeumer.vscode-eslint", diff --git a/apps/server/package.json b/apps/server/package.json index 004df4882..aea63fada 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -3,19 +3,20 @@ "@dso-console/shared": "workspace:*", "@fastify/cookie": "^9.2.0", "@fastify/helmet": "^11.1.1", - "@fastify/session": "^10.6.1", "@fastify/swagger": "^8.12.0", "@fastify/swagger-ui": "^1.10.1", "@gitbeaker/core": "^39.25.0", "@gitbeaker/rest": "^39.25.0", "@keycloak/keycloak-admin-client": "^23.0.1", "@kubernetes/client-node": "^0.20.0", + "@mgcrea/fastify-session": "^2.2.1", "@prisma/client": "^5.6.0", "axios": "^1.6.2", "date-fns": "^2.30.0", "dotenv": "^16.3.1", "fastify": "^4.24.3", "fastify-keycloak-adapter": "^2.1.6", + "json-schema-to-ts": "^2.9.2", "mustache": "^4.2.0", "nanoid": "5.0.2", "node-vault-client": "^1.0.0", diff --git a/apps/server/src/__mocks__/app.ts b/apps/server/src/__mocks__/app.ts index 3fdc6c4b9..dc8b564ed 100644 --- a/apps/server/src/__mocks__/app.ts +++ b/apps/server/src/__mocks__/app.ts @@ -1,10 +1,10 @@ import { vi } from 'vitest' import fastify from 'fastify' import fastifyCookie from '@fastify/cookie' -import fastifySession from '@fastify/session' +import fastifySession from '@mgcrea/fastify-session' import fp from 'fastify-plugin' import { addAllSchemasToApp, apiPrefix } from '@/app.js' -import { apiRouter, miscRouter } from '@/routes/index.js' +import { apiRouter, miscRouter } from '@/resources/index.js' import { sessionConf } from '@/utils/keycloak.js' import { User } from '@dso-console/test-utils' @@ -129,7 +129,7 @@ export const getRequestor = () => { const mockSessionPlugin = (app, opt, next) => { app.addHook('onRequest', (req, res, next) => { - req.session = { user: getRequestor() } + req.session = { data: { user: getRequestor() } } next() }) next() diff --git a/apps/server/src/app.ts b/apps/server/src/app.ts index a028f37b6..1e68311ce 100644 --- a/apps/server/src/app.ts +++ b/apps/server/src/app.ts @@ -1,7 +1,7 @@ -import fastify, { FastifyInstance } from 'fastify' +import fastify, { type FastifyInstance, type FastifyRequest } from 'fastify' import helmet from '@fastify/helmet' import keycloak from 'fastify-keycloak-adapter' -import fastifySession from '@fastify/session' +import fastifySession from '@mgcrea/fastify-session' import fastifyCookie from '@fastify/cookie' import fastifySwagger from '@fastify/swagger' import fastifySwaggerUi from '@fastify/swagger-ui' @@ -22,12 +22,11 @@ import { stageOpenApiSchema, } from '@dso-console/shared' -import { apiRouter, miscRouter } from './routes/index.js' +import { apiRouter, miscRouter } from './resources/index.js' import { addReqLogs, loggerConf } from './utils/logger.js' import { DsoError } from './utils/errors.js' import { keycloakConf, sessionConf } from './utils/keycloak.js' import { isInt, isDev, isTest, keycloakRedirectUri } from './utils/env.js' -import { type FastifyRequestWithSession } from './types/index.js' export const apiPrefix = '/api/v1' @@ -91,7 +90,7 @@ const app: FastifyInstance = addAllSchemasToApp(fastify(fastifyConf)) opts.logLevel = 'silent' } }) - .setErrorHandler(function (error: DsoError | Error, req: FastifyRequestWithSession, reply) { + .setErrorHandler(function (error: DsoError | Error, req: FastifyRequest, reply) { const isDsoError = error instanceof DsoError const statusCode = isDsoError ? error.statusCode : 500 diff --git a/apps/server/src/generate-files/generate-ci-files.spec.ts b/apps/server/src/generate-files/controllers.spec.ts similarity index 100% rename from apps/server/src/generate-files/generate-ci-files.spec.ts rename to apps/server/src/generate-files/controllers.spec.ts diff --git a/apps/server/src/generate-files/controllers.ts b/apps/server/src/generate-files/controllers.ts new file mode 100644 index 000000000..8217b0326 --- /dev/null +++ b/apps/server/src/generate-files/controllers.ts @@ -0,0 +1,74 @@ +import * as fs from 'node:fs/promises' +import Mustache from 'mustache' +import path from 'node:path' + +import { addReqLogs } from '@/utils/logger.js' +import { sendCreated } from '@/utils/response.js' +import { type GenerateCIFilesDto } from '@dso-console/shared' + +import { type FastifyInstance } from 'fastify' + +const router = async (app: FastifyInstance, _opt) => { + app.post<{ + Body: GenerateCIFilesDto, + }>('/', async (req, res) => { + const content: Record = {} + const data = req.body + + if (data.typeLanguage === 'java') { + data.isJava = true + data.isNode = false + data.isPython = false + } + if (data.typeLanguage === 'node') { + data.isNode = true + data.isJava = false + data.isPython = false + } + if (data.typeLanguage === 'python') { + data.isPython = true + data.isNode = false + data.isJava = false + } + + try { + const template = await fs.readFile(path.resolve('src/generate-files/templates/gitlab-ci.yml')) + const gitlab = Mustache.render(template.toString(), data) + content['gitlab-ci-dso'] = gitlab + + const rules = await fs.readFile(path.resolve('src/generate-files/templates/rules.yml')) + content.rules = Mustache.render(rules.toString()) + const vault = await fs.readFile(path.resolve('src/generate-files/templates/vault.yml')) + content.vault = Mustache.render(vault.toString()) + const docker = await fs.readFile(path.resolve('src/generate-files/templates/docker.yml')) + content.docker = Mustache.render(docker.toString()) + + if (data.typeLanguage === 'python') { + const python = await fs.readFile(path.resolve('src/generate-files/templates/python.yml')) + content.python = Mustache.render(python.toString()) + } else if (data.typeLanguage === 'java') { + const java = await fs.readFile(path.resolve('src/generate-files/templates/java.yml')) + content.java = Mustache.render(java.toString()) + } else if (data.typeLanguage === 'node') { + const node = await fs.readFile(path.resolve('src/generate-files/templates/node.yml')) + content.node = Mustache.render(node.toString()) + } + + addReqLogs({ + req, + description: 'Fichiers de gitlab-ci créés avec succès', + }) + sendCreated(res, content) + } catch (error) { + const description = 'Echec de la création des fichiers de gitlab-ci' + addReqLogs({ + req, + description, + error, + }) + throw new Error(error?.message) + } + }) +} + +export default router diff --git a/apps/server/src/generate-files/generate-ci-files.ts b/apps/server/src/generate-files/generate-ci-files.ts deleted file mode 100644 index 461eded3a..000000000 --- a/apps/server/src/generate-files/generate-ci-files.ts +++ /dev/null @@ -1,69 +0,0 @@ -import * as fs from 'node:fs/promises' -import Mustache from 'mustache' -import path from 'node:path' - -import { addReqLogs } from '@/utils/logger.js' -import { sendCreated } from '@/utils/response.js' -import { type FastifyRequestWithSession } from '@/types' -import { type GenerateCIFilesDto } from '@dso-console/shared' - -export const generateCIFiles = async (req: FastifyRequestWithSession<{ - Body: GenerateCIFilesDto, -}>, res) => { - const content: Record = {} - const data = req.body - - if (data.typeLanguage === 'java') { - data.isJava = true - data.isNode = false - data.isPython = false - } - if (data.typeLanguage === 'node') { - data.isNode = true - data.isJava = false - data.isPython = false - } - if (data.typeLanguage === 'python') { - data.isPython = true - data.isNode = false - data.isJava = false - } - - try { - const template = await fs.readFile(path.resolve('src/generate-files/templates/gitlab-ci.yml')) - const gitlab = Mustache.render(template.toString(), data) - content['gitlab-ci-dso'] = gitlab - - const rules = await fs.readFile(path.resolve('src/generate-files/templates/rules.yml')) - content.rules = Mustache.render(rules.toString()) - const vault = await fs.readFile(path.resolve('src/generate-files/templates/vault.yml')) - content.vault = Mustache.render(vault.toString()) - const docker = await fs.readFile(path.resolve('src/generate-files/templates/docker.yml')) - content.docker = Mustache.render(docker.toString()) - - if (data.typeLanguage === 'python') { - const python = await fs.readFile(path.resolve('src/generate-files/templates/python.yml')) - content.python = Mustache.render(python.toString()) - } else if (data.typeLanguage === 'java') { - const java = await fs.readFile(path.resolve('src/generate-files/templates/java.yml')) - content.java = Mustache.render(java.toString()) - } else if (data.typeLanguage === 'node') { - const node = await fs.readFile(path.resolve('src/generate-files/templates/node.yml')) - content.node = Mustache.render(node.toString()) - } - - addReqLogs({ - req, - description: 'Fichiers de gitlab-ci créés avec succès', - }) - sendCreated(res, content) - } catch (error) { - const description = 'Echec de la création des fichiers de gitlab-ci' - addReqLogs({ - req, - description, - error, - }) - throw new Error(error?.message) - } -} diff --git a/apps/server/src/resources/cluster/admin/business.ts b/apps/server/src/resources/cluster/admin/business.ts index 9dfaaed19..fa638ef87 100644 --- a/apps/server/src/resources/cluster/admin/business.ts +++ b/apps/server/src/resources/cluster/admin/business.ts @@ -1,9 +1,10 @@ import { linkClusterToProjects, addLogs, createCluster as createClusterQuery, getClusterById, getClusterByLabel, getProjectsByClusterId, getStagesByClusterId, removeClusterFromProject, removeClusterFromStage, updateCluster as updateClusterQuery, getClusterEnvironments, deleteCluster as deleteClusterQuery } from '@/resources/queries-index.js' import { BadRequestError, DsoError, NotFoundError } from '@/utils/errors.js' import { hooks } from '@/plugins/index.js' -import { type CreateClusterDto, type UpdateClusterDto, clusterSchema, exclude } from '@dso-console/shared' -import { type User } from '@prisma/client' +import { type CreateClusterDto, clusterSchema, updateClusterSchema } from '@dso-console/shared' +import { Cluster, type User } from '@prisma/client' import { linkClusterToStages } from '@/resources/stage/business.js' +import { FromSchema } from 'json-schema-to-ts' export const checkClusterProjectIds = (data: CreateClusterDto) => { // si le cluster est dedicated, la clé projectIds doit être renseignée @@ -37,26 +38,30 @@ export const createCluster = async (data: CreateClusterDto, userId: User['id']) const isLabelTaken = await getClusterByLabel(data.label) if (isLabelTaken) throw new BadRequestError('Ce label existe déjà pour un autre cluster', undefined) - // TODO check if secretName is available with validation plugins - const kubeConfig = { - user: data.user, - cluster: data.cluster, - } - const clusterData = exclude(structuredClone(data), ['projectIds', 'stageIds', 'user', 'cluster']) - const cluster = await createClusterQuery(clusterData, kubeConfig) + const { + projectIds, + stageIds, + user, + cluster, + ...clusterData + } = data + + // @ts-ignore + const clusterCreated = await createClusterQuery(clusterData, { user, cluster }) - await linkClusterToProjects(cluster.id, data.projectIds) + await linkClusterToProjects(clusterCreated.id, projectIds) - await linkClusterToStages(cluster.id, data.stageIds) + await linkClusterToStages(clusterCreated.id, stageIds) - const results = await hooks.createCluster.execute({ ...cluster, user: data.user, cluster: data.cluster }) + // @ts-ignore + const results = await hooks.createCluster.execute({ ...clusterCreated, user, cluster }) // @ts-ignore await addLogs('Create Cluster', results, userId) - return cluster + return clusterCreated } -export const updateCluster = async (data: UpdateClusterDto, clusterId: UpdateClusterDto['id']) => { +export const updateCluster = async (data: FromSchema, clusterId: Cluster['id']) => { if (data?.privacy === 'public') delete data.projectIds await clusterSchema.validateAsync(data, { presence: 'optional' }) @@ -68,37 +73,46 @@ export const updateCluster = async (data: UpdateClusterDto, clusterId: UpdateClu user: data.user, cluster: data.cluster, } - const clusterData = exclude(structuredClone(data), ['projectIds', 'stageIds', 'user', 'cluster']) - const cluster = await updateClusterQuery(clusterId, clusterData, kubeConfig) + const { + projectIds, + stageIds, + user, + cluster, + ...clusterData + } = data + // @ts-ignore + const clusterUpdated = await updateClusterQuery(clusterId, clusterData, { user, cluster }) + + // @ts-ignore await hooks.updateCluster.execute({ ...cluster, user: { ...kubeConfig.user }, cluster: { ...kubeConfig.cluster } }) - if (data.projectIds) { - await linkClusterToProjects(clusterId, data.projectIds) + if (projectIds) { + await linkClusterToProjects(clusterId, projectIds) const dbProjects = await getProjectsByClusterId(clusterId) for (const project of dbProjects) { - if (!data.projectIds.includes(project.id)) { - await removeClusterFromProject(cluster.id, project.id) + if (!projectIds.includes(project.id)) { + await removeClusterFromProject(clusterUpdated.id, project.id) } } } - if (data.stageIds) { - await linkClusterToStages(clusterId, data.stageIds) + if (stageIds) { + await linkClusterToStages(clusterId, stageIds) const dbStages = await getStagesByClusterId(clusterId) for (const stage of dbStages) { - if (!data.stageIds.includes(stage.id)) { - await removeClusterFromStage(cluster.id, stage.id) + if (!stageIds.includes(stage.id)) { + await removeClusterFromStage(clusterUpdated.id, stage.id) } } } - return cluster + return clusterUpdated } -export const deleteCluster = async (clusterId: string, userId: string) => { +export const deleteCluster = async (clusterId: Cluster['id'], userId: User['id']) => { try { const environments = await getClusterAssociatedEnvironments(clusterId) if (environments?.length) throw new BadRequestError('Impossible de supprimer le cluster, des environnements en activité y sont déployés', { extras: environments }) diff --git a/apps/server/src/routes/admin/cluster.spec.ts b/apps/server/src/resources/cluster/admin/controllers.spec.ts similarity index 93% rename from apps/server/src/routes/admin/cluster.spec.ts rename to apps/server/src/resources/cluster/admin/controllers.spec.ts index 06e3152cc..5b68abba7 100644 --- a/apps/server/src/routes/admin/cluster.spec.ts +++ b/apps/server/src/resources/cluster/admin/controllers.spec.ts @@ -1,7 +1,7 @@ -import prisma from '../../__mocks__/prisma.js' -import app, { getRequestor, setRequestor } from '../../__mocks__/app.js' +import prisma from '../../../__mocks__/prisma.js' +import app, { getRequestor, setRequestor } from '../../../__mocks__/app.js' import { vi, describe, it, expect, beforeAll, afterEach, afterAll, beforeEach } from 'vitest' -import { getConnection, closeConnections } from '../../connect.js' +import { getConnection, closeConnections } from '../../../connect.js' import { adminGroupPath } from '@dso-console/shared' import { getRandomCluster, getRandomRole, getRandomUser } from '@dso-console/test-utils' diff --git a/apps/server/src/resources/cluster/admin/controllers.ts b/apps/server/src/resources/cluster/admin/controllers.ts index 1df32ee9c..9ca274640 100644 --- a/apps/server/src/resources/cluster/admin/controllers.ts +++ b/apps/server/src/resources/cluster/admin/controllers.ts @@ -1,5 +1,3 @@ -import { type CreateClusterDto, type UpdateClusterDto, type ClusterParams } from '@dso-console/shared' -import { type FastifyRequestWithSession } from '@/types/index.js' import { addReqLogs } from '@/utils/logger.js' import { sendCreated, sendNoContent, sendOk } from '@/utils/response.js' import { @@ -9,83 +7,107 @@ import { getClusterAssociatedEnvironments, deleteCluster, } from './business.js' -import { type RouteHandler } from 'fastify' +import type { FastifyInstance } from 'fastify' -// GET -export const getClusterAssociatedEnvironmentsController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: ClusterParams -}>, res) => { - const clusterId = req.params.clusterId +import { createClusterSchema, getClusterAssociatedEnvironmentsSchema, updateClusterSchema, deleteClusterSchema } from '@dso-console/shared' +import { FromSchema } from 'json-schema-to-ts' +import '@/types/index.js' - const environments = await getClusterAssociatedEnvironments(clusterId) - - addReqLogs({ - req, - description: 'Environnements associés au cluster récupérés', - extras: { - clusterId, +const router = async (app: FastifyInstance, _opt) => { + // Récupérer les environnements associés au cluster + app.get<{ + Params: FromSchema, + }>('/:clusterId/environments', + { + schema: getClusterAssociatedEnvironmentsSchema, }, - }) + async (req, res) => { + const clusterId = req.params.clusterId + const environments = await getClusterAssociatedEnvironments(clusterId) - sendOk(res, environments) -} + addReqLogs({ + req, + description: 'Environnements associés au cluster récupérés', + extras: { + clusterId, + }, + }) -// POST -export const createClusterController: RouteHandler = async (req: FastifyRequestWithSession<{ - Body: CreateClusterDto -}>, res) => { - const data = req.body - const userId = req.session?.user?.id + sendOk(res, environments) + }) - data.projectIds = checkClusterProjectIds(data) + // Déclarer un nouveau cluster + app.post<{ + Body: FromSchema + }>('/', + { + schema: createClusterSchema, + }, + async (req, res) => { + const data = req.body + const userId = req.session.data.user.id - const cluster = await createCluster(data, userId) + data.projectIds = checkClusterProjectIds(data) - addReqLogs({ - req, - description: 'Cluster créé avec succès', - extras: { - clusterId: cluster.id, - }, - }) - sendCreated(res, cluster) -} + const cluster = await createCluster(data, userId) -// PUT -export const updateClusterController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: ClusterParams - Body: UpdateClusterDto -}>, res) => { - const data = req.body - const clusterId = req.params?.clusterId + addReqLogs({ + req, + description: 'Cluster créé avec succès', + extras: { + clusterId: cluster.id, + }, + }) + sendCreated(res, cluster) + }) - const cluster = await updateCluster(data, clusterId) + // Mettre à jour un cluster + app.put<{ + Params: FromSchema, + Body: FromSchema, +}>('/:clusterId', + { + schema: updateClusterSchema, + }, + async (req, res) => { + const data = req.body + const clusterId = req.params.clusterId - addReqLogs({ - req, - description: 'Cluster mis à jour avec succès', - extras: { - clusterId: cluster.id, - }, + const cluster = await updateCluster(data, clusterId) + + addReqLogs({ + req, + description: 'Cluster mis à jour avec succès', + extras: { + clusterId: cluster.id, + }, + }) + sendOk(res, cluster) }) - sendOk(res, cluster) -} -// DELETE -export const deleteClusterController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: ClusterParams -}>, res) => { - const clusterId = req.params?.clusterId - const userId = req.session.user?.id + // DELETE + // Supprimer un cluster + app.delete<{ + Params: FromSchema + }>('/:clusterId', + { + schema: deleteClusterSchema, + }, + async (req, res) => { + const clusterId = req.params.clusterId + const userId = req.session.data.user.id - await deleteCluster(clusterId, userId) + await deleteCluster(clusterId, userId) - addReqLogs({ - req, - description: 'Cluster supprimé avec succès', - extras: { - clusterId, - }, - }) - sendNoContent(res) + addReqLogs({ + req, + description: 'Cluster supprimé avec succès', + extras: { + clusterId, + }, + }) + sendNoContent(res) + }) } + +export default router diff --git a/apps/server/src/resources/cluster/controllers.ts b/apps/server/src/resources/cluster/controllers.ts index 0467d1e7b..9f6b2a534 100644 --- a/apps/server/src/resources/cluster/controllers.ts +++ b/apps/server/src/resources/cluster/controllers.ts @@ -1,17 +1,26 @@ import { addReqLogs } from '@/utils/logger.js' import { getAllCleanedClusters } from './business.js' import { sendOk } from '@/utils/response.js' -import { type RouteHandler } from 'fastify' -import { type FastifyRequestWithSession } from '@/types/index.js' +import type { FastifyInstance } from 'fastify' -// GET -export const getClustersController: RouteHandler = async (req: FastifyRequestWithSession, res) => { - const user = req.session?.user - const cleanedClusters = await getAllCleanedClusters(user) +import { getClustersSchema } from '@dso-console/shared' - addReqLogs({ - req, - description: 'Clusters récupérés avec succès', - }) - sendOk(res, cleanedClusters) +const router = async (app: FastifyInstance, _opt) => { + // Récupérer les quotas disponibles + app.get('/', + { + schema: getClustersSchema, + }, + async (req, res) => { + const user = req.session.data.user + const cleanedClusters = await getAllCleanedClusters(user) + + addReqLogs({ + req, + description: 'Clusters récupérés avec succès', + }) + sendOk(res, cleanedClusters) + }) } + +export default router diff --git a/apps/server/src/resources/environment/business.ts b/apps/server/src/resources/environment/business.ts index 64a3b0525..56380d57d 100644 --- a/apps/server/src/resources/environment/business.ts +++ b/apps/server/src/resources/environment/business.ts @@ -31,7 +31,7 @@ import { projectRootDir } from '@/utils/env.js' import { getProjectInfosAndClusters } from '@/resources/project/business.js' import { gitlabUrl } from '@/plugins/core/gitlab/utils.js' import { type AsyncReturnType, adminGroupPath } from '@dso-console/shared' -import { KeycloakSession } from '@/types/index.js' +import type { SessionData } from '@mgcrea/fastify-session' // Fetch infos export const getEnvironmentInfosAndClusters = async (environmentId: string) => { @@ -230,7 +230,7 @@ export const createEnvironment = async ( } type UpdateEnvironmentParam = { - user: KeycloakSession['session']['user'], + user: SessionData['user'], projectId: Project['id'], environmentId: Environment['id'], quotaStageId?: QuotaStage['id'], diff --git a/apps/server/src/routes/project-environment.spec.ts b/apps/server/src/resources/environment/controllers.spec.ts similarity index 98% rename from apps/server/src/routes/project-environment.spec.ts rename to apps/server/src/resources/environment/controllers.spec.ts index 1301f4e77..7fa146dfa 100644 --- a/apps/server/src/routes/project-environment.spec.ts +++ b/apps/server/src/resources/environment/controllers.spec.ts @@ -1,8 +1,8 @@ -import prisma from '../__mocks__/prisma.js' -import app, { getRequestor, setRequestor } from '../__mocks__/app.js' +import prisma from '../../__mocks__/prisma.js' +import app, { getRequestor, setRequestor } from '../../__mocks__/app.js' import { vi, describe, it, expect, beforeAll, afterEach, afterAll } from 'vitest' import { createRandomDbSetup, getRandomEnv, getRandomUser, getRandomRole, getRandomPerm, getRandomLog } from '@dso-console/test-utils' -import { getConnection, closeConnections } from '../connect.js' +import { getConnection, closeConnections } from '../../connect.js' import { projectIsLockedInfo } from '@dso-console/shared' describe('User routes', () => { diff --git a/apps/server/src/resources/environment/controllers.ts b/apps/server/src/resources/environment/controllers.ts index cee1348e6..05c1eb145 100644 --- a/apps/server/src/resources/environment/controllers.ts +++ b/apps/server/src/resources/environment/controllers.ts @@ -4,13 +4,9 @@ import { sendCreated, sendNoContent, } from '@/utils/response.js' -import type { - InitializeEnvironmentDto, - UpdateEnvironmentDto, - EnvironmentParams, - InitializeEnvironmentParams, +import { + getEnvironmentByIdSchema, initializeEnvironmentSchema, updateEnvironmentSchema, deleteEnvironmentSchema, } from '@dso-console/shared' -import { type FastifyRequestWithSession } from '@/types/index.js' import { getEnvironmentInfos, createEnvironment, @@ -18,116 +14,141 @@ import { deleteEnvironment, checkGetEnvironment, } from './business.js' -import { type RouteHandler } from 'fastify' - -// GET -// TODO #541 : ce controller n'est pas utilisé -export const getEnvironmentByIdController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: EnvironmentParams, -}>, res) => { - const environmentId = req.params?.environmentId - const userId = req.session?.user?.id - const projectId = req.params?.projectId - - // appel business 1 : récup données - const env = await getEnvironmentInfos(environmentId) - - // appel business 2 : check pré-requis - checkGetEnvironment(env, userId) - - // Nettoyage des clés - delete env.project.roles - - addReqLogs({ - req, - description: 'Environnement récupéré avec succès', - extras: { - environmentId, - projectId, - }, - }) - sendOk(res, env) -} +import type { FastifyInstance } from 'fastify' -// POST -export const initializeEnvironmentController: RouteHandler = async (req: FastifyRequestWithSession<{ - Body: InitializeEnvironmentDto, - Params: InitializeEnvironmentParams, -}>, res) => { - const data = req.body - const userId = req.session?.user?.id - const projectId = req.params?.projectId - - const environment = await createEnvironment({ - userId, - projectId, - name: data.name, - clusterId: data.clusterId, - quotaStageId: data.quotaStageId, - }) +import { FromSchema } from 'json-schema-to-ts' - addReqLogs({ - req, - description: 'Environnement et permissions créés avec succès', - extras: { - environmentId: environment.id, - projectId, +// DELETE +const router = async (app: FastifyInstance, _opt) => { + // Récupérer un environnement par son id + // TODO #541 : ce controller n'est pas utilisé + app.get<{ + Params: FromSchema, + }>('/:projectId/environments/:environmentId', + { + schema: getEnvironmentByIdSchema, }, + async (req, res) => { + const environmentId = req.params.environmentId + const userId = req.session.data.user.id + const projectId = req.params.projectId + + // appel business 1 : récup données + const env = await getEnvironmentInfos(environmentId) + + // appel business 2 : check pré-requis + checkGetEnvironment(env, userId) + + // Nettoyage des clés + delete env.project.roles + + addReqLogs({ + req, + description: 'Environnement récupéré avec succès', + extras: { + environmentId, + projectId, + }, + }) + sendOk(res, env) + }) + + // Créer un environnement + app.post<{ + Body: FromSchema, + Params: FromSchema, +}>('/:projectId/environments', + { + schema: initializeEnvironmentSchema, + }, + async (req, res) => { + const data = req.body + const userId = req.session.data.user.id + const projectId = req.params.projectId + + const environment = await createEnvironment({ + userId, + projectId, + name: data.name, + clusterId: data.clusterId, + quotaStageId: data.quotaStageId, + }) + + addReqLogs({ + req, + description: 'Environnement et permissions créés avec succès', + extras: { + environmentId: environment.id, + projectId, + }, + }) + + sendCreated(res, environment) }) - sendCreated(res, environment) -} - -export const updateEnvironmentController: RouteHandler = async (req: FastifyRequestWithSession<{ - Body: UpdateEnvironmentDto, - Params: EnvironmentParams, -}>, res) => { - const data = req.body - const user = req.session?.user - const { projectId, environmentId } = req.params - - const environment = await updateEnvironment({ - user, - projectId, - environmentId, - quotaStageId: data.quotaStageId, - clusterId: data.clusterId, - }) - - addReqLogs({ - req, - description: 'Environnement mis à jour avec succès', - extras: { - environmentId, - projectId: environment.projectId, + // Mettre à jour un environnement + app.put<{ + Body: FromSchema, + Params: FromSchema, + }>('/:projectId/environments/:environmentId', + { + schema: updateEnvironmentSchema, }, - }) - - sendOk(res, environment) -} - -// DELETE -export const deleteEnvironmentController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: EnvironmentParams, -}>, res) => { - const environmentId = req.params?.environmentId - const projectId = req.params?.projectId - const userId = req.session?.user?.id - - await deleteEnvironment({ - userId, - projectId, - environmentId, - }) - - addReqLogs({ - req, - description: 'Environnement supprimé avec succès', - extras: { - environmentId, - projectId, + async (req, res) => { + const data = req.body + const user = req.session.data.user + const { projectId, environmentId } = req.params + + const environment = await updateEnvironment({ + user, + projectId, + environmentId, + quotaStageId: data.quotaStageId, + clusterId: data.clusterId, + }) + + addReqLogs({ + req, + description: 'Environnement mis à jour avec succès', + extras: { + environmentId, + projectId: environment.projectId, + }, + }) + + sendOk(res, environment) + }) + + // Supprimer un environnement + app.delete<{ + Params: FromSchema, + }>('/:projectId/environments/:environmentId', + { + schema: deleteEnvironmentSchema, }, - }) - - sendNoContent(res) + async (req, res) => { + const environmentId = req.params.environmentId + const projectId = req.params.projectId + const userId = req.session.data.user.id + + await deleteEnvironment({ + userId, + projectId, + environmentId, + }) + + addReqLogs({ + req, + description: 'Environnement supprimé avec succès', + extras: { + environmentId, + projectId, + }, + }) + + sendNoContent(res) + }, + ) } + +export default router diff --git a/apps/server/src/routes/admin/index.ts b/apps/server/src/resources/index-admin.ts similarity index 68% rename from apps/server/src/routes/admin/index.ts rename to apps/server/src/resources/index-admin.ts index 3827a5b74..cf12e469d 100644 --- a/apps/server/src/routes/admin/index.ts +++ b/apps/server/src/resources/index-admin.ts @@ -1,11 +1,11 @@ -import userRouter from './user.js' -import organizationRouter from './organization.js' -import projectRouter from './project.js' -import logRouter from './log.js' -import dbRouter from './db.js' -import clusterRouter from './cluster.js' -import quotaRouter from './quota.js' -import stageRouter from './stage.js' +import clusterRouter from './cluster/admin/controllers.js' +import dbRouter from './system/db/controllers.js' +import logRouter from './log/admin/controllers.js' +import organizationRouter from './organization/admin/controllers.js' +import projectRouter from './project/admin/controllers.js' +import quotaRouter from './quota/admin/controllers.js' +import stageRouter from './stage/admin/controllers.js' +import userRouter from './user/admin/controllers.js' import { checkAdminGroup } from '@/utils/controller.js' import { type FastifyInstance } from 'fastify' diff --git a/apps/server/src/routes/index.ts b/apps/server/src/resources/index.ts similarity index 68% rename from apps/server/src/routes/index.ts rename to apps/server/src/resources/index.ts index 27bf39c7c..2a723c605 100644 --- a/apps/server/src/routes/index.ts +++ b/apps/server/src/resources/index.ts @@ -1,12 +1,12 @@ -import ciFilesRouter from './ci-files.js' -import projectOrganizationRouter from './organization.js' -import projectRouter from './project.js' -import serviceRouter from './service.js' -import projectQuotaRouter from './quota.js' -import projectStageRouter from './stage.js' -import projectClusterRouter from './cluster.js' +import ciFilesRouter from '../generate-files/controllers.js' +import projectOrganizationRouter from './organization/controllers.js' +import projectRouter from './project/controllers.js' +import serviceRouter from './service/controllers.js' +import projectQuotaRouter from './quota/controllers.js' +import projectStageRouter from './stage/controllers.js' +import projectClusterRouter from './cluster/controllers.js' import { sendOk } from '../utils/response.js' -import adminRouter from './admin/index.js' +import adminRouter from './index-admin.js' import type { FastifyInstance } from 'fastify' const version = process.env.APP_VERSION || 'dev' diff --git a/apps/server/src/routes/admin/log.spec.ts b/apps/server/src/resources/log/admin/controllers.spec.ts similarity index 91% rename from apps/server/src/routes/admin/log.spec.ts rename to apps/server/src/resources/log/admin/controllers.spec.ts index 568436433..be9964b16 100644 --- a/apps/server/src/routes/admin/log.spec.ts +++ b/apps/server/src/resources/log/admin/controllers.spec.ts @@ -1,7 +1,7 @@ -import prisma from '../../__mocks__/prisma.js' -import app, { setRequestor } from '../../__mocks__/app.js' +import prisma from '../../../__mocks__/prisma.js' +import app, { setRequestor } from '../../../__mocks__/app.js' import { vi, describe, it, expect, beforeAll, afterEach, afterAll } from 'vitest' -import { getConnection, closeConnections } from '@/connect.js' +import { getConnection, closeConnections } from '../../../connect.js' import { adminGroupPath } from '@dso-console/shared' import { getRandomLog, getRandomUser, repeatFn } from '@dso-console/test-utils' diff --git a/apps/server/src/resources/log/admin/controllers.ts b/apps/server/src/resources/log/admin/controllers.ts index 3933ea684..363932c7a 100644 --- a/apps/server/src/resources/log/admin/controllers.ts +++ b/apps/server/src/resources/log/admin/controllers.ts @@ -1,19 +1,23 @@ import { sendOk } from '@/utils/response.js' import { addReqLogs } from '@/utils/logger.js' -import type { FastifyRequestWithSession } from '@/types/index.js' import type { AdminLogsQuery } from '@dso-console/shared' -import type { RouteHandler } from 'fastify' +import type { FastifyRequest, FastifyInstance } from 'fastify' import { getAllLogs } from './business.js' -export const getAllLogsController: RouteHandler = async (req: FastifyRequestWithSession<{ +const router = async (app: FastifyInstance, _opt) => { + // Récupérer des logs + app.get('/', async (req: FastifyRequest<{ Querystring: AdminLogsQuery }>, res) => { - const { offset, limit } = req.query - const [total, logs] = await getAllLogs(offset, limit) + const { offset, limit } = req.query + const [total, logs] = await getAllLogs(offset, limit) - addReqLogs({ - req, - description: 'Logs récupérés avec succès', + addReqLogs({ + req, + description: 'Logs récupérés avec succès', + }) + sendOk(res, { total, logs }) }) - sendOk(res, { total, logs }) } + +export default router diff --git a/apps/server/src/routes/admin/organization.spec.ts b/apps/server/src/resources/organization/admin/controllers.spec.ts similarity index 96% rename from apps/server/src/routes/admin/organization.spec.ts rename to apps/server/src/resources/organization/admin/controllers.spec.ts index dd424aea5..d67b1ca11 100644 --- a/apps/server/src/routes/admin/organization.spec.ts +++ b/apps/server/src/resources/organization/admin/controllers.spec.ts @@ -1,10 +1,10 @@ -import prisma from '../../__mocks__/prisma.js' -import app, { setRequestor } from '../../__mocks__/app.js' +import prisma from '../../../__mocks__/prisma.js' +import app, { setRequestor } from '../../../__mocks__/app.js' import { vi, describe, it, expect, beforeAll, afterEach, afterAll, beforeEach } from 'vitest' import { getRandomOrganization, getRandomProject, getRandomUser } from '@dso-console/test-utils' -import { getConnection, closeConnections } from '@/connect.js' +import { getConnection, closeConnections } from '../../../connect.js' import { adminGroupPath, allOrganizations } from '@dso-console/shared' -import { filteredOrganizations } from '@/utils/mock-plugins.js' +import { filteredOrganizations } from '../../../utils/mock-plugins.js' describe('Organizations routes', () => { beforeAll(async () => { diff --git a/apps/server/src/resources/organization/admin/controllers.ts b/apps/server/src/resources/organization/admin/controllers.ts index a33fe60af..710354338 100644 --- a/apps/server/src/resources/organization/admin/controllers.ts +++ b/apps/server/src/resources/organization/admin/controllers.ts @@ -1,65 +1,88 @@ import { addReqLogs } from '@/utils/logger.js' import { sendOk, sendCreated } from '@/utils/response.js' import { createOrganization, fetchOrganizations, getAllOrganization, updateOrganization } from './business.js' -import { type FastifyRequestWithSession } from '@/types/index.js' -import { type CreateOrganizationDto, type UpdateOrganizationDto, type OrganizationParams } from '@dso-console/shared' -import { type RouteHandler } from 'fastify' +import type { CreateOrganizationDto, UpdateOrganizationDto, OrganizationParams } from '@dso-console/shared' +import type { FastifyRequest, FastifyInstance } from 'fastify' -// GET -export const getAllOrganizationsController: RouteHandler = async (req: FastifyRequestWithSession, res) => { - const organizations = await getAllOrganization() - addReqLogs({ - req, - description: 'Organisations récupérées avec succès', - }) - sendOk(res, organizations) -} +import { getAllOrganizationsSchema, createOrganizationSchema, fetchOrganizationsSchema, updateOrganizationSchema } from '@dso-console/shared' + +const router = async (app: FastifyInstance, _opt) => { + // Récupérer toutes les organisations + app.get('/', + { + schema: getAllOrganizationsSchema, + }, + async (req: FastifyRequest, res) => { + const organizations = await getAllOrganization() + addReqLogs({ + req, + description: 'Organisations récupérées avec succès', + }) + sendOk(res, organizations) + }) -// POST -export const createOrganizationController: RouteHandler = async (req: FastifyRequestWithSession<{ + // Créer une organisation + app.post('/', + { + schema: createOrganizationSchema, + }, + async (req: FastifyRequest<{ Body: CreateOrganizationDto }>, res) => { - const data = req.body - const organization = await createOrganization(data) + const data = req.body + const organization = await createOrganization(data) - addReqLogs({ - req, - description: 'Organisation créée avec succès', - extras: { - organizationId: organization.id, + addReqLogs({ + req, + description: 'Organisation créée avec succès', + extras: { + organizationId: organization.id, + }, + }) + sendCreated(res, organization) + }) + + // Synchroniser les organisations via les plugins externes + app.put('/sync', + { + schema: fetchOrganizationsSchema, }, - }) - sendCreated(res, organization) -} + async (req: FastifyRequest, res) => { + const userId = req.session.data.user.id -// PUT -export const updateOrganizationController: RouteHandler = async (req: FastifyRequestWithSession<{ - Body: UpdateOrganizationDto - Params: OrganizationParams -}>, res) => { - const name = req.params?.orgName - const { active, label, source } = req.body + const consoleOrganizations = await fetchOrganizations(userId) - const organization = await updateOrganization(name, active, label, source) + addReqLogs({ + req, + description: 'Organisations synchronisées avec succès', + }) + sendCreated(res, consoleOrganizations) + }) - addReqLogs({ - req, - description: 'Organisation mise à jour avec succès', - extras: { - organizationId: organization.id, + // Mettre à jour une organisation + app.put('/:orgName', + { + schema: updateOrganizationSchema, }, - }) - sendCreated(res, organization) -} -export const fetchOrganizationsController: RouteHandler = async (req: FastifyRequestWithSession, res) => { - const userId = req.session.user.id + async (req: FastifyRequest<{ + Body: UpdateOrganizationDto + Params: OrganizationParams +}>, res) => { + const name = req.params.orgName + const { active, label, source } = req.body - const consoleOrganizations = await fetchOrganizations(userId) + const organization = await updateOrganization(name, active, label, source) - addReqLogs({ - req, - description: 'Organisations synchronisées avec succès', - }) - sendCreated(res, consoleOrganizations) + addReqLogs({ + req, + description: 'Organisation mise à jour avec succès', + extras: { + organizationId: organization.id, + }, + }) + sendCreated(res, organization) + }) } + +export default router diff --git a/apps/server/src/resources/organization/business.ts b/apps/server/src/resources/organization/business.ts index 5169113f8..d53e8984d 100644 --- a/apps/server/src/resources/organization/business.ts +++ b/apps/server/src/resources/organization/business.ts @@ -1,7 +1,7 @@ import { getOrCreateUser, getActiveOrganizationsQuery, getOrganizationById } from '@/resources/queries-index.js' import { NotFoundError, UnauthorizedError } from '@/utils/errors.js' -import { type UserDto } from '../user/business.js' import { userSchema } from '@dso-console/shared' +import { SessionData } from '@mgcrea/fastify-session' // TODO 539 : à supprimer ? n'est pas utilisé export const getOrganizationInfos = async (organizationId: string) => { @@ -10,7 +10,7 @@ export const getOrganizationInfos = async (organizationId: string) => { return organization } -export const getActiveOrganizations = async (requestor: UserDto) => { +export const getActiveOrganizations = async (requestor: SessionData['user']) => { await userSchema.validateAsync(requestor) const user = await getOrCreateUser(requestor) if (!user) throw new UnauthorizedError('Veuillez vous connecter') diff --git a/apps/server/src/resources/organization/controllers.ts b/apps/server/src/resources/organization/controllers.ts index 2126426d2..dade264d8 100644 --- a/apps/server/src/resources/organization/controllers.ts +++ b/apps/server/src/resources/organization/controllers.ts @@ -3,18 +3,26 @@ import { sendOk } from '@/utils/response.js' import { getActiveOrganizations, } from './business.js' -import { type FastifyRequestWithSession } from '@/types/index.js' -import { type RouteHandler } from 'fastify' +import type { FastifyInstance } from 'fastify' -// GET -export const getActiveOrganizationsController: RouteHandler = async (req: FastifyRequestWithSession, res) => { - const requestor = req.session?.user - delete requestor.groups +import { getActiveOrganizationsSchema } from '@dso-console/shared' - const organizations = await getActiveOrganizations(requestor) - addReqLogs({ - req, - description: 'Organisations récupérées avec succès', - }) - sendOk(res, organizations) +const router = async (app: FastifyInstance, _opt) => { + app.get('/', + { + schema: getActiveOrganizationsSchema, + }, + async (req, res) => { + const requestor = req.session.data.user + delete requestor.groups + + const organizations = await getActiveOrganizations(requestor) + addReqLogs({ + req, + description: 'Organisations récupérées avec succès', + }) + sendOk(res, organizations) + }) } + +export default router diff --git a/apps/server/src/routes/organization.spec.ts b/apps/server/src/resources/organization/organization.spec.ts similarity index 90% rename from apps/server/src/routes/organization.spec.ts rename to apps/server/src/resources/organization/organization.spec.ts index 51d416587..1c12296a6 100644 --- a/apps/server/src/routes/organization.spec.ts +++ b/apps/server/src/resources/organization/organization.spec.ts @@ -1,8 +1,8 @@ -import prisma from '../__mocks__/prisma.js' -import app, { getRequestor, setRequestor } from '../__mocks__/app.js' +import prisma from '../../__mocks__/prisma.js' +import app, { getRequestor, setRequestor } from '../../__mocks__/app.js' import { vi, describe, it, expect, beforeAll, afterEach, afterAll } from 'vitest' import { getRandomOrganization, getRandomUser } from '@dso-console/test-utils' -import { getConnection, closeConnections } from '../connect.js' +import { getConnection, closeConnections } from '../../connect.js' describe('Organizations routes', () => { beforeAll(async () => { diff --git a/apps/server/src/resources/organization/organization.ts b/apps/server/src/resources/organization/organization.ts new file mode 100644 index 000000000..e69de29bb diff --git a/apps/server/src/routes/project-permission.spec.ts b/apps/server/src/resources/permission/controllers.spec.ts similarity index 98% rename from apps/server/src/routes/project-permission.spec.ts rename to apps/server/src/resources/permission/controllers.spec.ts index bb488b698..565c4c564 100644 --- a/apps/server/src/routes/project-permission.spec.ts +++ b/apps/server/src/resources/permission/controllers.spec.ts @@ -1,8 +1,8 @@ -import prisma from '../__mocks__/prisma.js' -import app, { getRequestor, setRequestor } from '../__mocks__/app.js' +import prisma from '../../__mocks__/prisma.js' +import app, { getRequestor, setRequestor } from '../../__mocks__/app.js' import { vi, describe, it, expect, beforeAll, afterEach, afterAll } from 'vitest' import { createRandomDbSetup, getRandomPerm, getRandomRole, getRandomUser } from '@dso-console/test-utils' -import { getConnection, closeConnections } from '../connect.js' +import { getConnection, closeConnections } from '../../connect.js' describe('Permission routes', () => { const requestor = getRandomUser() diff --git a/apps/server/src/resources/permission/controllers.ts b/apps/server/src/resources/permission/controllers.ts index e6fbacc67..6db1b5bf1 100644 --- a/apps/server/src/resources/permission/controllers.ts +++ b/apps/server/src/resources/permission/controllers.ts @@ -1,97 +1,118 @@ import { addReqLogs } from '@/utils/logger.js' import { sendOk, sendCreated } from '@/utils/response.js' import { deletePermission, getEnvironmentPermissions, setPermission, updatePermission } from './business.js' -import { type RouteHandler } from 'fastify' -import { type FastifyRequestWithSession } from '@/types/index.js' -import type { DeletePermissionParams, PermissionParams, UpdatePermissionDto } from '@dso-console/shared' +import type { FastifyInstance } from 'fastify' -// GET -export const getEnvironmentPermissionsController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: PermissionParams -}>, res) => { - const userId = req.session?.user?.id - const environmentId = req.params?.environmentId - const projectId = req.params?.projectId +import { deletePermissionSchema, getEnvironmentPermissionsSchema, setPermissionSchema, updatePermissionSchema } from '@dso-console/shared' +import { FromSchema } from 'json-schema-to-ts' - const permissions = await getEnvironmentPermissions(userId, projectId, environmentId) - - addReqLogs({ - req, - description: 'Permissions de l\'environnement récupérées avec succès', - extras: { - projectId, - environmentId, +const router = async (app: FastifyInstance, _opt) => { + // Récupérer les permissions d'un environnement + app.get<{ + Params: FromSchema + }>('/:projectId/environments/:environmentId/permissions', + { + schema: getEnvironmentPermissionsSchema, }, - }) - sendOk(res, permissions) -} + async (req, res) => { + const userId = req.session.data.user.id + const environmentId = req.params.environmentId + const projectId = req.params.projectId -// POST -export const setPermissionController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: PermissionParams - Body: UpdatePermissionDto -}>, res) => { - const requestorId = req.session?.user?.id - const environmentId = req.params?.environmentId - const projectId = req.params?.projectId - const data = req.body + const permissions = await getEnvironmentPermissions(userId, projectId, environmentId) - const permission = await setPermission(projectId, requestorId, data.userId, environmentId, data.level) + addReqLogs({ + req, + description: 'Permissions de l\'environnement récupérées avec succès', + extras: { + projectId, + environmentId, + }, + }) + sendOk(res, permissions) + }) - addReqLogs({ - req, - description: 'Permission créée avec succès', - extras: { - permissionId: permission.id, - projectId, - environmentId, + // Créer une permission + app.post<{ + Params: FromSchema + Body: FromSchema + }>('/:projectId/environments/:environmentId/permissions', + { + schema: setPermissionSchema, }, - }) - sendCreated(res, permission) -} + async (req, res) => { + const requestorId = req.session.data.user?.id + const environmentId = req.params.environmentId + const projectId = req.params.projectId + const data = req.body -// PUT -export const updatePermissionController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: PermissionParams - Body: UpdatePermissionDto -}>, res) => { - const requestorId = req.session?.user?.id - const environmentId = req.params?.environmentId - const projectId = req.params?.projectId - const data = req.body + const permission = await setPermission(projectId, requestorId, data.userId, environmentId, data.level) - const permission = await updatePermission(projectId, requestorId, data.userId, environmentId, data.level) + addReqLogs({ + req, + description: 'Permission créée avec succès', + extras: { + permissionId: permission.id, + projectId, + environmentId, + }, + }) + sendCreated(res, permission) + }) - addReqLogs({ - req, - description: 'Permission mise à jour avec succès', - extras: { - permissionId: permission.id, - projectId, - environmentId, + // Mettre à jour le level d'une permission + app.put<{ + Params: FromSchema + Body: FromSchema + }>('/:projectId/environments/:environmentId/permissions', + { + schema: updatePermissionSchema, }, - }) - sendOk(res, permission) -} + async (req, res) => { + const requestorId = req.session.data.user.id + const environmentId = req.params.environmentId + const projectId = req.params.projectId + const data = req.body -// DELETE -export const deletePermissionController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: DeletePermissionParams -}>, res) => { - const requestorId = req.session?.user?.id - const environmentId = req.params?.environmentId - const projectId = req.params?.projectId - const userId = req.params?.userId + const permission = await updatePermission(projectId, requestorId, data.userId, environmentId, data.level) - const permission = await deletePermission(userId, environmentId, requestorId) + addReqLogs({ + req, + description: 'Permission mise à jour avec succès', + extras: { + permissionId: permission.id, + projectId, + environmentId, + }, + }) + sendOk(res, permission) + }) - addReqLogs({ - req, - description: 'Permissions supprimée avec succès', - extras: { - projectId, - environmentId, + // Supprimer une permission + app.delete<{ + Params: FromSchema + }>('/:projectId/environments/:environmentId/permissions/:userId', + { + schema: deletePermissionSchema, }, - }) - sendOk(res, permission) + async (req, res) => { + const requestorId = req.session.data.user.id + const environmentId = req.params.environmentId + const projectId = req.params.projectId + const userId = req.params.userId + + const permission = await deletePermission(userId, environmentId, requestorId) + + addReqLogs({ + req, + description: 'Permissions supprimée avec succès', + extras: { + projectId, + environmentId, + }, + }) + sendOk(res, permission) + }) } + +export default router diff --git a/apps/server/src/routes/admin/project.spec.ts b/apps/server/src/resources/project/admin/controllers.spec.ts similarity index 94% rename from apps/server/src/routes/admin/project.spec.ts rename to apps/server/src/resources/project/admin/controllers.spec.ts index f4c09bd98..33129db59 100644 --- a/apps/server/src/routes/admin/project.spec.ts +++ b/apps/server/src/resources/project/admin/controllers.spec.ts @@ -1,7 +1,7 @@ -import prisma from '../../__mocks__/prisma.js' -import app, { setRequestor } from '../../__mocks__/app.js' +import prisma from '../../../__mocks__/prisma.js' +import app, { setRequestor } from '../../../__mocks__/app.js' import { vi, describe, it, expect, beforeAll, afterEach, afterAll, beforeEach } from 'vitest' -import { getConnection, closeConnections } from '../../connect.js' +import { getConnection, closeConnections } from '../../../connect.js' import { adminGroupPath } from '@dso-console/shared' import { getRandomProject, getRandomUser, repeatFn } from '@dso-console/test-utils' diff --git a/apps/server/src/resources/project/admin/controllers.ts b/apps/server/src/resources/project/admin/controllers.ts index e0ede6e1b..e76c936c3 100644 --- a/apps/server/src/resources/project/admin/controllers.ts +++ b/apps/server/src/resources/project/admin/controllers.ts @@ -1,30 +1,47 @@ import { addReqLogs } from '@/utils/logger.js' -import { type RouteHandler } from 'fastify' -import { type FastifyRequestWithSession } from '@/types/index.js' +import { FastifyRequest, type FastifyInstance } from 'fastify' import { sendNoContent, sendOk } from '@/utils/response.js' import { getAllProjects, handleProjectLocking } from './business.js' -// GET -export const getAllProjectsController: RouteHandler = async (req: FastifyRequestWithSession, res) => { - const allProjects = await getAllProjects() +import { getAllProjectsSchema, patchProjectSchema } from '@dso-console/shared' +import { FromSchema } from 'json-schema-to-ts' - addReqLogs({ - req, - description: 'Ensemble des projets récupérés avec succès', - }) - return sendOk(res, allProjects) -} +const router = async (app: FastifyInstance, _opt) => { + // Récupérer tous les projets + app.get('/', + { + schema: getAllProjectsSchema, + }, + async (req: FastifyRequest, res) => { + const allProjects = await getAllProjects() + + addReqLogs({ + req, + description: 'Ensemble des projets récupérés avec succès', + }) + return sendOk(res, allProjects) + }) -// PATCH -export const handleProjectLockingController = async (req, res) => { - const projectId = req.params.projectId - const lock = req.body.lock + // (Dé)verrouiller un projet + app.patch<{ + Params: FromSchema + Body: FromSchema + }>('/:projectId', + { + schema: patchProjectSchema, + }, + async (req, res) => { + const projectId = req.params.projectId + const lock = req.body.lock - await handleProjectLocking(projectId, lock) + await handleProjectLocking(projectId, lock) - addReqLogs({ - req, - description: `Projet ${lock ? 'verrouillé' : 'déverrouillé'} avec succès`, - }) - return sendNoContent(res) + addReqLogs({ + req, + description: `Projet ${lock ? 'verrouillé' : 'déverrouillé'} avec succès`, + }) + return sendNoContent(res) + }) } + +export default router diff --git a/apps/server/src/routes/project.spec.ts b/apps/server/src/resources/project/controllers.spec.ts similarity index 98% rename from apps/server/src/routes/project.spec.ts rename to apps/server/src/resources/project/controllers.spec.ts index b58dc45c0..d0bbaef56 100644 --- a/apps/server/src/routes/project.spec.ts +++ b/apps/server/src/resources/project/controllers.spec.ts @@ -1,9 +1,9 @@ -import prisma from '../__mocks__/prisma.js' -import app, { getRequestor, setRequestor } from '../__mocks__/app.js' +import prisma from '../../__mocks__/prisma.js' +import app, { getRequestor, setRequestor } from '../../__mocks__/app.js' import { vi, describe, it, expect, beforeAll, afterEach, afterAll } from 'vitest' import { createRandomDbSetup, getRandomCluster, getRandomProject, getRandomRole, getRandomUser } from '@dso-console/test-utils' import { faker } from '@faker-js/faker' -import { getConnection, closeConnections } from '../connect.js' +import { getConnection, closeConnections } from '../../connect.js' import { descriptionMaxLength, exclude, projectIsLockedInfo } from '@dso-console/shared' describe('Project routes', () => { diff --git a/apps/server/src/resources/project/controllers.ts b/apps/server/src/resources/project/controllers.ts index afc225238..92066fc22 100644 --- a/apps/server/src/resources/project/controllers.ts +++ b/apps/server/src/resources/project/controllers.ts @@ -1,17 +1,11 @@ -import type { RouteHandler } from 'fastify' - +import type { FastifyInstance } from 'fastify' import { addReqLogs } from '@/utils/logger.js' import { sendOk, sendCreated, sendNoContent, } from '@/utils/response.js' -import type { - CreateProjectDto, - UpdateProjectDto, - ProjectParams, -} from '@dso-console/shared' -import type { FastifyRequestWithSession } from '@/types/index.js' +import type { ProjectParams } from '@dso-console/shared' import { getUserProjects, getProject, @@ -20,115 +14,174 @@ import { archiveProject, getProjectSecrets, } from './business.js' - -// GET -export const getUserProjectsController: RouteHandler = async (req: FastifyRequestWithSession, res) => { - const requestor = req.session?.user - delete requestor.groups - - const projectsInfos = await getUserProjects(requestor) - - addReqLogs({ - req, - description: 'Projets de l\'utilisateur récupérés avec succès', - extras: { - userId: requestor.id, +import projectEnvironmentRouter from '../environment/controllers.js' +import projectRepositoryRouter from '../repository/controllers.js' +import projectUserRouter from '../user/controllers.js' +import projectPermissionRouter from '../permission/controllers.js' +import { + getProjectByIdSchema, + getUserProjectsSchema, + createProjectSchema, + updateProjectSchema, + archiveProjectSchema, + // getProjectSecretsSchema, +} from '@dso-console/shared' +import { FromSchema } from 'json-schema-to-ts' + +const router = async (app: FastifyInstance, _opt) => { + // Récupérer tous les projets d'un user + app.get( + '/', + { + schema: getUserProjectsSchema, }, - }) - sendOk(res, projectsInfos) -} - -export const getProjectByIdController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: ProjectParams, -}>, res) => { - const projectId = req.params?.projectId - const userId = req.session?.user?.id - - const project = await getProject(projectId, userId) - - addReqLogs({ - req, - description: 'Projet de l\'utilisateur récupéré avec succès', - extras: { - projectId, - userId, + async (req, res) => { + const requestor = req.session.data.user + delete requestor.groups + + const projectsInfos = await getUserProjects(requestor) + + addReqLogs({ + req, + description: 'Projets de l\'utilisateur récupérés avec succès', + extras: { + userId: requestor.id, + }, + }) + sendOk(res, projectsInfos) }, - }) - sendOk(res, project) -} - -export const getProjectSecretsController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: ProjectParams, -}>, res) => { - const projectId = req.params?.projectId - const userId = req.session?.user?.id - - const projectSecrets = await getProjectSecrets(projectId, userId) - - addReqLogs({ - req, - description: 'Secrets du projet récupérés avec succès', - extras: { - projectId, - userId, + ) + + // Récupérer un projet par son id + app.get<{ + Params: FromSchema, + }>('/:projectId', + { + schema: getProjectByIdSchema, }, + async (req, res) => { + const projectId = req.params.projectId + const userId = req.session.data.user.id + + const project = await getProject(projectId, userId) + + addReqLogs({ + req, + description: 'Projet de l\'utilisateur récupéré avec succès', + extras: { + projectId, + userId, + }, + }) + sendOk(res, project) + }) + + // Récupérer les secrets d'un projet + app.get<{ + Params: ProjectParams, +}>('/:projectId/secrets', + // TODO : pb schema, réponse inconnue (dépend des plugins) + // { + // schema: getProjectSecretsSchema, + // }, + async (req, res) => { + const projectId = req.params.projectId + const userId = req.session.data.user.id + + const projectSecrets = await getProjectSecrets(projectId, userId) + + addReqLogs({ + req, + description: 'Secrets du projet récupérés avec succès', + extras: { + projectId, + userId, + }, + }) + sendOk(res, projectSecrets) }) - sendOk(res, projectSecrets) -} - -// POST -export const createProjectController: RouteHandler = async (req: FastifyRequestWithSession<{ Body: CreateProjectDto }>, res) => { - const requestor = req.session?.user - delete requestor.groups - const data = req.body - - const project = await createProject(data, requestor) - addReqLogs({ - req, - description: 'Projet créé avec succès', - extras: { - projectId: project.id, + // Créer un projet + app.post<{ + Body: FromSchema + }>('/', + { + schema: createProjectSchema, }, + async (req, res) => { + const requestor = req.session.data.user + delete requestor.groups + const data = req.body + + const project = await createProject(data, requestor) + addReqLogs({ + req, + description: 'Projet créé avec succès', + extras: { + projectId: project.id, + }, + }) + sendCreated(res, project) + }) + + // Mettre à jour un projet + app.put<{ + Params: FromSchema, + Body: FromSchema +}>('/:projectId', + { + schema: updateProjectSchema, + }, + async (req, res) => { + const requestor = req.session.data.user + const projectId = req.params.projectId + const data = req.body + + const project = await updateProject(data, projectId, requestor) + addReqLogs({ + req, + description: 'Projet mis à jour avec succès', + extras: { + projectId, + }, + }) + sendOk(res, project) }) - sendCreated(res, project) -} -// UPDATE -export const updateProjectController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: ProjectParams, - Body: UpdateProjectDto -}>, res) => { - const requestor = req.session?.user - const projectId = req.params?.projectId - const data = req.body - - const project = await updateProject(data, projectId, requestor) - addReqLogs({ - req, - description: 'Projet mis à jour avec succès', - extras: { - projectId, - }, + // Archiver un projet + app.delete<{ + Params: FromSchema +}>('/:projectId', + { + schema: archiveProjectSchema, + }, + async (req, res) => { + const requestor = req.session.data.user + const projectId = req.params.projectId + + await archiveProject(projectId, requestor) + + addReqLogs({ + req, + description: 'Projet en cours de suppression', + extras: { + projectId, + }, + }) + sendNoContent(res) }) - sendOk(res, project) -} -// DELETE -export const archiveProjectController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: ProjectParams -}>, res) => { - const requestor = req.session?.user - const projectId = req.params?.projectId + // Enregistrement du sous routeur environment + app.register(projectEnvironmentRouter) - await archiveProject(projectId, requestor) + // Enregistrement du sous routeur repository + app.register(projectRepositoryRouter) - addReqLogs({ - req, - description: 'Projet en cours de suppression', - extras: { - projectId, - }, - }) - sendNoContent(res) + // Enregistrement du sous routeur user + app.register(projectUserRouter) + + // Enregistrement du sous routeur permission + app.register(projectPermissionRouter) } + +export default router diff --git a/apps/server/src/routes/admin/quota.spec.ts b/apps/server/src/resources/quota/admin/controllers.spec.ts similarity index 97% rename from apps/server/src/routes/admin/quota.spec.ts rename to apps/server/src/resources/quota/admin/controllers.spec.ts index 1488c6420..67442e7e1 100644 --- a/apps/server/src/routes/admin/quota.spec.ts +++ b/apps/server/src/resources/quota/admin/controllers.spec.ts @@ -1,7 +1,7 @@ -import prisma from '../../__mocks__/prisma.js' -import app, { getRequestor, setRequestor } from '../../__mocks__/app.js' +import prisma from '../../../__mocks__/prisma.js' +import app, { getRequestor, setRequestor } from '../../../__mocks__/app.js' import { vi, describe, it, expect, beforeAll, afterEach, afterAll, beforeEach } from 'vitest' -import { getConnection, closeConnections } from '../../connect.js' +import { getConnection, closeConnections } from '../../../connect.js' import { adminGroupPath } from '@dso-console/shared' import { getRandomEnv, getRandomQuota, getRandomQuotaStage, getRandomRole, getRandomStage, getRandomUser, repeatFn } from '@dso-console/test-utils' diff --git a/apps/server/src/resources/quota/admin/controllers.ts b/apps/server/src/resources/quota/admin/controllers.ts index 91e0e86f6..caa3b45c2 100644 --- a/apps/server/src/resources/quota/admin/controllers.ts +++ b/apps/server/src/resources/quota/admin/controllers.ts @@ -1,104 +1,128 @@ -import { type FastifyRequestWithSession } from '@/types' import { addReqLogs } from '@/utils/logger.js' import { sendCreated, sendNoContent, sendOk } from '@/utils/response.js' import { createQuota, deleteQuota, getQuotaAssociatedEnvironments, updateQuotaStage, updateQuotaPrivacy } from './business.js' -import type { CreateQuotaDto, QuotaParams, UpdateQuotaPrivacyDto, UpdateQuotaStageDto } from '@dso-console/shared' -import { type RouteHandler } from 'fastify' - -// GET -export const getQuotaAssociatedEnvironmentsController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: QuotaParams -}>, res) => { - const quotaId = req.params.quotaId - - const environments = await getQuotaAssociatedEnvironments(quotaId) - - addReqLogs({ - req, - description: 'Environnements associés au quota récupérés', - extras: { - quotaId, +import type { FastifyInstance } from 'fastify' + +import { createQuotaSchema, deleteQuotaSchema, getQuotaAssociatedEnvironmentsSchema, updateQuotaPrivacySchema, updateQuotaStageSchema } from '@dso-console/shared' +import { FromSchema } from 'json-schema-to-ts' + +const router = async (app: FastifyInstance, _opt) => { + // Récupérer les environnements associés au quota + app.get<{ + Params: FromSchema + }>('/:quotaId/environments', + { + schema: getQuotaAssociatedEnvironmentsSchema, }, - }) - - sendOk(res, environments) -} - -// POST -export const createQuotaController: RouteHandler = async (req: FastifyRequestWithSession<{ - Body: CreateQuotaDto -}>, res) => { - const data = req.body - - const quota = await createQuota(data) - - addReqLogs({ - req, - description: 'Quota créé avec succès', - extras: { - quotaId: quota.id, + async (req, res) => { + const quotaId = req.params.quotaId + + const environments = await getQuotaAssociatedEnvironments(quotaId) + + addReqLogs({ + req, + description: 'Environnements associés au quota récupérés', + extras: { + quotaId, + }, + }) + + sendOk(res, environments) + }) + + // Créer un quota + app.post<{ + Body: FromSchema + }>('/', + { + schema: createQuotaSchema, }, - }) - - sendCreated(res, quota) -} - -// PATCH -export const updateQuotaPrivacyController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: QuotaParams - Body: UpdateQuotaPrivacyDto -}>, res) => { - const quotaId = req.params.quotaId - const isPrivate = req.body.isPrivate - - const quota = await updateQuotaPrivacy(quotaId, isPrivate) - - addReqLogs({ - req, - description: 'Confidentialité du quota mise à jour avec succès', - extras: { - quotaId: quota.id, + async (req, res) => { + const data = req.body + + const quota = await createQuota(data) + + addReqLogs({ + req, + description: 'Quota créé avec succès', + extras: { + quotaId: quota.id, + }, + }) + + sendCreated(res, quota) + }) + + // Modifier une association quota / stage + app.put<{ + Body: FromSchema + }>('/quotastages', + { + schema: updateQuotaStageSchema, }, - }) - - sendOk(res, quota) -} - -// PUT -export const updateQuotaStageController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: QuotaParams - Body: UpdateQuotaStageDto -}>, res) => { - const data = req.body - - const quotaStages = await updateQuotaStage(data) - - addReqLogs({ - req, - description: 'Associations quota / types d\'environnement mises à jour avec succès', - extras: { - quotaStages: quotaStages.length + '', + async (req, res) => { + const data = req.body + + const quotaStages = await updateQuotaStage(data) + + addReqLogs({ + req, + description: 'Associations quota / types d\'environnement mises à jour avec succès', + extras: { + quotaStages: quotaStages.length + '', + }, + }) + + sendOk(res, quotaStages) + }) + + // Modifier la confidentialité d'un quota + app.patch<{ + Params: FromSchema, + Body: FromSchema + }>('/:quotaId/privacy', + { + schema: updateQuotaPrivacySchema, }, - }) - - sendOk(res, quotaStages) -} - -// DELETE -export const deleteQuotaController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: QuotaParams -}>, res) => { - const quotaId = req.params.quotaId + async (req, res) => { + const quotaId = req.params.quotaId + const isPrivate = req.body.isPrivate + + const quota = await updateQuotaPrivacy(quotaId, isPrivate) + + addReqLogs({ + req, + description: 'Confidentialité du quota mise à jour avec succès', + extras: { + quotaId: quota.id, + }, + }) + + sendOk(res, quota) + }) + + // Supprimer un quota + app.delete<{ + Params: FromSchema + }>('/:quotaId', + { + schema: deleteQuotaSchema, + }, + async (req, res) => { + const quotaId = req.params.quotaId - await deleteQuota(quotaId) + await deleteQuota(quotaId) - addReqLogs({ - req, - description: 'Quota supprimé avec succès', - extras: { - quotaId, - }, - }) + addReqLogs({ + req, + description: 'Quota supprimé avec succès', + extras: { + quotaId, + }, + }) - sendNoContent(res) + sendNoContent(res) + }) } + +export default router diff --git a/apps/server/src/resources/quota/admin/quota.ts b/apps/server/src/resources/quota/admin/quota.ts new file mode 100644 index 000000000..e69de29bb diff --git a/apps/server/src/resources/quota/controllers.ts b/apps/server/src/resources/quota/controllers.ts index cea4171a9..a45d661aa 100644 --- a/apps/server/src/resources/quota/controllers.ts +++ b/apps/server/src/resources/quota/controllers.ts @@ -1,17 +1,26 @@ import { addReqLogs } from '@/utils/logger.js' import { sendOk } from '@/utils/response.js' import { getQuotas } from './business.js' -import { type RouteHandler } from 'fastify' -import { type FastifyRequestWithSession } from '@/types/index.js' +import type { FastifyInstance } from 'fastify' -// GET -export const getQuotasController: RouteHandler = async (req: FastifyRequestWithSession, res) => { - const user = req.session?.user - const quotas = await getQuotas(user) +import { getQuotasSchema } from '@dso-console/shared' - addReqLogs({ - req, - description: 'Quotas récupérés avec succès', - }) - sendOk(res, quotas) +const router = async (app: FastifyInstance, _opt) => { + // Récupérer les quotas disponibles + app.get('/', + { + schema: getQuotasSchema, + }, + async (req, res) => { + const user = req.session.data.user + const quotas = await getQuotas(user) + + addReqLogs({ + req, + description: 'Quotas récupérés avec succès', + }) + sendOk(res, quotas) + }) } + +export default router diff --git a/apps/server/src/resources/quota/quota.ts b/apps/server/src/resources/quota/quota.ts new file mode 100644 index 000000000..e69de29bb diff --git a/apps/server/src/routes/project-repository.spec.ts b/apps/server/src/resources/repository/controllers.spec.ts similarity index 97% rename from apps/server/src/routes/project-repository.spec.ts rename to apps/server/src/resources/repository/controllers.spec.ts index 244ef70b6..e0cfdc261 100644 --- a/apps/server/src/routes/project-repository.spec.ts +++ b/apps/server/src/resources/repository/controllers.spec.ts @@ -1,8 +1,8 @@ -import prisma from '../__mocks__/prisma.js' -import app, { getRequestor, setRequestor } from '../__mocks__/app.js' +import prisma from '../../__mocks__/prisma.js' +import app, { getRequestor, setRequestor } from '../../__mocks__/app.js' import { vi, describe, it, expect, beforeAll, afterEach, afterAll } from 'vitest' import { createRandomDbSetup, getRandomLog, getRandomRepo, getRandomRole, getRandomUser } from '@dso-console/test-utils' -import { getConnection, closeConnections } from '../connect.js' +import { getConnection, closeConnections } from '../../connect.js' import { projectIsLockedInfo } from '@dso-console/shared' describe('Project routes', () => { diff --git a/apps/server/src/resources/repository/controllers.ts b/apps/server/src/resources/repository/controllers.ts index 88d9c3612..843f9f588 100644 --- a/apps/server/src/resources/repository/controllers.ts +++ b/apps/server/src/resources/repository/controllers.ts @@ -1,136 +1,159 @@ +import type { FastifyInstance } from 'fastify' +import { FromSchema } from 'json-schema-to-ts' import { filterObjectByKeys } from '@/utils/queries-tools.js' import { addReqLogs } from '@/utils/logger.js' import { sendOk, sendCreated } from '@/utils/response.js' -import { type FastifyRequestWithSession } from '@/types/index.js' -import type { - CreateRepositoryDto, UpdateRepositoryDto, RepositoryParams, ProjectRepositoriesParams, -} from '@dso-console/shared/src/resources/repository/dto.js' import { createRepository, deleteRepository, getProjectRepositories, getRepositoryById, updateRepository, checkUpsertRepository } from './business.js' import { BadRequestError } from '@/utils/errors.js' -import { type RouteHandler } from 'fastify' - -// GET -export const getRepositoryByIdController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: RepositoryParams -}>, res) => { - const projectId = req.params?.projectId - const repositoryId = req.params?.repositoryId - const userId = req.session?.user?.id - - const repository = await getRepositoryById(userId, projectId, repositoryId) - - addReqLogs({ - req, - description: 'Dépôt récupéré avec succès', - extras: { - repositoryId, - projectId, +import { createRepositorySchema, deleteRepositorySchema, getProjectRepositoriesSchema, getRepositoryByIdSchema, updateRepositorySchema } from '@dso-console/shared' + +const router = async (app: FastifyInstance, _opt) => { + // Récupérer un repository par son id + app.get<{ + Params: FromSchema + }>('/:projectId/repositories/:repositoryId', + { + schema: getRepositoryByIdSchema, }, - }) - sendOk(res, repository) -} - -export const getProjectRepositoriesController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: ProjectRepositoriesParams -}>, res) => { - const projectId = req.params?.projectId - const userId = req.session?.user?.id - - const repositories = await getProjectRepositories(userId, projectId) - - addReqLogs({ - req, - description: 'Dépôts du projet récupérés avec succès', - extras: { - projectId, - repositoriesId: repositories.map(({ id }) => id).join(', '), + async (req, res) => { + const projectId = req.params.projectId + const repositoryId = req.params.repositoryId + const userId = req.session.data.user.id + + const repository = await getRepositoryById(userId, projectId, repositoryId) + + addReqLogs({ + req, + description: 'Dépôt récupéré avec succès', + extras: { + repositoryId, + projectId, + }, + }) + sendOk(res, repository) + }) + + // Récupérer tous les repositories d'un projet + app.get<{ + Params: FromSchema + }>('/:projectId/repositories', + { + schema: getProjectRepositoriesSchema, }, - }) - sendOk(res, repositories) -} - -// CREATE -export const createRepositoryController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: ProjectRepositoriesParams - Body: CreateRepositoryDto -}>, res) => { - const data = req.body - const user = req.session?.user - const projectId = req.params?.projectId - - const repo = await createRepository(projectId, data, user.id) - - addReqLogs({ - req, - description: 'Dépôt créé avec succès', - extras: { - projectId, - repositoryId: repo.id, + async (req, res) => { + const projectId = req.params.projectId + const userId = req.session.data.user.id + + const repositories = await getProjectRepositories(userId, projectId) + + addReqLogs({ + req, + description: 'Dépôts du projet récupérés avec succès', + extras: { + projectId, + repositoriesId: repositories.map(({ id }) => id).join(', '), + }, + }) + sendOk(res, repositories) + }) + + // Créer un repository + app.post<{ + Params: FromSchema, + Body: FromSchema + }>('/:projectId/repositories', + { + schema: createRepositorySchema, }, - }) - sendCreated(res, repo) -} - -// UPDATE -export const updateRepositoryController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: RepositoryParams - Body: UpdateRepositoryDto -}>, res) => { - const userId = req.session?.user?.id - const projectId = req.params?.projectId - const repositoryId = req.params?.repositoryId - - const keysAllowedForUpdate = [ - 'externalRepoUrl', - 'isPrivate', - 'externalToken', - 'externalUserName', - ] - const data: Partial = filterObjectByKeys(req.body, keysAllowedForUpdate) - - await checkUpsertRepository(userId, projectId, 'owner') - - if (data.isPrivate && !data.externalToken) throw new BadRequestError('Le token est requis', undefined) - if (data.isPrivate && !data.externalUserName) throw new BadRequestError('Le nom d\'utilisateur est requis', undefined) - if (!data.isPrivate) { - data.externalToken = undefined - data.externalUserName = '' - } - - await getRepositoryById(userId, projectId, repositoryId) - - await updateRepository(projectId, repositoryId, data, userId) - - const description = 'Dépôt mis à jour avec succès' - addReqLogs({ - req, - description, - extras: { - projectId, - repositoryId, + async (req, res) => { + const data = req.body + const userId = req.session.data.user.id + const projectId = req.params.projectId + + const repo = await createRepository(projectId, data, userId) + + addReqLogs({ + req, + description: 'Dépôt créé avec succès', + extras: { + projectId, + repositoryId: repo.id, + }, + }) + sendCreated(res, repo) + }) + + // Mettre à jour un repository + app.put<{ + Params: FromSchema + Body: FromSchema + }>('/:projectId/repositories/:repositoryId', + { + schema: updateRepositorySchema, }, - }) - sendOk(res, description) -} - -// DELETE -export const deleteRepositoryController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: RepositoryParams -}>, res) => { - const projectId = req.params?.projectId - const repositoryId = req.params?.repositoryId - const userId = req.session?.user?.id - - await deleteRepository(projectId, repositoryId, userId) - - const description = 'Dépôt en cours de suppression' - addReqLogs({ - req, - description, - extras: { - projectId, - repositoryId, + async (req, res) => { + const userId = req.session.data.user.id + const projectId = req.params.projectId + const repositoryId = req.params.repositoryId + + const keysAllowedForUpdate = [ + 'externalRepoUrl', + 'isPrivate', + 'externalToken', + 'externalUserName', + ] + const data: Partial> = filterObjectByKeys(req.body, keysAllowedForUpdate) + + await checkUpsertRepository(userId, projectId, 'owner') + + if (data.isPrivate && !data.externalToken) throw new BadRequestError('Le token est requis', undefined) + if (data.isPrivate && !data.externalUserName) throw new BadRequestError('Le nom d\'utilisateur est requis', undefined) + if (!data.isPrivate) { + data.externalToken = undefined + data.externalUserName = '' + } + + await getRepositoryById(userId, projectId, repositoryId) + + await updateRepository(projectId, repositoryId, data, userId) + + const description = 'Dépôt mis à jour avec succès' + addReqLogs({ + req, + description, + extras: { + projectId, + repositoryId, + }, + }) + sendOk(res, description) + }) + + // Supprimer un repository + app.delete<{ + Params: FromSchema + }>('/:projectId/repositories/:repositoryId', + { + schema: deleteRepositorySchema, }, - }) - sendOk(res, description) + async (req, res) => { + const projectId = req.params.projectId + const repositoryId = req.params.repositoryId + const userId = req.session.data.user.id + + await deleteRepository(projectId, repositoryId, userId) + + const description = 'Dépôt en cours de suppression' + addReqLogs({ + req, + description, + extras: { + projectId, + repositoryId, + }, + }) + sendOk(res, description) + }) } + +export default router diff --git a/apps/server/src/resources/repository/project-repository.ts b/apps/server/src/resources/repository/project-repository.ts new file mode 100644 index 000000000..e69de29bb diff --git a/apps/server/src/resources/service/business.ts b/apps/server/src/resources/service/business.ts index 86027530d..57e208f8a 100644 --- a/apps/server/src/resources/service/business.ts +++ b/apps/server/src/resources/service/business.ts @@ -1,11 +1,11 @@ import { BadRequestError, ForbiddenError } from '@/utils/errors.js' import { getOrCreateUser } from '../queries-index.js' -import type { User } from '@prisma/client' import axios, { AxiosResponse } from 'axios' import { type ServiceInfos, servicesInfos } from '@/plugins/services.js' import { userSchema } from '@dso-console/shared' +import { SessionData } from '@mgcrea/fastify-session' -export const checkServicesHealth = async (requestor: User) => { +export const checkServicesHealth = async (requestor: SessionData['user']) => { await userSchema.validateAsync(requestor) const user = await getOrCreateUser(requestor) if (!user) throw new ForbiddenError('Vous n\'avez pas accès à cette information') diff --git a/apps/server/src/routes/service.spec.ts b/apps/server/src/resources/service/controllers.spec.ts similarity index 86% rename from apps/server/src/routes/service.spec.ts rename to apps/server/src/resources/service/controllers.spec.ts index b4c120b1b..d9f92c465 100644 --- a/apps/server/src/routes/service.spec.ts +++ b/apps/server/src/resources/service/controllers.spec.ts @@ -1,7 +1,7 @@ -import prisma from '../__mocks__/prisma.js' -import app, { getRequestor, setRequestor } from '../__mocks__/app.js' +import prisma from '../../__mocks__/prisma.js' +import app, { getRequestor, setRequestor } from '../../__mocks__/app.js' import { vi, describe, it, beforeAll, expect, afterEach, afterAll } from 'vitest' -import { getConnection, closeConnections } from '../connect.js' +import { getConnection, closeConnections } from '../../connect.js' import { getRandomUser } from '@dso-console/test-utils' describe('Service route', () => { diff --git a/apps/server/src/resources/service/controllers.ts b/apps/server/src/resources/service/controllers.ts index d59a47d9e..01c047be9 100644 --- a/apps/server/src/resources/service/controllers.ts +++ b/apps/server/src/resources/service/controllers.ts @@ -1,15 +1,20 @@ import { addReqLogs } from '@/utils/logger.js' import { sendOk } from '@/utils/response.js' import { checkServicesHealth } from './business.js' +import type { FastifyInstance } from 'fastify' -export const checkServicesHealthController = async (req, res) => { - const requestor = req.session?.user - delete requestor.groups +const router = async (app: FastifyInstance, _opt) => { + app.get('/', async (req, res) => { + const requestor = req.session.data.user + delete requestor.groups - const serviceData = await checkServicesHealth(requestor) - addReqLogs({ - req, - description: 'Etats des services récupérés avec succès', + const serviceData = await checkServicesHealth(requestor) + addReqLogs({ + req, + description: 'Etats des services récupérés avec succès', + }) + sendOk(res, serviceData) }) - sendOk(res, serviceData) } + +export default router diff --git a/apps/server/src/resources/stage/admin/business.ts b/apps/server/src/resources/stage/admin/business.ts index cb75cb4b8..ac0206c55 100644 --- a/apps/server/src/resources/stage/admin/business.ts +++ b/apps/server/src/resources/stage/admin/business.ts @@ -10,9 +10,10 @@ import { removeClusterFromStage, linkStageToQuotas, } from '@/resources/queries-index.js' -import { type CreateStageDto, type StageParams, type UpdateStageClustersDto, stageSchema } from '@dso-console/shared' +import { type CreateStageDto, type UpdateStageClustersDto, stageSchema } from '@dso-console/shared' +import { Stage } from '@prisma/client' -export const getStageAssociatedEnvironments = async (stageId: StageParams['stageId']) => { +export const getStageAssociatedEnvironments = async (stageId: Stage['id']) => { try { const stage = await getStageById(stageId) @@ -65,7 +66,7 @@ export const createStage = async (data: CreateStageDto) => { } } -export const updateStageClusters = async (stageId: StageParams['stageId'], clusterIds: UpdateStageClustersDto['clusterIds']) => { +export const updateStageClusters = async (stageId: Stage['id'], clusterIds: UpdateStageClustersDto['clusterIds']) => { try { const dbClusters = (await getStageById(stageId)).clusters @@ -84,7 +85,7 @@ export const updateStageClusters = async (stageId: StageParams['stageId'], clust } } -export const deleteStage = async (stageId: StageParams['stageId']) => { +export const deleteStage = async (stageId: Stage['id']) => { try { const environments = await getStageAssociatedEnvironments(stageId) if (environments.length) throw new BadRequestError('Impossible de supprimer le stage, des environnements en activité y ont souscrit', { extras: environments }) diff --git a/apps/server/src/routes/admin/stage.spec.ts b/apps/server/src/resources/stage/admin/controllers.spec.ts similarity index 96% rename from apps/server/src/routes/admin/stage.spec.ts rename to apps/server/src/resources/stage/admin/controllers.spec.ts index 9d77f1e37..e440232cf 100644 --- a/apps/server/src/routes/admin/stage.spec.ts +++ b/apps/server/src/resources/stage/admin/controllers.spec.ts @@ -1,7 +1,7 @@ -import prisma from '../../__mocks__/prisma.js' -import app, { getRequestor, setRequestor } from '../../__mocks__/app.js' +import prisma from '../../../__mocks__/prisma.js' +import app, { getRequestor, setRequestor } from '../../../__mocks__/app.js' import { vi, describe, it, expect, beforeAll, afterEach, afterAll, beforeEach } from 'vitest' -import { getConnection, closeConnections } from '../../connect.js' +import { getConnection, closeConnections } from '../../../connect.js' import { adminGroupPath } from '@dso-console/shared' import { getRandomCluster, getRandomEnv, getRandomQuota, getRandomQuotaStage, getRandomRole, getRandomStage, getRandomUser, repeatFn } from '@dso-console/test-utils' @@ -143,7 +143,7 @@ describe('Admin stages routes', () => { }) describe('updateQuotaStageController', () => { - it('Should update a quotaStage association', async () => { + it.skip('Should update a quotaStage association', async () => { const stage = getRandomStage('myStage') const quotas = repeatFn(4)(getRandomQuota) const dbQuotaStage = [...quotas.map(quota => getRandomQuotaStage(quota.id, stage.id)).slice(1), getRandomQuotaStage(getRandomQuota().id, stage.id)] @@ -168,7 +168,7 @@ describe('Admin stages routes', () => { expect(response.json()).toEqual(newQuotaStage) }) - it('Should not remove a quotaStage association if an environment suscribed it', async () => { + it.skip('Should not remove a quotaStage association if an environment suscribed it', async () => { const stage = getRandomStage('myStage') const quotas = repeatFn(4)(getRandomQuota) const dbQuotaStage = [...quotas.map(quota => getRandomQuotaStage(quota.id, stage.id)).slice(1), getRandomQuotaStage(getRandomQuota().id, stage.id)] diff --git a/apps/server/src/resources/stage/admin/controllers.ts b/apps/server/src/resources/stage/admin/controllers.ts index 774b4ce6d..afc022c3a 100644 --- a/apps/server/src/resources/stage/admin/controllers.ts +++ b/apps/server/src/resources/stage/admin/controllers.ts @@ -1,84 +1,118 @@ -import { type FastifyRequestWithSession } from '@/types' +import type { FastifyInstance } from 'fastify' +import type { FromSchema } from 'json-schema-to-ts' import { addReqLogs } from '@/utils/logger.js' import { sendCreated, sendNoContent, sendOk } from '@/utils/response.js' import { createStage, getStageAssociatedEnvironments, deleteStage, updateStageClusters } from './business.js' -import type { CreateStageDto, UpdateStageClustersDto, StageParams } from '@dso-console/shared' -import { type RouteHandler } from 'fastify' - -// GET -export const getStageAssociatedEnvironmentsController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: StageParams, -}>, res) => { - const stageId = req.params.stageId - - const environments = await getStageAssociatedEnvironments(stageId) - - addReqLogs({ - req, - description: 'Environnements associés au type d\'environnement récupérés', - extras: { - stageId, +import { + createStageSchema, + deleteStageSchema, + getStageAssociatedEnvironmentsSchema, + updateStageClustersSchema, +} from '@dso-console/shared' + +const router = async (app: FastifyInstance, _opt) => { + // Récupérer les environnements associés au stage + app.get<{ + Params: FromSchema, + }>('/:stageId/environments', + { + schema: getStageAssociatedEnvironmentsSchema, }, - }) - - sendOk(res, environments) -} + async (req, res) => { + const stageId = req.params.stageId -// POST -export const createStageController: RouteHandler = async (req: FastifyRequestWithSession<{ - Body: CreateStageDto, -}>, res) => { - const data = req.body + const environments = await getStageAssociatedEnvironments(stageId) - const stage = await createStage(data) + addReqLogs({ + req, + description: 'Environnements associés au type d\'environnement récupérés', + extras: { + stageId, + }, + }) - addReqLogs({ - req, - description: 'Type d\'environnement créé avec succès', - extras: { - stageId: stage.id, + sendOk(res, environments) }, + ) + + // Créer un stage + app.post<{ + Body: FromSchema, +}>('/', + { + schema: createStageSchema, + }, + async (req, res) => { + const data = req.body + + const stage = await createStage(data) + + addReqLogs({ + req, + description: 'Type d\'environnement créé avec succès', + extras: { + stageId: stage.id, + }, + }) + + sendCreated(res, stage) }) - sendCreated(res, stage) -} - -// PATCH -export const updateStageClustersController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: StageParams, - Body: UpdateStageClustersDto, -}>, res) => { - const stageId = req.params.stageId - const clusterIds = req.body.clusterIds - - const stage = await updateStageClusters(stageId, clusterIds) - - addReqLogs({ - req, - description: 'Type d\'environnement mis à jour avec succès', - extras: { - stageId, - }, + // ce endpoint est dupliquer de quota, tout d'abord il ne devrait pas exister et surtout n'y avoir qu'un seul point d'entrée + // // Modifier une association quota / stage + // app.put('/quotastages', + // { + // schema: updateQuotaStageSchema, + // }, + // updateQuotaStageController) + + // Modifier une association stage / clusters + app.patch<{ + Params: FromSchema, + Body: FromSchema, +}>('/:stageId/clusters', + { + schema: updateStageClustersSchema, + }, + async (req, res) => { + const stageId = req.params.stageId + const clusterIds = req.body.clusterIds + + const stage = await updateStageClusters(stageId, clusterIds) + + addReqLogs({ + req, + description: 'Type d\'environnement mis à jour avec succès', + extras: { + stageId, + }, + }) + + sendOk(res, stage) }) - sendOk(res, stage) -} - -// DELETE -export const deleteStageController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: StageParams, -}>, res) => { - const stageId = req.params.stageId + // Supprimer un stage + app.delete<{ + Params: FromSchema, + }>('/:stageId', + { + schema: deleteStageSchema, + }, + async (req, res) => { + const stageId = req.params.stageId - await deleteStage(stageId) + await deleteStage(stageId) - addReqLogs({ - req, - description: 'Type d\'environnement supprimé avec succès', - extras: { - stageId, - }, - }) + addReqLogs({ + req, + description: 'Type d\'environnement supprimé avec succès', + extras: { + stageId, + }, + }) - sendNoContent(res) + sendNoContent(res) + }) } + +export default router diff --git a/apps/server/src/resources/stage/controllers.ts b/apps/server/src/resources/stage/controllers.ts index 690728495..d58c04a4c 100644 --- a/apps/server/src/resources/stage/controllers.ts +++ b/apps/server/src/resources/stage/controllers.ts @@ -1,17 +1,26 @@ +import type { FastifyInstance } from 'fastify' import { addReqLogs } from '@/utils/logger.js' import { sendOk } from '@/utils/response.js' import { getStages } from './business.js' -import { type RouteHandler } from 'fastify' -import { type FastifyRequestWithSession } from '@/types/index.js' -// GET -export const getStagesController: RouteHandler = async (req: FastifyRequestWithSession, res) => { - const userId = req.session?.user?.id - const stages = await getStages(userId) +import { getStagesSchema } from '@dso-console/shared' - addReqLogs({ - req, - description: 'Stages récupérés avec succès', - }) - sendOk(res, stages) +const router = async (app: FastifyInstance, _opt) => { + // Récupérer les types d'environnement disponibles + app.get('/', + { + schema: getStagesSchema, + }, + async (req, res) => { + const userId = req.session.data.user.id + const stages = await getStages(userId) + + addReqLogs({ + req, + description: 'Stages récupérés avec succès', + }) + sendOk(res, stages) + }) } + +export default router diff --git a/apps/server/src/resources/stage/stage.ts b/apps/server/src/resources/stage/stage.ts new file mode 100644 index 000000000..e69de29bb diff --git a/apps/server/src/resources/system/db/controllers.ts b/apps/server/src/resources/system/db/controllers.ts index f880e3215..5d5fc1220 100644 --- a/apps/server/src/resources/system/db/controllers.ts +++ b/apps/server/src/resources/system/db/controllers.ts @@ -1,15 +1,18 @@ import { sendOk } from '@/utils/response.js' import { addReqLogs } from '@/utils/logger.js' -import type { FastifyRequestWithSession } from '@/types/index.js' -import type { FastifyReply } from 'fastify' +import type { FastifyReply, FastifyRequest, FastifyInstance } from 'fastify' import { getDb } from './business.js' // TODO revoir -export const getDbController = async (req: FastifyRequestWithSession, res: FastifyReply) => { - const db = await getDb() - addReqLogs({ - req, - description: 'Export de la BDD avec succès', +const router = async (app: FastifyInstance, _opt) => { + app.get('/', async (req: FastifyRequest, res: FastifyReply) => { + const db = await getDb() + addReqLogs({ + req, + description: 'Export de la BDD avec succès', + }) + sendOk(res, db) }) - sendOk(res, db) } + +export default router diff --git a/apps/server/src/routes/admin/user.spec.ts b/apps/server/src/resources/user/admin/controllers.spec.ts similarity index 91% rename from apps/server/src/routes/admin/user.spec.ts rename to apps/server/src/resources/user/admin/controllers.spec.ts index c63bef95f..c62651d6b 100644 --- a/apps/server/src/routes/admin/user.spec.ts +++ b/apps/server/src/resources/user/admin/controllers.spec.ts @@ -1,8 +1,8 @@ -import prisma from '../../__mocks__/prisma.js' -import app, { setRequestor } from '../../__mocks__/app.js' +import prisma from '../../../__mocks__/prisma.js' +import app, { setRequestor } from '../../../__mocks__/app.js' import { vi, describe, it, expect, beforeAll, afterEach, afterAll, beforeEach } from 'vitest' import { getRandomUser, repeatFn } from '@dso-console/test-utils' -import { getConnection, closeConnections } from '../../connect.js' +import { getConnection, closeConnections } from '../../../connect.js' import { adminGroupPath } from '@dso-console/shared' describe('Admin Users routes', () => { diff --git a/apps/server/src/resources/user/admin/controllers.ts b/apps/server/src/resources/user/admin/controllers.ts index 0016abaf6..345de7b6e 100644 --- a/apps/server/src/resources/user/admin/controllers.ts +++ b/apps/server/src/resources/user/admin/controllers.ts @@ -1,15 +1,25 @@ import { sendOk } from '@/utils/response.js' import { addReqLogs } from '@/utils/logger.js' import { getUsers } from './business.js' -import { type RouteHandler } from 'fastify' -import { type FastifyRequestWithSession } from '@/types/index.js' +import type { FastifyInstance } from 'fastify' -export const getUsersController: RouteHandler = async (req: FastifyRequestWithSession, res) => { - const users = await getUsers() +import { getUsersSchema } from '@dso-console/shared' - addReqLogs({ - req, - description: 'Ensemble des utilisateurs récupérés avec succès', - }) - sendOk(res, users) +const router = async (app: FastifyInstance, _opt) => { + // Récupérer tous les utilisateurs + app.get('/', + { + schema: getUsersSchema, + }, + async (req, res) => { + const users = await getUsers() + + addReqLogs({ + req, + description: 'Ensemble des utilisateurs récupérés avec succès', + }) + sendOk(res, users) + }) } + +export default router diff --git a/apps/server/src/resources/user/admin/user.ts b/apps/server/src/resources/user/admin/user.ts new file mode 100644 index 000000000..e69de29bb diff --git a/apps/server/src/routes/project-user.spec.ts b/apps/server/src/resources/user/controllers.spec.ts similarity index 98% rename from apps/server/src/routes/project-user.spec.ts rename to apps/server/src/resources/user/controllers.spec.ts index f4ee12bf8..e61036693 100644 --- a/apps/server/src/routes/project-user.spec.ts +++ b/apps/server/src/resources/user/controllers.spec.ts @@ -1,8 +1,8 @@ -import prisma from '../__mocks__/prisma.js' -import app, { getRequestor, setRequestor } from '../__mocks__/app.js' +import prisma from '../../__mocks__/prisma.js' +import app, { getRequestor, setRequestor } from '../../__mocks__/app.js' import { vi, describe, it, expect, beforeAll, afterEach, afterAll } from 'vitest' import { createRandomDbSetup, getRandomLog, getRandomRole, getRandomUser } from '@dso-console/test-utils' -import { getConnection, closeConnections } from '../connect.js' +import { getConnection, closeConnections } from '../../connect.js' import { projectIsLockedInfo } from '@dso-console/shared' describe('User routes', () => { diff --git a/apps/server/src/resources/user/controllers.ts b/apps/server/src/resources/user/controllers.ts index c9a7b6d5e..682099308 100644 --- a/apps/server/src/resources/user/controllers.ts +++ b/apps/server/src/resources/user/controllers.ts @@ -1,150 +1,176 @@ +import type { FastifyInstance } from 'fastify' import { sendOk, sendCreated } from '@/utils/response.js' import { addReqLogs } from '@/utils/logger.js' import { addUserToProject, checkProjectLocked, checkProjectRole, getMatchingUsers, getProjectInfos, getProjectUsers, removeUserFromProject, updateUserProjectRole } from './business.js' -import { type FastifyRequestWithSession } from '@/types/index.js' -import { type RouteHandler } from 'fastify' -import type { UserParams, AddUserToProjectDto, RoleParams, LettersQuery, UpdateUserProjectRoleDto } from '@dso-console/shared' -import { adminGroupPath } from '@dso-console/shared' - -// GET -// TODO : pas utilisé -export const getProjectUsersController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: UserParams -}>, res) => { - const user = req.session?.user - const projectId = req.params?.projectId - - const users = await getProjectUsers(projectId) - - if (!user.groups?.includes(adminGroupPath)) { - await checkProjectRole(user.id, { userList: users, minRole: 'user' }) - } - - addReqLogs({ - req, - description: 'Membres du projet récupérés avec succès', - extras: { - projectId, - }, +import { adminGroupPath, addUserToProjectSchema, getMatchingUsersSchema, getProjectUsersSchema, removeUserFromProjectSchema, updateUserProjectRoleSchema } from '@dso-console/shared' + +import { FromSchema } from 'json-schema-to-ts' + +const router = async (app: FastifyInstance, _opt) => { + // TODO : pas utilisé + // Récupérer les membres d'un projet + app.get<{ + Params: FromSchema +}>('/:projectId/users', + { + schema: getProjectUsersSchema, + }, + async (req, res) => { + const user = req.session.data.user + const projectId = req.params.projectId + + const users = await getProjectUsers(projectId) + + if (!user.groups?.includes(adminGroupPath)) { + await checkProjectRole(user.id, { userList: users, minRole: 'user' }) + } + + addReqLogs({ + req, + description: 'Membres du projet récupérés avec succès', + extras: { + projectId, + }, + }) + sendOk(res, users) }) - sendOk(res, users) -} - -export const getMatchingUsersController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: UserParams - Querystring: LettersQuery -}>, res) => { - const user = req.session?.user - const projectId = req.params?.projectId - const { letters } = req.query - - const users = await getProjectUsers(projectId) - - if (!user.groups?.includes(adminGroupPath)) { - await checkProjectRole(user.id, { userList: users, minRole: 'user' }) - } - const usersMatching = await getMatchingUsers(letters) - - addReqLogs({ - req, - description: 'Utilisateurs récupérés avec succès', - extras: { - projectId, - }, + // Récupérer des utilisateurs par match + app.get<{ + Params: FromSchema + Querystring: FromSchema +}>('/:projectId/users/match', + { + schema: getMatchingUsersSchema, + }, + async (req, res) => { + const user = req.session.data.user + const projectId = req.params.projectId + const { letters } = req.query + + const users = await getProjectUsers(projectId) + + if (!user.groups?.includes(adminGroupPath)) { + await checkProjectRole(user.id, { userList: users, minRole: 'user' }) + } + + const usersMatching = await getMatchingUsers(letters) + + addReqLogs({ + req, + description: 'Utilisateurs récupérés avec succès', + extras: { + projectId, + }, + }) + sendOk(res, usersMatching) }) - sendOk(res, usersMatching) -} -// CREATE -export const addUserToProjectController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: UserParams - Body: AddUserToProjectDto -}>, res) => { - const user = req.session?.user - const projectId = req.params?.projectId - const data = req.body - - const project = await getProjectInfos(projectId) - - if (!user.groups?.includes(adminGroupPath)) { - await checkProjectRole(user.id, { roles: project.roles, minRole: 'owner' }) - } - - await checkProjectLocked(project) - - const userToAdd = await addUserToProject(project, data.email, user.id) - - const description = 'Utilisateur ajouté au projet avec succès' - addReqLogs({ - req, - description, - extras: { - projectId, - userId: userToAdd.id, - }, + // Ajouter un membre dans un projet + app.post<{ + Params: FromSchema + Body: FromSchema +}>('/:projectId/users', + { + schema: addUserToProjectSchema, + }, + async (req, res) => { + const user = req.session.data.user + const projectId = req.params.projectId + const data = req.body + + const project = await getProjectInfos(projectId) + + if (!user.groups?.includes(adminGroupPath)) { + await checkProjectRole(user.id, { roles: project.roles, minRole: 'owner' }) + } + + await checkProjectLocked(project) + + const userToAdd = await addUserToProject(project, data.email, user.id) + + const description = 'Utilisateur ajouté au projet avec succès' + addReqLogs({ + req, + description, + extras: { + projectId, + userId: userToAdd.id, + }, + }) + sendCreated(res, description) }) - sendCreated(res, description) -} -// PUT -export const updateUserProjectRoleController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: RoleParams - Body: UpdateUserProjectRoleDto -}>, res) => { - const user = req.session?.user - const projectId = req.params?.projectId - const userToUpdateId = req.params?.userId - const data = req.body - - const project = await getProjectInfos(projectId) - - if (!user.groups?.includes(adminGroupPath)) { - await checkProjectRole(user.id, { roles: project.roles, minRole: 'owner' }) - } - - await checkProjectLocked(project) - - await updateUserProjectRole(userToUpdateId, project, data.role) - - const description = 'Rôle de l\'utilisateur mis à jour avec succès' - addReqLogs({ - req, - description, - extras: { - projectId, - userId: userToUpdateId, - }, + // Mettre à jour un membre d'un projet + app.put<{ + Params: FromSchema + Body: FromSchema +}>('/:projectId/users/:userId', + { + schema: updateUserProjectRoleSchema, + }, + async (req, res) => { + const user = req.session.data.user + const projectId = req.params.projectId + const userToUpdateId = req.params.userId + const data = req.body + + const project = await getProjectInfos(projectId) + + if (!user.groups?.includes(adminGroupPath)) { + await checkProjectRole(user.id, { roles: project.roles, minRole: 'owner' }) + } + + await checkProjectLocked(project) + + await updateUserProjectRole(userToUpdateId, project, data.role) + + const description = 'Rôle de l\'utilisateur mis à jour avec succès' + addReqLogs({ + req, + description, + extras: { + projectId, + userId: userToUpdateId, + }, + }) + sendOk(res, description) + }, +) + + // Supprimer un membre d'un projet + app.delete<{ + Params: FromSchema +}>('/:projectId/users/:userId', + { + schema: removeUserFromProjectSchema, + }, + async (req, res) => { + const user = req.session.data.user + const projectId = req.params.projectId + const userToRemoveId = req.params.userId + + const project = await getProjectInfos(projectId) + + if (!user.groups?.includes(adminGroupPath)) { + await checkProjectRole(user.id, { roles: project.roles, minRole: 'owner' }) + } + + await checkProjectLocked(project) + + await removeUserFromProject(userToRemoveId, project, user.id) + + const description = 'Utilisateur retiré du projet avec succès' + addReqLogs({ + req, + description, + extras: { + projectId, + userId: userToRemoveId, + }, + }) + sendOk(res, description) }) - sendOk(res, description) } -// DELETE -export const removeUserFromProjectController: RouteHandler = async (req: FastifyRequestWithSession<{ - Params: RoleParams -}>, res) => { - const user = req.session?.user - const projectId = req.params?.projectId - const userToRemoveId = req.params?.userId - - const project = await getProjectInfos(projectId) - - if (!user.groups?.includes(adminGroupPath)) { - await checkProjectRole(user.id, { roles: project.roles, minRole: 'owner' }) - } - - await checkProjectLocked(project) - - await removeUserFromProject(userToRemoveId, project, user.id) - - const description = 'Utilisateur retiré du projet avec succès' - addReqLogs({ - req, - description, - extras: { - projectId, - userId: userToRemoveId, - }, - }) - sendOk(res, description) -} +export default router diff --git a/apps/server/src/routes/admin/cluster.ts b/apps/server/src/routes/admin/cluster.ts deleted file mode 100644 index 07f915ea9..000000000 --- a/apps/server/src/routes/admin/cluster.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { - getClusterAssociatedEnvironmentsController, - createClusterController, - updateClusterController, - deleteClusterController, -} from '@/resources/cluster/admin/controllers.js' -import { createClusterSchema, getClusterAssociatedEnvironmentsSchema, updateClusterSchema, deleteClusterSchema } from '@dso-console/shared' -import { type FastifyInstance } from 'fastify' - -const router = async (app: FastifyInstance, _opt) => { - // Récupérer les environnements associés au cluster - app.get('/:clusterId/environments', - { - schema: getClusterAssociatedEnvironmentsSchema, - }, - getClusterAssociatedEnvironmentsController) - - // Déclarer un nouveau cluster - app.post('/', - { - schema: createClusterSchema, - }, - createClusterController) - - // Mettre à jour un cluster - app.put('/:clusterId', - { - schema: updateClusterSchema, - }, - updateClusterController) - - // Supprimer un cluster - app.delete('/:clusterId', - { - schema: deleteClusterSchema, - }, - deleteClusterController) -} - -export default router diff --git a/apps/server/src/routes/admin/db.ts b/apps/server/src/routes/admin/db.ts deleted file mode 100644 index 99b85739c..000000000 --- a/apps/server/src/routes/admin/db.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { getDbController } from '@/resources/system/db/controllers.js' -import { type FastifyInstance } from 'fastify' - -const router = async (app: FastifyInstance, _opt) => { - app.get('/', getDbController) -} - -export default router diff --git a/apps/server/src/routes/admin/log.ts b/apps/server/src/routes/admin/log.ts deleted file mode 100644 index 72e27663f..000000000 --- a/apps/server/src/routes/admin/log.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { - getAllLogsController, -} from '@/resources/log/admin/controllers.js' -import { type FastifyInstance } from 'fastify' - -const router = async (app: FastifyInstance, _opt) => { - // Récupérer des logs - app.get('/', getAllLogsController) -} - -export default router diff --git a/apps/server/src/routes/admin/organization.ts b/apps/server/src/routes/admin/organization.ts deleted file mode 100644 index 525ea8527..000000000 --- a/apps/server/src/routes/admin/organization.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { - getAllOrganizationsController, - createOrganizationController, - updateOrganizationController, - fetchOrganizationsController, -} from '@/resources/organization/admin/controllers.js' -import { getAllOrganizationsSchema, createOrganizationSchema, fetchOrganizationsSchema, updateOrganizationSchema } from '@dso-console/shared' -import { type FastifyInstance } from 'fastify' - -const router = async (app: FastifyInstance, _opt) => { - // Récupérer toutes les organisations - app.get('/', - { - schema: getAllOrganizationsSchema, - }, - getAllOrganizationsController) - - // Créer une organisation - app.post('/', - { - schema: createOrganizationSchema, - }, - createOrganizationController) - - // Synchroniser les organisations via les plugins externes - app.put('/sync', - { - schema: fetchOrganizationsSchema, - }, - fetchOrganizationsController) - - // Mettre à jour une organisation - app.put('/:orgName', - { - schema: updateOrganizationSchema, - }, - updateOrganizationController) -} - -export default router diff --git a/apps/server/src/routes/admin/project.ts b/apps/server/src/routes/admin/project.ts deleted file mode 100644 index fede4724a..000000000 --- a/apps/server/src/routes/admin/project.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { - getAllProjectsController, - handleProjectLockingController, -} from '@/resources/project/admin/controllers.js' -import { getAllProjectsSchema } from '@dso-console/shared' -import { type FastifyInstance } from 'fastify' - -const router = async (app: FastifyInstance, _opt) => { - // Récupérer tous les projets - app.get('/', - { - schema: getAllProjectsSchema, - }, - getAllProjectsController) - - // (Dé)verrouiller un projet - app.patch('/:projectId', handleProjectLockingController) -} - -export default router diff --git a/apps/server/src/routes/admin/quota.ts b/apps/server/src/routes/admin/quota.ts deleted file mode 100644 index 930f396e8..000000000 --- a/apps/server/src/routes/admin/quota.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { - getQuotaAssociatedEnvironmentsController, - createQuotaController, - deleteQuotaController, - updateQuotaStageController, - updateQuotaPrivacyController, -} from '@/resources/quota/admin/controllers.js' -import { createQuotaSchema, deleteQuotaSchema, getQuotaAssociatedEnvironmentsSchema, updateQuotaPrivacySchema, updateQuotaStageSchema } from '@dso-console/shared' -import { type FastifyInstance } from 'fastify' - -const router = async (app: FastifyInstance, _opt) => { - // Récupérer les environnements associés au quota - app.get('/:quotaId/environments', - { - schema: getQuotaAssociatedEnvironmentsSchema, - }, - getQuotaAssociatedEnvironmentsController) - - // Créer un quota - app.post('/', - { - schema: createQuotaSchema, - }, - createQuotaController) - - // Modifier une association quota / stage - app.put('/quotastages', - { - schema: updateQuotaStageSchema, - }, - updateQuotaStageController) - - // Modifier la confidentialité d'un quota - app.patch('/:quotaId/privacy', - { - schema: updateQuotaPrivacySchema, - }, - updateQuotaPrivacyController) - - // Supprimer un quota - app.delete('/:quotaId', - { - schema: deleteQuotaSchema, - }, - deleteQuotaController) -} - -export default router diff --git a/apps/server/src/routes/admin/stage.ts b/apps/server/src/routes/admin/stage.ts deleted file mode 100644 index 9ac5f140c..000000000 --- a/apps/server/src/routes/admin/stage.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { - updateQuotaStageController, -} from '@/resources/quota/admin/controllers.js' - -import { - getStageAssociatedEnvironmentsController, - createStageController, - deleteStageController, - updateStageClustersController, -} from '@/resources/stage/admin/controllers.js' -import { createStageSchema, deleteStageSchema, getStageAssociatedEnvironmentsSchema, updateQuotaStageSchema, updateStageClustersSchema } from '@dso-console/shared' -import { type FastifyInstance } from 'fastify' - -const router = async (app: FastifyInstance, _opt) => { - // Récupérer les environnements associés au stage - app.get('/:stageId/environments', - { - schema: getStageAssociatedEnvironmentsSchema, - }, - getStageAssociatedEnvironmentsController) - - // Créer un stage - app.post('/', - { - schema: createStageSchema, - }, - createStageController) - - // Modifier une association quota / stage - app.put('/quotastages', - { - schema: updateQuotaStageSchema, - }, - updateQuotaStageController) - - // Modifier une association stage / clusters - app.patch('/:stageId/clusters', - { - schema: updateStageClustersSchema, - }, - updateStageClustersController) - - // Supprimer un stage - app.delete('/:stageId', - { - schema: deleteStageSchema, - }, - deleteStageController) -} - -export default router diff --git a/apps/server/src/routes/admin/user.ts b/apps/server/src/routes/admin/user.ts deleted file mode 100644 index 0b8c85af4..000000000 --- a/apps/server/src/routes/admin/user.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { - getUsersController, -} from '@/resources/user/admin/controllers.js' -import { getUsersSchema } from '@dso-console/shared' -import { type FastifyInstance } from 'fastify' - -const router = async (app: FastifyInstance, _opt) => { - // Récupérer tous les utilisateurs - app.get('/', - { - schema: getUsersSchema, - }, - getUsersController) -} - -export default router diff --git a/apps/server/src/routes/ci-files.ts b/apps/server/src/routes/ci-files.ts deleted file mode 100644 index c16529ff3..000000000 --- a/apps/server/src/routes/ci-files.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { type FastifyInstance } from 'fastify' -import { generateCIFiles } from '../generate-files/generate-ci-files.js' - -const router = async (app: FastifyInstance, _opt) => { - app.post('/', generateCIFiles) -} - -export default router diff --git a/apps/server/src/routes/cluster.ts b/apps/server/src/routes/cluster.ts deleted file mode 100644 index dba063083..000000000 --- a/apps/server/src/routes/cluster.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { type FastifyInstance } from 'fastify' -import { - getClustersController, -} from '../resources/cluster/controllers.js' -import { getClustersSchema } from '@dso-console/shared' - -const router = async (app: FastifyInstance, _opt) => { - // Récupérer les quotas disponibles - app.get('/', - { - schema: getClustersSchema, - }, - getClustersController) -} - -export default router diff --git a/apps/server/src/routes/organization.ts b/apps/server/src/routes/organization.ts deleted file mode 100644 index fdfaae7b0..000000000 --- a/apps/server/src/routes/organization.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { - getActiveOrganizationsController, -} from '@/resources/organization/controllers.js' -import { getActiveOrganizationsSchema } from '@dso-console/shared' -import { type FastifyInstance } from 'fastify' - -const router = async (app: FastifyInstance, _opt) => { - app.get('/', - { - schema: getActiveOrganizationsSchema, - }, - getActiveOrganizationsController) -} - -export default router diff --git a/apps/server/src/routes/project-environment.ts b/apps/server/src/routes/project-environment.ts deleted file mode 100644 index bb0311a88..000000000 --- a/apps/server/src/routes/project-environment.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { type FastifyInstance } from 'fastify' -import { - getEnvironmentByIdController, - initializeEnvironmentController, - updateEnvironmentController, - deleteEnvironmentController, -} from '../resources/environment/controllers.js' -import { getEnvironmentByIdSchema, initializeEnvironmentSchema, updateEnvironmentSchema, deleteEnvironmentSchema, type InitializeEnvironmentDto, type UpdateEnvironmentDto } from '@dso-console/shared' - -const router = async (app: FastifyInstance, _opt) => { - // Récupérer un environnement par son id - app.get('/:projectId/environments/:environmentId', - { - schema: getEnvironmentByIdSchema, - }, - getEnvironmentByIdController) - - // Créer un environnement - app.post<{ Body: InitializeEnvironmentDto }>('/:projectId/environments', - { - schema: initializeEnvironmentSchema, - }, - initializeEnvironmentController) - - // Mettre à jour un environnement - app.put<{ Body: UpdateEnvironmentDto }>('/:projectId/environments/:environmentId', - { - schema: updateEnvironmentSchema, - }, - updateEnvironmentController) - - // Supprimer un environnement - app.delete('/:projectId/environments/:environmentId', - { - schema: deleteEnvironmentSchema, - }, - deleteEnvironmentController) -} - -export default router diff --git a/apps/server/src/routes/project-permission.ts b/apps/server/src/routes/project-permission.ts deleted file mode 100644 index c02bc9653..000000000 --- a/apps/server/src/routes/project-permission.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { - getEnvironmentPermissionsController, - setPermissionController, - updatePermissionController, - deletePermissionController, -} from '@/resources/permission/controllers.js' -import { deletePermissionSchema, getEnvironmentPermissionsSchema, setPermissionSchema, updatePermissionSchema } from '@dso-console/shared' -import { type FastifyInstance } from 'fastify' - -const router = async (app: FastifyInstance, _opt) => { - // Récupérer les permissions d'un environnement - app.get('/:projectId/environments/:environmentId/permissions', - { - schema: getEnvironmentPermissionsSchema, - }, - getEnvironmentPermissionsController) - - // Créer une permission - app.post('/:projectId/environments/:environmentId/permissions', - { - schema: setPermissionSchema, - }, - setPermissionController) - - // Mettre à jour le level d'une permission - app.put('/:projectId/environments/:environmentId/permissions', - { - schema: updatePermissionSchema, - }, - updatePermissionController) - - // Supprimer une permission - app.delete('/:projectId/environments/:environmentId/permissions/:userId', - { - schema: deletePermissionSchema, - }, - deletePermissionController) -} - -export default router diff --git a/apps/server/src/routes/project-repository.ts b/apps/server/src/routes/project-repository.ts deleted file mode 100644 index 3a9ed5639..000000000 --- a/apps/server/src/routes/project-repository.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { - getRepositoryByIdController, - getProjectRepositoriesController, - createRepositoryController, - updateRepositoryController, - deleteRepositoryController, -} from '@/resources/repository/controllers.js' -import { createRepositorySchema, deleteRepositorySchema, getProjectRepositoriesSchema, getRepositoryByIdSchema, updateRepositorySchema } from '@dso-console/shared' -import { type FastifyInstance } from 'fastify' - -const router = async (app: FastifyInstance, _opt) => { - // Récupérer un repository par son id - app.get('/:projectId/repositories/:repositoryId', - { - schema: getRepositoryByIdSchema, - }, - getRepositoryByIdController) - - // Récupérer tous les repositories d'un projet - app.get('/:projectId/repositories', - { - schema: getProjectRepositoriesSchema, - }, - getProjectRepositoriesController) - - // Créer un repository - app.post('/:projectId/repositories', - { - schema: createRepositorySchema, - }, - createRepositoryController) - - // Mettre à jour un repository - app.put('/:projectId/repositories/:repositoryId', - { - schema: updateRepositorySchema, - }, - updateRepositoryController) - - // Supprimer un repository - app.delete('/:projectId/repositories/:repositoryId', - { - schema: deleteRepositorySchema, - }, - deleteRepositoryController) -} - -export default router diff --git a/apps/server/src/routes/project-user.ts b/apps/server/src/routes/project-user.ts deleted file mode 100644 index b1cb37eb6..000000000 --- a/apps/server/src/routes/project-user.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { - getProjectUsersController, - addUserToProjectController, - removeUserFromProjectController, - updateUserProjectRoleController, - getMatchingUsersController, -} from '@/resources/user/controllers.js' -import { addUserToProjectSchema, getMatchingUsersSchema, getProjectUsersSchema, removeUserFromProjectSchema, updateUserProjectRoleSchema } from '@dso-console/shared' -import { type FastifyInstance } from 'fastify' - -const router = async (app: FastifyInstance, _opt) => { - // TODO : pas utilisé - // Récupérer les membres d'un projet - app.get('/:projectId/users', - { - schema: getProjectUsersSchema, - }, - getProjectUsersController) - - // Récupérer des utilisateurs par match - app.get('/:projectId/users/match', - { - schema: getMatchingUsersSchema, - }, - getMatchingUsersController) - - // Ajouter un membre dans un projet - app.post('/:projectId/users', - { - schema: addUserToProjectSchema, - }, - addUserToProjectController) - - // Mettre à jour un membre d'un projet - app.put('/:projectId/users/:userId', - { - schema: updateUserProjectRoleSchema, - }, - updateUserProjectRoleController) - - // Supprimer un membre d'un projet - app.delete('/:projectId/users/:userId', - { - schema: removeUserFromProjectSchema, - }, - removeUserFromProjectController) -} - -export default router diff --git a/apps/server/src/routes/project.ts b/apps/server/src/routes/project.ts deleted file mode 100644 index cf50767e3..000000000 --- a/apps/server/src/routes/project.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { type FastifyInstance } from 'fastify' - -import { - getUserProjectsController, - getProjectByIdController, - createProjectController, - archiveProjectController, - updateProjectController, - getProjectSecretsController, -} from '@/resources/project/controllers.js' -import projectEnvironmentRouter from './project-environment.js' -import projectRepositoryRouter from './project-repository.js' -import projectUserRouter from './project-user.js' -import projectPermissionRouter from './project-permission.js' -import { - getProjectByIdSchema, - getUserProjectsSchema, - createProjectSchema, - updateProjectSchema, - archiveProjectSchema, - // getProjectSecretsSchema, -} from '@dso-console/shared' - -const router = async (app: FastifyInstance, _opt) => { - // Récupérer tous les projets d'un user - app.get( - '/', - { - schema: getUserProjectsSchema, - }, - getUserProjectsController, - ) - - // Récupérer un projet par son id - app.get('/:projectId', - { - schema: getProjectByIdSchema, - }, - getProjectByIdController) - - // Récupérer les secrets d'un projet - app.get('/:projectId/secrets', - // TODO : pb schema, réponse inconnue (dépend des plugins) - // { - // schema: getProjectSecretsSchema, - // }, - getProjectSecretsController) - - // Créer un projet - app.post('/', - { - schema: createProjectSchema, - }, - createProjectController) - - // Mettre à jour un projet - app.put('/:projectId', - { - schema: updateProjectSchema, - }, - updateProjectController) - - // Archiver un projet - app.delete('/:projectId', - { - schema: archiveProjectSchema, - }, - archiveProjectController) - - // Enregistrement du sous routeur environment - app.register(projectEnvironmentRouter) - - // Enregistrement du sous routeur repository - app.register(projectRepositoryRouter) - - // Enregistrement du sous routeur user - app.register(projectUserRouter) - - // Enregistrement du sous routeur permission - app.register(projectPermissionRouter) -} - -export default router diff --git a/apps/server/src/routes/quota.ts b/apps/server/src/routes/quota.ts deleted file mode 100644 index 20654aa3e..000000000 --- a/apps/server/src/routes/quota.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { type FastifyInstance } from 'fastify' -import { - getQuotasController, -} from '../resources/quota/controllers.js' -import { getQuotasSchema } from '@dso-console/shared' - -const router = async (app: FastifyInstance, _opt) => { - // Récupérer les quotas disponibles - app.get('/', - { - schema: getQuotasSchema, - }, - getQuotasController) -} - -export default router diff --git a/apps/server/src/routes/service.ts b/apps/server/src/routes/service.ts deleted file mode 100644 index b1fb64396..000000000 --- a/apps/server/src/routes/service.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { checkServicesHealthController } from '@/resources/service/controllers.js' -import { type FastifyInstance } from 'fastify' - -const router = async (app: FastifyInstance, _opt) => { - app.get('/', checkServicesHealthController) -} - -export default router diff --git a/apps/server/src/routes/stage.ts b/apps/server/src/routes/stage.ts deleted file mode 100644 index b287bc3a6..000000000 --- a/apps/server/src/routes/stage.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { type FastifyInstance } from 'fastify' -import { - getStagesController, -} from '../resources/stage/controllers.js' -import { getStagesSchema } from '@dso-console/shared' - -const router = async (app: FastifyInstance, _opt) => { - // Récupérer les types d'environnement disponibles - app.get('/', - { - schema: getStagesSchema, - }, - getStagesController) -} - -export default router diff --git a/apps/server/src/types/index.ts b/apps/server/src/types/index.ts index 489fbd9eb..733f7ca36 100644 --- a/apps/server/src/types/index.ts +++ b/apps/server/src/types/index.ts @@ -1,18 +1,18 @@ import type { Cluster } from '@prisma/client' -import type { FastifyRequest } from 'fastify/types/request' import type { ClusterModel } from '@dso-console/shared' -export type KeycloakSession = { - session?: { - user?: { - id: string - firstName: string - lastName: string - email: string - groups: string[] - } - } +export type UserDetails = { + id: string + firstName: string + lastName: string + email: string + groups: string[] } -export type FastifyRequestWithSession = FastifyRequest & KeycloakSession export type ClusterMix = Cluster & ClusterModel + +declare module '@mgcrea/fastify-session' { + interface SessionData{ + user: UserDetails + } +} diff --git a/apps/server/src/utils/controller.ts b/apps/server/src/utils/controller.ts index fa2cb7258..f59a24f48 100644 --- a/apps/server/src/utils/controller.ts +++ b/apps/server/src/utils/controller.ts @@ -1,10 +1,10 @@ import { type ProjectRoles, adminGroupPath, projectIsLockedInfo } from '@dso-console/shared' import type { Permission, User, Role, Cluster } from '@prisma/client' import { ForbiddenError } from './errors.js' -import type { FastifyRequestWithSession } from '@/types/index.js' +import { FastifyRequest } from 'fastify' -export const checkAdminGroup = (req: FastifyRequestWithSession, res, done) => { - if (!req.session.user.groups?.includes(adminGroupPath)) { +export const checkAdminGroup = (req: FastifyRequest, _res, done) => { + if (!req.session.data.user.groups?.includes(adminGroupPath)) { throw new ForbiddenError('Vous n\'avez pas les droits administrateur') } done() diff --git a/apps/server/src/utils/keycloak.ts b/apps/server/src/utils/keycloak.ts index 5db6edc3b..79a094ce1 100644 --- a/apps/server/src/utils/keycloak.ts +++ b/apps/server/src/utils/keycloak.ts @@ -8,7 +8,14 @@ import { keycloakRedirectUri, } from './env.js' -const userPayloadMapper = (userPayload) => ({ +type KeycloakPayload = { + sub: string + email: string + given_name: string + family_name: string + groups: string[] +} +const userPayloadMapper = (userPayload: KeycloakPayload) => ({ id: userPayload.sub, email: userPayload.email, firstName: userPayload.given_name, @@ -22,8 +29,8 @@ export const keycloakConf = { clientId: keycloakClientId, clientSecret: keycloakClientSecret, useHttps: keycloakProtocol === 'https', - disableCookiePlugin: true, - disableSessionPlugin: true, + disableCookiePlugin: false, + disableSessionPlugin: false, userPayloadMapper, retries: 5, excludedPatterns: ['/api/v1/version', '/api/v1/healthz', '/api/v1/swagger-ui/**'], diff --git a/apps/server/src/utils/logger.ts b/apps/server/src/utils/logger.ts index cccf4361e..8de4d2ed0 100644 --- a/apps/server/src/utils/logger.ts +++ b/apps/server/src/utils/logger.ts @@ -1,4 +1,5 @@ -import { type FastifyRequestWithSession } from '@/types' +import { FastifyRequest } from 'fastify' + export const loggerConf = { development: { transport: { @@ -16,7 +17,7 @@ export const loggerConf = { } interface ReqLogsInput { - req: FastifyRequestWithSession; + req: FastifyRequest; error?: string | Error; description: string; extras?: Record @@ -29,8 +30,8 @@ export const addReqLogs = ({ req, error, description, extras }: ReqLogsInput) => const logInfos = { file: frame.split(' ')[6].split(':')[0].split('src/')[1], function: frame.split(' ')[5].split('.')[1], - requestorId: req.session?.user?.id, - requestorGroups: req.session?.user?.groups, + requestorId: req.session?.data?.user?.id, + requestorGroups: req.session?.data?.user?.groups, description, ...extras, } diff --git a/packages/shared/src/resources/cluster/openApiSchema.ts b/packages/shared/src/resources/cluster/openApiSchema.ts index 991013eea..85460ee48 100644 --- a/packages/shared/src/resources/cluster/openApiSchema.ts +++ b/packages/shared/src/resources/cluster/openApiSchema.ts @@ -118,6 +118,7 @@ export const getClustersSchema = { export const getClusterAssociatedEnvironmentsSchema = { description: 'Retrieve environments associated to a cluster', + params: clusterParamsSchema, tags: ['cluster', 'environment'], summary: 'Retrieve environments associated to a cluster, for admins only', response: { diff --git a/packages/shared/src/resources/project/openApiSchema.ts b/packages/shared/src/resources/project/openApiSchema.ts index 56d9b86c9..0b885e6f3 100644 --- a/packages/shared/src/resources/project/openApiSchema.ts +++ b/packages/shared/src/resources/project/openApiSchema.ts @@ -196,6 +196,22 @@ export const updateProjectSchema = { }, } as const +export const patchProjectSchema = { + description: 'Patch project (lock/unlock)', + tags: ['project'], + summary: 'Patch a project', + params: projectParamsSchema, + body: { + type: 'object', + properties: { + lock: { type: 'boolean' }, + }, + }, + response: { + 200: {}, + }, +} as const + export const archiveProjectSchema = { description: 'Archive a project', tags: ['project'], diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5506379af..3115dc383 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -178,9 +178,6 @@ importers: '@fastify/helmet': specifier: ^11.1.1 version: 11.1.1 - '@fastify/session': - specifier: ^10.6.1 - version: 10.6.1 '@fastify/swagger': specifier: ^8.12.0 version: 8.12.0 @@ -199,6 +196,9 @@ importers: '@kubernetes/client-node': specifier: ^0.20.0 version: 0.20.0 + '@mgcrea/fastify-session': + specifier: ^2.2.1 + version: 2.2.1 '@prisma/client': specifier: ^5.6.0 version: 5.6.0(prisma@5.6.0) @@ -217,6 +217,9 @@ importers: fastify-keycloak-adapter: specifier: ^2.1.6 version: 2.1.6 + json-schema-to-ts: + specifier: ^2.9.2 + version: 2.9.2 mustache: specifier: ^4.2.0 version: 4.2.0 @@ -316,7 +319,7 @@ importers: version: 0.34.6(@types/node@20.10.1) vitest: specifier: ^0.34.6 - version: 0.34.6 + version: 0.34.6(jsdom@22.1.0) packages/eslintconfig: dependencies: @@ -413,7 +416,7 @@ importers: version: 4.5.0(@types/node@20.8.9) vitest: specifier: ^0.34.6 - version: 0.34.6 + version: 0.34.6(jsdom@22.1.0) packages/test-utils: dependencies: @@ -2097,6 +2100,14 @@ packages: engines: {node: '>=8'} dev: false + /@mgcrea/fastify-session@2.2.1: + resolution: {integrity: sha512-6YX39E95Y+Ma8eT7MMS2YJZu0uRjJ+eHfouP3hB04lnKplgnfnpYO2YQpkfaT0YmU0XNZI6oWVqWTWVKDNSSIw==} + engines: {node: '>=14'} + dependencies: + fastify-plugin: 4.5.1 + nanoid: 3.3.5 + dev: false + /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -2617,7 +2628,6 @@ packages: /@tootallnate/once@2.0.0: resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} - dev: true /@tsconfig/node10@1.0.9: resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} @@ -3448,7 +3458,7 @@ packages: std-env: 3.3.3 test-exclude: 6.0.0 v8-to-istanbul: 9.1.0 - vitest: 0.34.6 + vitest: 0.34.6(jsdom@22.1.0) transitivePeerDependencies: - supports-color dev: true @@ -3656,7 +3666,6 @@ packages: /abab@2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} - dev: true /abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} @@ -3695,7 +3704,6 @@ packages: debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color - dev: true /aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} @@ -4235,7 +4243,7 @@ packages: normalize-path: 3.0.0 readdirp: 3.6.0 optionalDependencies: - fsevents: 2.3.2 + fsevents: 2.3.3 dev: true /chownr@2.0.0: @@ -4525,7 +4533,6 @@ packages: engines: {node: '>=14'} dependencies: rrweb-cssom: 0.6.0 - dev: true /csstype@3.1.2: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} @@ -4613,7 +4620,6 @@ packages: abab: 2.0.6 whatwg-mimetype: 3.0.0 whatwg-url: 12.0.1 - dev: true /date-fns@2.30.0: resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} @@ -4691,7 +4697,6 @@ packages: /decimal.js@10.4.3: resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} - dev: true /deep-eql@4.1.3: resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} @@ -4786,7 +4791,6 @@ packages: engines: {node: '>=12'} dependencies: webidl-conversions: 7.0.0 - dev: true /domhandler@5.0.3: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} @@ -4874,7 +4878,6 @@ packages: /entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} - dev: true /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} @@ -6013,14 +6016,6 @@ packages: /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - /fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: true - optional: true - /fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -6379,7 +6374,6 @@ packages: engines: {node: '>=12'} dependencies: whatwg-encoding: 2.0.0 - dev: true /html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -6419,7 +6413,6 @@ packages: debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color - dev: true /http-signature@1.2.0: resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==} @@ -6448,7 +6441,6 @@ packages: debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color - dev: true /human-signals@1.1.1: resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} @@ -6478,7 +6470,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: safer-buffer: 2.1.2 - dev: true /ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -6697,7 +6688,6 @@ packages: /is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - dev: true /is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} @@ -6924,7 +6914,6 @@ packages: - bufferutil - supports-color - utf-8-validate - dev: true /json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -7566,6 +7555,12 @@ packages: hasBin: true dev: false + /nanoid@3.3.5: + resolution: {integrity: sha512-nvgaJGpIANf4+VWJAaDGORQyMzhFkze8aXVdrHq+BaSvzfpOuponEysaVFKV/0Bca5V+3SBiDvRabEPbpalEBg==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: false + /nanoid@3.3.6: resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -7704,7 +7699,6 @@ packages: /nwsapi@2.2.6: resolution: {integrity: sha512-vSZ4miHQ4FojLjmz2+ux4B0/XA16jfwt/LBzIUftDpRd8tujHFkXjMyLwjS08fIZCzesj2z7gJukOKJwqebJAQ==} - dev: true /oauth-sign@0.9.0: resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} @@ -7926,7 +7920,6 @@ packages: resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} dependencies: entities: 4.5.0 - dev: true /path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} @@ -8611,7 +8604,7 @@ packages: engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true optionalDependencies: - fsevents: 2.3.2 + fsevents: 2.3.3 dev: true /rollup@4.6.1: @@ -8635,7 +8628,6 @@ packages: /rrweb-cssom@0.6.0: resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==} - dev: true /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -8689,7 +8681,6 @@ packages: engines: {node: '>=v12.22.7'} dependencies: xmlchars: 2.2.0 - dev: true /schemes@1.4.0: resolution: {integrity: sha512-ImFy9FbCsQlVgnE3TCWmLPCFnVzx0lHL/l+umHplDqAKd0dzFpnS6lFZIpagBlYhKwzVmlV36ec0Y1XTu8JBAQ==} @@ -9264,7 +9255,6 @@ packages: /symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - dev: true /tabbable@6.2.0: resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} @@ -9407,7 +9397,6 @@ packages: engines: {node: '>=14'} dependencies: punycode: 2.3.0 - dev: true /trim-newlines@3.0.1: resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} @@ -9865,42 +9854,6 @@ packages: - supports-color - terser - /vite@4.5.0(@types/node@20.10.1): - resolution: {integrity: sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==} - engines: {node: ^14.18.0 || >=16.0.0} - hasBin: true - peerDependencies: - '@types/node': '>= 14' - less: '*' - lightningcss: ^1.21.0 - sass: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - dependencies: - '@types/node': 20.10.1 - esbuild: 0.18.11 - postcss: 8.4.31 - rollup: 3.29.4 - optionalDependencies: - fsevents: 2.3.2 - dev: true - /vite@4.5.0(@types/node@20.8.9): resolution: {integrity: sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==} engines: {node: ^14.18.0 || >=16.0.0} @@ -9934,7 +9887,7 @@ packages: postcss: 8.4.31 rollup: 3.29.4 optionalDependencies: - fsevents: 2.3.2 + fsevents: 2.3.3 dev: true /vite@5.0.4(@types/node@20.10.1): @@ -9980,73 +9933,9 @@ packages: dependencies: ts-essentials: 9.3.2(typescript@5.3.2) typescript: 5.3.2 - vitest: 0.34.6 + vitest: 0.34.6(jsdom@22.1.0) dev: false - /vitest@0.34.6: - resolution: {integrity: sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==} - engines: {node: '>=v14.18.0'} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@vitest/browser': '*' - '@vitest/ui': '*' - happy-dom: '*' - jsdom: '*' - playwright: '*' - safaridriver: '*' - webdriverio: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - playwright: - optional: true - safaridriver: - optional: true - webdriverio: - optional: true - dependencies: - '@types/chai': 4.3.5 - '@types/chai-subset': 1.3.3 - '@types/node': 20.10.1 - '@vitest/expect': 0.34.6 - '@vitest/runner': 0.34.6 - '@vitest/snapshot': 0.34.6 - '@vitest/spy': 0.34.6 - '@vitest/utils': 0.34.6 - acorn: 8.10.0 - acorn-walk: 8.2.0 - cac: 6.7.14 - chai: 4.3.10 - debug: 4.3.4(supports-color@8.1.1) - local-pkg: 0.4.3 - magic-string: 0.30.3 - pathe: 1.1.1 - picocolors: 1.0.0 - std-env: 3.3.3 - strip-literal: 1.0.1 - tinybench: 2.5.0 - tinypool: 0.7.0 - vite: 5.0.4(@types/node@20.10.1) - vite-node: 0.34.6(@types/node@20.10.1) - why-is-node-running: 2.2.2 - transitivePeerDependencies: - - less - - lightningcss - - sass - - stylus - - sugarss - - supports-color - - terser - /vitest@0.34.6(jsdom@22.1.0): resolution: {integrity: sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==} engines: {node: '>=v14.18.0'} @@ -10100,7 +9989,7 @@ packages: strip-literal: 1.0.1 tinybench: 2.5.0 tinypool: 0.7.0 - vite: 4.5.0(@types/node@20.10.1) + vite: 5.0.4(@types/node@20.10.1) vite-node: 0.34.6(@types/node@20.10.1) why-is-node-running: 2.2.2 transitivePeerDependencies: @@ -10111,7 +10000,6 @@ packages: - sugarss - supports-color - terser - dev: true /vue-demi@0.12.5(vue@3.3.7): resolution: {integrity: sha512-BREuTgTYlUr0zw0EZn3hnhC3I6gPWv+Kwh4MCih6QcAeaTlaIX0DwOVN0wHej7hSvDPecz4jygy/idsgKfW58Q==} @@ -10218,7 +10106,6 @@ packages: engines: {node: '>=14'} dependencies: xml-name-validator: 4.0.0 - dev: true /wait-on@7.0.1(debug@4.3.4): resolution: {integrity: sha512-9AnJE9qTjRQOlTZIldAaf/da2eW0eSRSgcqq85mXQja/DW3MriHxkpODDSUEg+Gri/rKEcXUZHe+cevvYItaog==} @@ -10237,19 +10124,16 @@ packages: /webidl-conversions@7.0.0: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} - dev: true /whatwg-encoding@2.0.0: resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} engines: {node: '>=12'} dependencies: iconv-lite: 0.6.3 - dev: true /whatwg-mimetype@3.0.0: resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} engines: {node: '>=12'} - dev: true /whatwg-url@12.0.1: resolution: {integrity: sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==} @@ -10257,7 +10141,6 @@ packages: dependencies: tr46: 4.1.1 webidl-conversions: 7.0.0 - dev: true /which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} @@ -10374,11 +10257,9 @@ packages: /xml-name-validator@4.0.0: resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} engines: {node: '>=12'} - dev: true /xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - dev: true /xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} From 539dc299e7a93fcf2b87be245ac2ddaf47d97ea8 Mon Sep 17 00:00:00 2001 From: ArnaudTa <33383276+ArnaudTA@users.noreply.github.com> Date: Thu, 28 Dec 2023 02:14:47 +0100 Subject: [PATCH 02/25] refactor: :rewind: revert fastify/session --- apps/server/package.json | 2 +- apps/server/src/__mocks__/app.ts | 4 +-- apps/server/src/app.ts | 2 +- .../resources/cluster/admin/controllers.ts | 4 +-- .../src/resources/cluster/controllers.ts | 2 +- .../src/resources/environment/business.ts | 4 +-- .../src/resources/environment/controllers.ts | 8 +++--- .../organization/admin/controllers.ts | 2 +- .../src/resources/organization/business.ts | 4 +-- .../src/resources/organization/controllers.ts | 2 +- .../src/resources/permission/controllers.ts | 8 +++--- .../src/resources/project/controllers.ts | 12 ++++----- .../server/src/resources/quota/controllers.ts | 2 +- .../src/resources/repository/controllers.ts | 10 +++---- apps/server/src/resources/service/business.ts | 4 +-- .../src/resources/service/controllers.ts | 2 +- .../server/src/resources/stage/controllers.ts | 2 +- apps/server/src/resources/user/controllers.ts | 10 +++---- apps/server/src/types/index.ts | 4 +-- apps/server/src/utils/controller.ts | 2 +- apps/server/src/utils/keycloak.ts | 4 +-- apps/server/src/utils/logger.ts | 4 +-- ci/kind/run.sh | 6 ++++- .../src/resources/quota/openApiSchema.ts | 1 + pnpm-lock.yaml | 26 +++++-------------- 25 files changed, 61 insertions(+), 70 deletions(-) diff --git a/apps/server/package.json b/apps/server/package.json index aea63fada..8c218dd92 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -3,13 +3,13 @@ "@dso-console/shared": "workspace:*", "@fastify/cookie": "^9.2.0", "@fastify/helmet": "^11.1.1", + "@fastify/session": "^10.7.0", "@fastify/swagger": "^8.12.0", "@fastify/swagger-ui": "^1.10.1", "@gitbeaker/core": "^39.25.0", "@gitbeaker/rest": "^39.25.0", "@keycloak/keycloak-admin-client": "^23.0.1", "@kubernetes/client-node": "^0.20.0", - "@mgcrea/fastify-session": "^2.2.1", "@prisma/client": "^5.6.0", "axios": "^1.6.2", "date-fns": "^2.30.0", diff --git a/apps/server/src/__mocks__/app.ts b/apps/server/src/__mocks__/app.ts index dc8b564ed..3c11075e5 100644 --- a/apps/server/src/__mocks__/app.ts +++ b/apps/server/src/__mocks__/app.ts @@ -1,7 +1,7 @@ import { vi } from 'vitest' import fastify from 'fastify' import fastifyCookie from '@fastify/cookie' -import fastifySession from '@mgcrea/fastify-session' +import fastifySession from '@fastify/session' import fp from 'fastify-plugin' import { addAllSchemasToApp, apiPrefix } from '@/app.js' import { apiRouter, miscRouter } from '@/resources/index.js' @@ -129,7 +129,7 @@ export const getRequestor = () => { const mockSessionPlugin = (app, opt, next) => { app.addHook('onRequest', (req, res, next) => { - req.session = { data: { user: getRequestor() } } + req.session = { user: getRequestor() } next() }) next() diff --git a/apps/server/src/app.ts b/apps/server/src/app.ts index 1e68311ce..f894063a6 100644 --- a/apps/server/src/app.ts +++ b/apps/server/src/app.ts @@ -1,7 +1,7 @@ import fastify, { type FastifyInstance, type FastifyRequest } from 'fastify' import helmet from '@fastify/helmet' import keycloak from 'fastify-keycloak-adapter' -import fastifySession from '@mgcrea/fastify-session' +import fastifySession from '@fastify/session' import fastifyCookie from '@fastify/cookie' import fastifySwagger from '@fastify/swagger' import fastifySwaggerUi from '@fastify/swagger-ui' diff --git a/apps/server/src/resources/cluster/admin/controllers.ts b/apps/server/src/resources/cluster/admin/controllers.ts index 9ca274640..c849c2001 100644 --- a/apps/server/src/resources/cluster/admin/controllers.ts +++ b/apps/server/src/resources/cluster/admin/controllers.ts @@ -45,7 +45,7 @@ const router = async (app: FastifyInstance, _opt) => { }, async (req, res) => { const data = req.body - const userId = req.session.data.user.id + const userId = req.session.user.id data.projectIds = checkClusterProjectIds(data) @@ -95,7 +95,7 @@ const router = async (app: FastifyInstance, _opt) => { }, async (req, res) => { const clusterId = req.params.clusterId - const userId = req.session.data.user.id + const userId = req.session.user.id await deleteCluster(clusterId, userId) diff --git a/apps/server/src/resources/cluster/controllers.ts b/apps/server/src/resources/cluster/controllers.ts index 9f6b2a534..0ea001512 100644 --- a/apps/server/src/resources/cluster/controllers.ts +++ b/apps/server/src/resources/cluster/controllers.ts @@ -12,7 +12,7 @@ const router = async (app: FastifyInstance, _opt) => { schema: getClustersSchema, }, async (req, res) => { - const user = req.session.data.user + const user = req.session.user const cleanedClusters = await getAllCleanedClusters(user) addReqLogs({ diff --git a/apps/server/src/resources/environment/business.ts b/apps/server/src/resources/environment/business.ts index 56380d57d..399ce62a5 100644 --- a/apps/server/src/resources/environment/business.ts +++ b/apps/server/src/resources/environment/business.ts @@ -31,7 +31,7 @@ import { projectRootDir } from '@/utils/env.js' import { getProjectInfosAndClusters } from '@/resources/project/business.js' import { gitlabUrl } from '@/plugins/core/gitlab/utils.js' import { type AsyncReturnType, adminGroupPath } from '@dso-console/shared' -import type { SessionData } from '@mgcrea/fastify-session' +import type { UserDetails } from '@/types/index.js' // Fetch infos export const getEnvironmentInfosAndClusters = async (environmentId: string) => { @@ -230,7 +230,7 @@ export const createEnvironment = async ( } type UpdateEnvironmentParam = { - user: SessionData['user'], + user: UserDetails, projectId: Project['id'], environmentId: Environment['id'], quotaStageId?: QuotaStage['id'], diff --git a/apps/server/src/resources/environment/controllers.ts b/apps/server/src/resources/environment/controllers.ts index 05c1eb145..63bbc9f94 100644 --- a/apps/server/src/resources/environment/controllers.ts +++ b/apps/server/src/resources/environment/controllers.ts @@ -30,7 +30,7 @@ const router = async (app: FastifyInstance, _opt) => { }, async (req, res) => { const environmentId = req.params.environmentId - const userId = req.session.data.user.id + const userId = req.session.user.id const projectId = req.params.projectId // appel business 1 : récup données @@ -63,7 +63,7 @@ const router = async (app: FastifyInstance, _opt) => { }, async (req, res) => { const data = req.body - const userId = req.session.data.user.id + const userId = req.session.user.id const projectId = req.params.projectId const environment = await createEnvironment({ @@ -96,7 +96,7 @@ const router = async (app: FastifyInstance, _opt) => { }, async (req, res) => { const data = req.body - const user = req.session.data.user + const user = req.session.user const { projectId, environmentId } = req.params const environment = await updateEnvironment({ @@ -129,7 +129,7 @@ const router = async (app: FastifyInstance, _opt) => { async (req, res) => { const environmentId = req.params.environmentId const projectId = req.params.projectId - const userId = req.session.data.user.id + const userId = req.session.user.id await deleteEnvironment({ userId, diff --git a/apps/server/src/resources/organization/admin/controllers.ts b/apps/server/src/resources/organization/admin/controllers.ts index 710354338..fda67ee19 100644 --- a/apps/server/src/resources/organization/admin/controllers.ts +++ b/apps/server/src/resources/organization/admin/controllers.ts @@ -48,7 +48,7 @@ const router = async (app: FastifyInstance, _opt) => { schema: fetchOrganizationsSchema, }, async (req: FastifyRequest, res) => { - const userId = req.session.data.user.id + const userId = req.session.user.id const consoleOrganizations = await fetchOrganizations(userId) diff --git a/apps/server/src/resources/organization/business.ts b/apps/server/src/resources/organization/business.ts index d53e8984d..26852916f 100644 --- a/apps/server/src/resources/organization/business.ts +++ b/apps/server/src/resources/organization/business.ts @@ -1,7 +1,7 @@ import { getOrCreateUser, getActiveOrganizationsQuery, getOrganizationById } from '@/resources/queries-index.js' +import { UserDetails } from '@/types/index.js' import { NotFoundError, UnauthorizedError } from '@/utils/errors.js' import { userSchema } from '@dso-console/shared' -import { SessionData } from '@mgcrea/fastify-session' // TODO 539 : à supprimer ? n'est pas utilisé export const getOrganizationInfos = async (organizationId: string) => { @@ -10,7 +10,7 @@ export const getOrganizationInfos = async (organizationId: string) => { return organization } -export const getActiveOrganizations = async (requestor: SessionData['user']) => { +export const getActiveOrganizations = async (requestor: UserDetails) => { await userSchema.validateAsync(requestor) const user = await getOrCreateUser(requestor) if (!user) throw new UnauthorizedError('Veuillez vous connecter') diff --git a/apps/server/src/resources/organization/controllers.ts b/apps/server/src/resources/organization/controllers.ts index dade264d8..425928edd 100644 --- a/apps/server/src/resources/organization/controllers.ts +++ b/apps/server/src/resources/organization/controllers.ts @@ -13,7 +13,7 @@ const router = async (app: FastifyInstance, _opt) => { schema: getActiveOrganizationsSchema, }, async (req, res) => { - const requestor = req.session.data.user + const requestor = req.session.user delete requestor.groups const organizations = await getActiveOrganizations(requestor) diff --git a/apps/server/src/resources/permission/controllers.ts b/apps/server/src/resources/permission/controllers.ts index 6db1b5bf1..a775ff7e1 100644 --- a/apps/server/src/resources/permission/controllers.ts +++ b/apps/server/src/resources/permission/controllers.ts @@ -15,7 +15,7 @@ const router = async (app: FastifyInstance, _opt) => { schema: getEnvironmentPermissionsSchema, }, async (req, res) => { - const userId = req.session.data.user.id + const userId = req.session.user.id const environmentId = req.params.environmentId const projectId = req.params.projectId @@ -41,7 +41,7 @@ const router = async (app: FastifyInstance, _opt) => { schema: setPermissionSchema, }, async (req, res) => { - const requestorId = req.session.data.user?.id + const requestorId = req.session.user?.id const environmentId = req.params.environmentId const projectId = req.params.projectId const data = req.body @@ -69,7 +69,7 @@ const router = async (app: FastifyInstance, _opt) => { schema: updatePermissionSchema, }, async (req, res) => { - const requestorId = req.session.data.user.id + const requestorId = req.session.user.id const environmentId = req.params.environmentId const projectId = req.params.projectId const data = req.body @@ -96,7 +96,7 @@ const router = async (app: FastifyInstance, _opt) => { schema: deletePermissionSchema, }, async (req, res) => { - const requestorId = req.session.data.user.id + const requestorId = req.session.user.id const environmentId = req.params.environmentId const projectId = req.params.projectId const userId = req.params.userId diff --git a/apps/server/src/resources/project/controllers.ts b/apps/server/src/resources/project/controllers.ts index 92066fc22..5e2267f11 100644 --- a/apps/server/src/resources/project/controllers.ts +++ b/apps/server/src/resources/project/controllers.ts @@ -36,7 +36,7 @@ const router = async (app: FastifyInstance, _opt) => { schema: getUserProjectsSchema, }, async (req, res) => { - const requestor = req.session.data.user + const requestor = req.session.user delete requestor.groups const projectsInfos = await getUserProjects(requestor) @@ -61,7 +61,7 @@ const router = async (app: FastifyInstance, _opt) => { }, async (req, res) => { const projectId = req.params.projectId - const userId = req.session.data.user.id + const userId = req.session.user.id const project = await getProject(projectId, userId) @@ -86,7 +86,7 @@ const router = async (app: FastifyInstance, _opt) => { // }, async (req, res) => { const projectId = req.params.projectId - const userId = req.session.data.user.id + const userId = req.session.user.id const projectSecrets = await getProjectSecrets(projectId, userId) @@ -109,7 +109,7 @@ const router = async (app: FastifyInstance, _opt) => { schema: createProjectSchema, }, async (req, res) => { - const requestor = req.session.data.user + const requestor = req.session.user delete requestor.groups const data = req.body @@ -133,7 +133,7 @@ const router = async (app: FastifyInstance, _opt) => { schema: updateProjectSchema, }, async (req, res) => { - const requestor = req.session.data.user + const requestor = req.session.user const projectId = req.params.projectId const data = req.body @@ -156,7 +156,7 @@ const router = async (app: FastifyInstance, _opt) => { schema: archiveProjectSchema, }, async (req, res) => { - const requestor = req.session.data.user + const requestor = req.session.user const projectId = req.params.projectId await archiveProject(projectId, requestor) diff --git a/apps/server/src/resources/quota/controllers.ts b/apps/server/src/resources/quota/controllers.ts index a45d661aa..2272d4da5 100644 --- a/apps/server/src/resources/quota/controllers.ts +++ b/apps/server/src/resources/quota/controllers.ts @@ -12,7 +12,7 @@ const router = async (app: FastifyInstance, _opt) => { schema: getQuotasSchema, }, async (req, res) => { - const user = req.session.data.user + const user = req.session.user const quotas = await getQuotas(user) addReqLogs({ diff --git a/apps/server/src/resources/repository/controllers.ts b/apps/server/src/resources/repository/controllers.ts index 843f9f588..5b3d62688 100644 --- a/apps/server/src/resources/repository/controllers.ts +++ b/apps/server/src/resources/repository/controllers.ts @@ -18,7 +18,7 @@ const router = async (app: FastifyInstance, _opt) => { async (req, res) => { const projectId = req.params.projectId const repositoryId = req.params.repositoryId - const userId = req.session.data.user.id + const userId = req.session.user.id const repository = await getRepositoryById(userId, projectId, repositoryId) @@ -42,7 +42,7 @@ const router = async (app: FastifyInstance, _opt) => { }, async (req, res) => { const projectId = req.params.projectId - const userId = req.session.data.user.id + const userId = req.session.user.id const repositories = await getProjectRepositories(userId, projectId) @@ -67,7 +67,7 @@ const router = async (app: FastifyInstance, _opt) => { }, async (req, res) => { const data = req.body - const userId = req.session.data.user.id + const userId = req.session.user.id const projectId = req.params.projectId const repo = await createRepository(projectId, data, userId) @@ -92,7 +92,7 @@ const router = async (app: FastifyInstance, _opt) => { schema: updateRepositorySchema, }, async (req, res) => { - const userId = req.session.data.user.id + const userId = req.session.user.id const projectId = req.params.projectId const repositoryId = req.params.repositoryId @@ -139,7 +139,7 @@ const router = async (app: FastifyInstance, _opt) => { async (req, res) => { const projectId = req.params.projectId const repositoryId = req.params.repositoryId - const userId = req.session.data.user.id + const userId = req.session.user.id await deleteRepository(projectId, repositoryId, userId) diff --git a/apps/server/src/resources/service/business.ts b/apps/server/src/resources/service/business.ts index 57e208f8a..bceca6b52 100644 --- a/apps/server/src/resources/service/business.ts +++ b/apps/server/src/resources/service/business.ts @@ -3,9 +3,9 @@ import { getOrCreateUser } from '../queries-index.js' import axios, { AxiosResponse } from 'axios' import { type ServiceInfos, servicesInfos } from '@/plugins/services.js' import { userSchema } from '@dso-console/shared' -import { SessionData } from '@mgcrea/fastify-session' +import { UserDetails } from '@/types/index.js' -export const checkServicesHealth = async (requestor: SessionData['user']) => { +export const checkServicesHealth = async (requestor: UserDetails) => { await userSchema.validateAsync(requestor) const user = await getOrCreateUser(requestor) if (!user) throw new ForbiddenError('Vous n\'avez pas accès à cette information') diff --git a/apps/server/src/resources/service/controllers.ts b/apps/server/src/resources/service/controllers.ts index 01c047be9..a0f5601c5 100644 --- a/apps/server/src/resources/service/controllers.ts +++ b/apps/server/src/resources/service/controllers.ts @@ -5,7 +5,7 @@ import type { FastifyInstance } from 'fastify' const router = async (app: FastifyInstance, _opt) => { app.get('/', async (req, res) => { - const requestor = req.session.data.user + const requestor = req.session.user delete requestor.groups const serviceData = await checkServicesHealth(requestor) diff --git a/apps/server/src/resources/stage/controllers.ts b/apps/server/src/resources/stage/controllers.ts index d58c04a4c..0678ed3b2 100644 --- a/apps/server/src/resources/stage/controllers.ts +++ b/apps/server/src/resources/stage/controllers.ts @@ -12,7 +12,7 @@ const router = async (app: FastifyInstance, _opt) => { schema: getStagesSchema, }, async (req, res) => { - const userId = req.session.data.user.id + const userId = req.session.user.id const stages = await getStages(userId) addReqLogs({ diff --git a/apps/server/src/resources/user/controllers.ts b/apps/server/src/resources/user/controllers.ts index 682099308..e68117a34 100644 --- a/apps/server/src/resources/user/controllers.ts +++ b/apps/server/src/resources/user/controllers.ts @@ -16,7 +16,7 @@ const router = async (app: FastifyInstance, _opt) => { schema: getProjectUsersSchema, }, async (req, res) => { - const user = req.session.data.user + const user = req.session.user const projectId = req.params.projectId const users = await getProjectUsers(projectId) @@ -44,7 +44,7 @@ const router = async (app: FastifyInstance, _opt) => { schema: getMatchingUsersSchema, }, async (req, res) => { - const user = req.session.data.user + const user = req.session.user const projectId = req.params.projectId const { letters } = req.query @@ -75,7 +75,7 @@ const router = async (app: FastifyInstance, _opt) => { schema: addUserToProjectSchema, }, async (req, res) => { - const user = req.session.data.user + const user = req.session.user const projectId = req.params.projectId const data = req.body @@ -110,7 +110,7 @@ const router = async (app: FastifyInstance, _opt) => { schema: updateUserProjectRoleSchema, }, async (req, res) => { - const user = req.session.data.user + const user = req.session.user const projectId = req.params.projectId const userToUpdateId = req.params.userId const data = req.body @@ -146,7 +146,7 @@ const router = async (app: FastifyInstance, _opt) => { schema: removeUserFromProjectSchema, }, async (req, res) => { - const user = req.session.data.user + const user = req.session.user const projectId = req.params.projectId const userToRemoveId = req.params.userId diff --git a/apps/server/src/types/index.ts b/apps/server/src/types/index.ts index 733f7ca36..61fbdd64c 100644 --- a/apps/server/src/types/index.ts +++ b/apps/server/src/types/index.ts @@ -11,8 +11,8 @@ export type UserDetails = { export type ClusterMix = Cluster & ClusterModel -declare module '@mgcrea/fastify-session' { - interface SessionData{ +declare module 'fastify' { + interface Session{ user: UserDetails } } diff --git a/apps/server/src/utils/controller.ts b/apps/server/src/utils/controller.ts index f59a24f48..a2f25046b 100644 --- a/apps/server/src/utils/controller.ts +++ b/apps/server/src/utils/controller.ts @@ -4,7 +4,7 @@ import { ForbiddenError } from './errors.js' import { FastifyRequest } from 'fastify' export const checkAdminGroup = (req: FastifyRequest, _res, done) => { - if (!req.session.data.user.groups?.includes(adminGroupPath)) { + if (!req.session.user.groups?.includes(adminGroupPath)) { throw new ForbiddenError('Vous n\'avez pas les droits administrateur') } done() diff --git a/apps/server/src/utils/keycloak.ts b/apps/server/src/utils/keycloak.ts index 79a094ce1..87ef95235 100644 --- a/apps/server/src/utils/keycloak.ts +++ b/apps/server/src/utils/keycloak.ts @@ -29,8 +29,8 @@ export const keycloakConf = { clientId: keycloakClientId, clientSecret: keycloakClientSecret, useHttps: keycloakProtocol === 'https', - disableCookiePlugin: false, - disableSessionPlugin: false, + disableCookiePlugin: true, + disableSessionPlugin: true, userPayloadMapper, retries: 5, excludedPatterns: ['/api/v1/version', '/api/v1/healthz', '/api/v1/swagger-ui/**'], diff --git a/apps/server/src/utils/logger.ts b/apps/server/src/utils/logger.ts index 8de4d2ed0..e6011d807 100644 --- a/apps/server/src/utils/logger.ts +++ b/apps/server/src/utils/logger.ts @@ -30,8 +30,8 @@ export const addReqLogs = ({ req, error, description, extras }: ReqLogsInput) => const logInfos = { file: frame.split(' ')[6].split(':')[0].split('src/')[1], function: frame.split(' ')[5].split('.')[1], - requestorId: req.session?.data?.user?.id, - requestorGroups: req.session?.data?.user?.groups, + requestorId: req.session?.user?.id, + requestorGroups: req.session?.user?.groups, description, ...extras, } diff --git a/ci/kind/run.sh b/ci/kind/run.sh index f3920fd76..fba81b4b5 100755 --- a/ci/kind/run.sh +++ b/ci/kind/run.sh @@ -144,8 +144,12 @@ fi # Load images into cluster nodes if [[ "$COMMAND" =~ "load" ]]; then wait $JOB_CREATE + wait -f $JOB_CREATE $JOB_BUILD source ./ci/kind/run-load.sh & JOB_LOAD="$!" + if [[ "$COMMAND" == *load ]]; then + wait $JOB_LOAD + fi fi @@ -174,7 +178,7 @@ fi # Deploy application in dev or test mode if [[ "$COMMAND" =~ "dev" ]]; then - wait $JOB_LOAD + wait $JOB_LOAD -f printf "\n\n${red}[kind wrapper].${no_color} Deploy application in development mode\n\n" helm --kube-context kind-kind upgrade \ diff --git a/packages/shared/src/resources/quota/openApiSchema.ts b/packages/shared/src/resources/quota/openApiSchema.ts index 6c2e8eb9b..da263fc3f 100644 --- a/packages/shared/src/resources/quota/openApiSchema.ts +++ b/packages/shared/src/resources/quota/openApiSchema.ts @@ -159,6 +159,7 @@ export const createQuotaSchema = { export const updateQuotaPrivacySchema = { description: 'Update a quota\'s privacy', tags: ['quota'], + params: quotaParamsSchema, summary: 'Update a quota\'s privacy, admin only', body: { type: 'object', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3115dc383..ee00188c4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -178,6 +178,9 @@ importers: '@fastify/helmet': specifier: ^11.1.1 version: 11.1.1 + '@fastify/session': + specifier: ^10.7.0 + version: 10.7.0 '@fastify/swagger': specifier: ^8.12.0 version: 8.12.0 @@ -196,9 +199,6 @@ importers: '@kubernetes/client-node': specifier: ^0.20.0 version: 0.20.0 - '@mgcrea/fastify-session': - specifier: ^2.2.1 - version: 2.2.1 '@prisma/client': specifier: ^5.6.0 version: 5.6.0(prisma@5.6.0) @@ -1799,8 +1799,8 @@ packages: mime: 3.0.0 dev: false - /@fastify/session@10.6.1: - resolution: {integrity: sha512-S8qonAVTyF1h9+b8Ht76DhrFRERUO3wGBPBXDt2BFnteuJjcnEJVSqhhvOv1CpnbpJjmsyfgBpTOLcPWRNmjyg==} + /@fastify/session@10.7.0: + resolution: {integrity: sha512-ECA75gnyaxcyIukgyO2NGT3XdbLReNl/pTKrrkRfDc6pVqNtdptwwfx9KXrIMOfsO4B3m84eF3wZ9GgnebiZ4w==} dependencies: fastify-plugin: 4.5.1 safe-stable-stringify: 2.4.3 @@ -2100,14 +2100,6 @@ packages: engines: {node: '>=8'} dev: false - /@mgcrea/fastify-session@2.2.1: - resolution: {integrity: sha512-6YX39E95Y+Ma8eT7MMS2YJZu0uRjJ+eHfouP3hB04lnKplgnfnpYO2YQpkfaT0YmU0XNZI6oWVqWTWVKDNSSIw==} - engines: {node: '>=14'} - dependencies: - fastify-plugin: 4.5.1 - nanoid: 3.3.5 - dev: false - /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -5777,7 +5769,7 @@ packages: dependencies: '@fastify/cookie': 9.2.0 '@fastify/jwt': 7.2.4 - '@fastify/session': 10.6.1 + '@fastify/session': 10.7.0 axios: 1.6.2 axios-retry: 3.9.1 fastify-plugin: 4.5.1 @@ -7555,12 +7547,6 @@ packages: hasBin: true dev: false - /nanoid@3.3.5: - resolution: {integrity: sha512-nvgaJGpIANf4+VWJAaDGORQyMzhFkze8aXVdrHq+BaSvzfpOuponEysaVFKV/0Bca5V+3SBiDvRabEPbpalEBg==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - dev: false - /nanoid@3.3.6: resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} From cb38e7573314ba0980c4161d1a77a9e83fddb236 Mon Sep 17 00:00:00 2001 From: clairenollet Date: Tue, 2 Jan 2024 16:40:05 +0100 Subject: [PATCH 03/25] feat: :sparkles: download projects data button for admins --- .../cypress/e2e/specs/admin/projects.e2e.ts | 14 +++++ apps/client/src/api/api.ts | 5 ++ apps/client/src/components/CIForm.vue | 1 + apps/client/src/components/PermissionForm.vue | 2 - apps/client/src/icons.ts | 1 + apps/client/src/router/index.ts | 1 - apps/client/src/stores/admin/project.ts | 5 ++ apps/client/src/views/CreateProject.vue | 2 - apps/client/src/views/admin/ListClusters.vue | 2 - apps/client/src/views/admin/ListProjects.vue | 44 ++++++++++++++++ apps/client/src/views/admin/ListQuotas.vue | 2 - apps/client/src/views/admin/ListStages.vue | 2 - apps/client/src/views/admin/ListUser.vue | 3 -- .../client/src/views/projects/DsoProjects.vue | 2 - apps/client/src/views/projects/DsoRepos.vue | 2 - .../src/views/projects/ManageEnvironments.vue | 2 - apps/server/package.json | 1 + .../src/resources/project/admin/business.ts | 15 +++++- .../project/admin/controllers.spec.ts | 18 +++++++ .../resources/project/admin/controllers.ts | 19 ++++++- apps/server/src/resources/project/queries.ts | 51 +++++++++++++++++++ .../src/resources/project/openApiSchema.ts | 11 ++++ pnpm-lock.yaml | 40 +++++++++++---- 23 files changed, 212 insertions(+), 33 deletions(-) diff --git a/apps/client/cypress/e2e/specs/admin/projects.e2e.ts b/apps/client/cypress/e2e/specs/admin/projects.e2e.ts index cf91e203b..782cce587 100644 --- a/apps/client/cypress/e2e/specs/admin/projects.e2e.ts +++ b/apps/client/cypress/e2e/specs/admin/projects.e2e.ts @@ -270,4 +270,18 @@ describe('Administration projects', () => { cy.get(`td[title="retirer ${user.email} du projet"]`) .should('exist') }) + + it('Should download projects informations, loggedIn as admin', () => { + cy.visit('/admin/projects') + cy.url().should('contain', '/admin/projects') + cy.get('.fr-link--download').should('not.exist') + cy.getByDataTestid('download-btn') + .click() + cy.get('.fr-link--download').should('exist') + .click() + .find('span').should(($span) => { + const text = $span.text() + expect(text).to.match(/CSV – \d* bytes/) + }) + }) }) diff --git a/apps/client/src/api/api.ts b/apps/client/src/api/api.ts index d713f72e8..09a0e5f85 100644 --- a/apps/client/src/api/api.ts +++ b/apps/client/src/api/api.ts @@ -232,6 +232,11 @@ export const handleProjectLocking = async (projectId: string, lock: boolean) => return response.data } +export const generateProjectsData = async () => { + const response = await apiClient.get('/admin/projects/data') + return response.data +} + // Admin - Logs export const getAllLogs = async ({ offset, limit }: AdminLogsQuery) => { const response = await apiClient.get(`/admin/logs?offset=${offset}&limit=${limit}`) diff --git a/apps/client/src/components/CIForm.vue b/apps/client/src/components/CIForm.vue index a9f7d9c45..4c3793fef 100644 --- a/apps/client/src/components/CIForm.vue +++ b/apps/client/src/components/CIForm.vue @@ -231,6 +231,7 @@ watch(internalRepoName, (internalRepoName) => { :size="file.size" :href="file.href" :title="file.title" + :download="file.title" /> | undefined> = ref(props.environment) const permissions = ref([]) const permissionToUpdate = ref({}) diff --git a/apps/client/src/icons.ts b/apps/client/src/icons.ts index bff20b062..506c509be 100644 --- a/apps/client/src/icons.ts +++ b/apps/client/src/icons.ts @@ -50,4 +50,5 @@ export { RiSoundModuleLine, RiStockLine, RiArrowGoBackLine, + RiFileDownloadLine, } from 'oh-vue-icons/icons/ri/index.js' diff --git a/apps/client/src/router/index.ts b/apps/client/src/router/index.ts index ce25005c8..c6b23b4f6 100644 --- a/apps/client/src/router/index.ts +++ b/apps/client/src/router/index.ts @@ -231,7 +231,6 @@ router.beforeEach(async (to, _from, next) => { * On reload on projects views, retrieve projectId from url and send it to store */ router.beforeEach(async (to, _from, next) => { - const snackbarStore = useSnackbarStore() const projectStore = useProjectStore() const projectsPath = '/projects/' diff --git a/apps/client/src/stores/admin/project.ts b/apps/client/src/stores/admin/project.ts index f0579cc4f..b97c44c42 100644 --- a/apps/client/src/stores/admin/project.ts +++ b/apps/client/src/stores/admin/project.ts @@ -19,10 +19,15 @@ export const useAdminProjectStore = defineStore('admin-project', () => { return api.archiveProject(projectId) } + const generateProjectsData = async () => { + return api.generateProjectsData() + } + return { getAllProjects, getAllActiveProjects, handleProjectLocking, archiveProject, + generateProjectsData, } }) diff --git a/apps/client/src/views/CreateProject.vue b/apps/client/src/views/CreateProject.vue index b62cc9105..bc5c80e49 100644 --- a/apps/client/src/views/CreateProject.vue +++ b/apps/client/src/views/CreateProject.vue @@ -2,7 +2,6 @@ import { computed, onMounted, ref, type Ref } from 'vue' import { useProjectStore } from '@/stores/project.js' import { useUserStore } from '@/stores/user.js' -import { useSnackbarStore } from '@/stores/snackbar.js' import { useOrganizationStore } from '@/stores/organization.js' import { descriptionMaxLength, @@ -17,7 +16,6 @@ import router from '@/router/index.js' import LoadingCt from '@/components/LoadingCt.vue' import { handleError } from '@/utils/func.js' -const snackbarStore = useSnackbarStore() const projectStore = useProjectStore() const userStore = useUserStore() const organizationStore = useOrganizationStore() diff --git a/apps/client/src/views/admin/ListClusters.vue b/apps/client/src/views/admin/ListClusters.vue index 12ebf4138..7252ef522 100644 --- a/apps/client/src/views/admin/ListClusters.vue +++ b/apps/client/src/views/admin/ListClusters.vue @@ -1,6 +1,5 @@