Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Referentiel score #3332

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions backend/jest-e2e.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* eslint-disable */
export default {
displayName: 'backend-e2e',
preset: '../jest.preset.js',
rootDir: '.',
testEnvironment: 'node',
testMatch: ['**/*/*.e2e-spec.ts'],
transform: {
'^.+\\.(t|j)s$': [
'ts-jest',
{ tsconfig: '<rootDir>/tsconfig.spec-e2e.json' },
],
},
coverageDirectory: '../coverage/backend-e2e',
};
4 changes: 2 additions & 2 deletions backend/jest.config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/* eslint-disable */
export default {
displayName: 'my-nest-app',
displayName: 'backend',
preset: '../jest.preset.js',
testEnvironment: 'node',
transform: {
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../coverage/my-nest-app',
coverageDirectory: '../coverage/backend',
};
7 changes: 7 additions & 0 deletions backend/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@
"options": {
"jestConfig": "backend/jest.config.ts"
}
},
"test-e2e": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "backend/jest-e2e.config.ts"
}
}
}
}
4 changes: 4 additions & 0 deletions backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { CollectivitesModule } from './collectivites/collectivites.module';
import { CommonModule } from './common/common.module';
import { validateBackendConfiguration } from './common/services/backend-configuration.service';
import { IndicateursModule } from './indicateurs/indicateurs.module';
import { PersonnalisationsModule } from './personnalisations/personnalisations.module';
import { ReferentielsModule } from './referentiels/referentiels.module';
import { SheetModule } from './spreadsheets/sheet.module';
import { TrpcRouter } from './trpc.router';
import { TrpcModule } from './trpc/trpc.module';
Expand All @@ -21,6 +23,8 @@ import { TrpcModule } from './trpc/trpc.module';
CollectivitesModule,
IndicateursModule,
AuthModule,
PersonnalisationsModule,
ReferentielsModule,
],
controllers: [],
exports: [TrpcRouter],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Reflector } from '@nestjs/core';

export const AllowAnonymousAccess = Reflector.createDecorator<boolean>();
3 changes: 3 additions & 0 deletions backend/src/auth/decorators/allow-public-access.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Reflector } from '@nestjs/core';

export const AllowPublicAccess = Reflector.createDecorator<boolean>();
3 changes: 0 additions & 3 deletions backend/src/auth/decorators/public-endpoint.decorator.ts

This file was deleted.

28 changes: 19 additions & 9 deletions backend/src/auth/guards/auth.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';
import BackendConfigurationService from '../../common/services/backend-configuration.service';
import { getErrorMessage } from '../../common/services/errors.helper';
import { PublicEndpoint } from '../decorators/public-endpoint.decorator';
import { AllowAnonymousAccess } from '../decorators/allow-anonymous-access.decorator';
import { AllowPublicAccess } from '../decorators/allow-public-access.decorator';
import { SupabaseJwtPayload } from '../models/auth.models';

@Injectable()
Expand All @@ -19,18 +20,18 @@ export class AuthGuard implements CanActivate {
constructor(
private jwtService: JwtService,
private reflector: Reflector,
private backendConfigurationService: BackendConfigurationService,
private backendConfigurationService: BackendConfigurationService
) {}

async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();

const publicEndpoint = this.reflector.get(
PublicEndpoint,
context.getHandler(),
const allowPublicAccess = this.reflector.get(
AllowPublicAccess,
context.getHandler()
);

if (publicEndpoint) {
if (allowPublicAccess) {
this.logger.log(`Public endpoint`);
return true;
}
Expand All @@ -46,15 +47,24 @@ export class AuthGuard implements CanActivate {
secret:
this.backendConfigurationService.getBackendConfiguration()
.SUPABASE_JWT_SECRET,
},
}
);
// 💡 We're assigning the payload to the request object here
// so that we can access it in our route handlers
request['tokenInfo'] = payload;
this.logger.log(`Token validated for user ${payload.sub}`);
if (payload.is_anonymous) {
this.logger.error(`Anonymous user is not allowed`);
throw new UnauthorizedException();
const allowAnonymousAccess = this.reflector.get(
AllowAnonymousAccess,
context.getHandler()
);
if (allowAnonymousAccess) {
this.logger.log(`Anonymous user is allowed`);
return true;
} else {
this.logger.error(`Anonymous user is not allowed`);
throw new UnauthorizedException();
}
}
} catch (err) {
this.logger.error(`Failed to validate token: ${getErrorMessage(err)}`);
Expand Down
3 changes: 2 additions & 1 deletion backend/src/collectivites/collectivites.module.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { Module } from '@nestjs/common';
import { CommonModule } from '../common/common.module';
import { CollectiviteController } from './controllers/collectivite.controller';
import CollectivitesService from './services/collectivites.service';
import GroupementsService from './services/groupements.service';

@Module({
imports: [CommonModule],
providers: [CollectivitesService, GroupementsService],
exports: [CollectivitesService, GroupementsService],
controllers: [],
controllers: [CollectiviteController],
})
export class CollectivitesModule {}
24 changes: 24 additions & 0 deletions backend/src/collectivites/controllers/collectivite.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Controller, Get, Param } from '@nestjs/common';
import { ApiOkResponse } from '@nestjs/swagger';
import { AllowPublicAccess } from '../../auth/decorators/allow-public-access.decorator';
import CollectivitesService from '../services/collectivites.service';

/**
* Création des classes de réponse à partir du schema pour générer automatiquement la documentation OpenAPI
*/
//export class VersionResponseClass extends createZodDto(versionResponseSchema) {}

@Controller()
export class CollectiviteController {
constructor(private readonly collectiviteService: CollectivitesService) {}

@AllowPublicAccess()
@Get('collectivites/:collectivite_id')
@ApiOkResponse({
//type: VersionResponseClass,
description: "Récupération des informations d'une collectivite",
})
async getCollectivite(@Param('collectivite_id') collectiviteId: number) {
return this.collectiviteService.getCollectivite(collectiviteId);
}
}
88 changes: 88 additions & 0 deletions backend/src/collectivites/models/collectivite.models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
boolean,
integer,
pgEnum,
pgSchema,
pgTable,
serial,
timestamp,
Expand All @@ -13,6 +14,15 @@ import { createInsertSchema, createSelectSchema } from 'drizzle-zod';
// TODO: create domain siren as varchar(9) check ( value ~ '^\d{9}$' );
// TODO: create domain codegeo as varchar(5);

export enum CollectiviteTypeEnum {
EPCI = 'EPCI',
COMMUNE = 'commune',
}

export enum CollectiviteSousTypeEnum {
SYNDICAT = 'syndicat',
}

export const epciNatureEnum = pgEnum('nature', [
'SMF',
'CU',
Expand Down Expand Up @@ -66,3 +76,81 @@ export const communeTable = pgTable('commune', {
});
export type CommuneType = InferSelectModel<typeof communeTable>;
export type CreateCommuneType = InferInsertModel<typeof communeTable>;

export type CollectiviteAvecType = Omit<
CollectiviteType &
Partial<CommuneType> &
Partial<EpciType> & {
type: CollectiviteTypeEnum;
soustype: CollectiviteSousTypeEnum | null;
population_tags: CollectivitePopulationTypeEnum[];
drom: boolean;
},
'collectivite_id'
>;

export enum CollectivitePopulationTypeEnum {
MOINS_DE_5000 = 'moins_de_5000',
MOINS_DE_10000 = 'moins_de_10000',
MOINS_DE_20000 = 'moins_de_20000',
MOINS_DE_50000 = 'moins_de_50000',
MOINS_DE_100000 = 'moins_de_100000',
PLUS_DE_20000 = 'plus_de_20000',
PLUS_DE_100000 = 'plus_de_100000',
}
export const typePopulationEnum = pgEnum('type_population', [
CollectivitePopulationTypeEnum.MOINS_DE_5000,
CollectivitePopulationTypeEnum.MOINS_DE_10000,
CollectivitePopulationTypeEnum.MOINS_DE_20000,
CollectivitePopulationTypeEnum.MOINS_DE_50000,
CollectivitePopulationTypeEnum.MOINS_DE_100000,
CollectivitePopulationTypeEnum.PLUS_DE_20000,
CollectivitePopulationTypeEnum.PLUS_DE_100000,
]);

export enum CollectiviteLocalisationTypeEnum {
DOM = 'DOM',
METROPOLE = 'Metropole',
}
export const typeLocalisationEnum = pgEnum('type_localisation', [
CollectiviteLocalisationTypeEnum.DOM,
CollectiviteLocalisationTypeEnum.METROPOLE,
]);

export interface IdentiteCollectivite {
type: CollectiviteTypeEnum;
soustype: CollectiviteSousTypeEnum | null;
population_tags: CollectivitePopulationTypeEnum[];
drom: boolean;
}

export const importsSchema = pgSchema('imports');

export const regionTable = importsSchema.table('region', {
code: varchar('code', { length: 2 }),
population: integer('population').notNull(),
libelle: varchar('libelle', { length: 30 }),
drom: boolean('drom').notNull(),
});
export type RegionType = InferSelectModel<typeof regionTable>;
export type CreateRegionType = InferInsertModel<typeof regionTable>;

export const banaticTable = importsSchema.table('banatic', {
siren: varchar('siren', { length: 9 }).primaryKey(),
libelle: varchar('libelle', { length: 250 }),
region_code: varchar('region_code', { length: 2 }),
departement_code: varchar('departement_code', { length: 3 }),
nature: epciNatureEnum('nature').notNull(),
population: integer('population').notNull(),
});

export type BanaticType = InferSelectModel<typeof banaticTable>;
export type CreateBanaticType = InferInsertModel<typeof banaticTable>;

export const importCommuneTable = importsSchema.table('commune', {
code: varchar('code', { length: 5 }).primaryKey(),
region_code: varchar('region_code', { length: 2 }),
departement_code: varchar('departement_code', { length: 3 }),
libelle: varchar('libelle', { length: 30 }),
population: integer('population').notNull(),
});
Loading
Loading