From 873dcf713a540c16fc60e95724f35c246f7dda8f Mon Sep 17 00:00:00 2001
From: "Yassine R."
Date: Wed, 22 Jan 2025 01:36:59 +0100
Subject: [PATCH 1/5] feat(frontend): add referrer
---
.../_common/model/usager/UsagerLight.type.ts | 1 +
.../1736291936636-auto-migration.ts | 20 +++++
.../entities/usager/UsagerTable.typeorm.ts | 3 +
.../usagers/controllers/agenda.controller.ts | 17 +---
.../src/usagers/dto/UsagerAyantDroitDto.ts | 1 +
.../dto/decision-form/create-usager.dto.ts | 13 +++
.../src/users/controllers/users.controller.ts | 1 +
.../src/usager/interfaces/Usager.interface.ts | 1 +
.../interfaces/UsagerDecision.interface.ts | 10 ++-
.../UsagerDecisionMotif.type.ts | 0
.../UsagerDecisionOrientation.type.ts | 0
.../UsagerDecisionStatut.type.ts | 0
.../common/src/usager/types/decision/index.ts | 4 +
packages/common/src/usager/types/index.ts | 4 +-
.../form/UsagerEtatCivilFormData.type.ts | 1 +
.../UserStructureProfile.type.ts | 1 +
.../frontend/src/app/app-routing.module.ts | 8 ++
.../components/login/login.component.html | 2 +-
.../edit-user/edit-user.component.html | 0
.../edit-user/edit-user.component.spec.ts | 0
.../edit-user/edit-user.component.ts | 64 ++++++++-------
.../register-user-admin.component.html | 0
.../register-user-admin.component.spec.ts | 0
.../register-user-admin.component.ts | 9 ++-
.../user-profil/user-profil.component.html | 0
.../user-profil/user-profil.component.spec.ts | 0
.../user-profil/user-profil.component.ts | 5 +-
.../manage-users-routing.module.ts | 26 ++++++
.../manage-users/manage-users.module.ts | 34 ++++++++
.../services/manage-users.service.spec.ts | 16 ++++
.../services/manage-users.service.ts | 79 +++++++++++++++++++
...display-etat-civil-decision.component.html | 7 ++
.../step-etat-civil.component.html | 16 ++++
.../step-etat-civil.component.ts | 4 +-
.../step-rdv/step-rdv.component.html | 4 +-
.../components/step-rdv/step-rdv.component.ts | 27 ++++---
.../services/usager-dossier.service.ts | 17 +---
.../display-etat-civil.component.html | 7 ++
.../etat-civil-parent-form.component.ts | 14 +++-
.../profil-etat-civil-form.component.html | 15 ++++
.../profil-etat-civil-form.component.ts | 4 +-
.../interfaces/UsagerFormModel.ts | 2 +
.../usager-shared/pipes/referrer-name.pipe.ts | 16 ++++
.../usager-shared/usager-shared.module.ts | 3 +
.../reset-password.component.ts | 2 +-
.../modules/users/services/users.service.ts | 57 +------------
.../app/modules/users/users-routing.module.ts | 11 +--
.../src/app/modules/users/users.module.ts | 17 +---
48 files changed, 368 insertions(+), 175 deletions(-)
create mode 100644 packages/backend/src/_migrations/1736291936636-auto-migration.ts
rename packages/common/src/usager/types/{ => decision}/UsagerDecisionMotif.type.ts (100%)
rename packages/common/src/usager/types/{ => decision}/UsagerDecisionOrientation.type.ts (100%)
rename packages/common/src/usager/types/{ => decision}/UsagerDecisionStatut.type.ts (100%)
create mode 100644 packages/common/src/usager/types/decision/index.ts
rename packages/frontend/src/app/modules/{users => manage-users}/components/edit-user/edit-user.component.html (100%)
rename packages/frontend/src/app/modules/{users => manage-users}/components/edit-user/edit-user.component.spec.ts (100%)
rename packages/frontend/src/app/modules/{users => manage-users}/components/edit-user/edit-user.component.ts (83%)
rename packages/frontend/src/app/modules/{users => manage-users}/components/register-user-admin/register-user-admin.component.html (100%)
rename packages/frontend/src/app/modules/{users => manage-users}/components/register-user-admin/register-user-admin.component.spec.ts (100%)
rename packages/frontend/src/app/modules/{users => manage-users}/components/register-user-admin/register-user-admin.component.ts (93%)
rename packages/frontend/src/app/modules/{users => manage-users}/components/user-profil/user-profil.component.html (100%)
rename packages/frontend/src/app/modules/{users => manage-users}/components/user-profil/user-profil.component.spec.ts (100%)
rename packages/frontend/src/app/modules/{users => manage-users}/components/user-profil/user-profil.component.ts (96%)
create mode 100644 packages/frontend/src/app/modules/manage-users/manage-users-routing.module.ts
create mode 100644 packages/frontend/src/app/modules/manage-users/manage-users.module.ts
create mode 100644 packages/frontend/src/app/modules/manage-users/services/manage-users.service.spec.ts
create mode 100644 packages/frontend/src/app/modules/manage-users/services/manage-users.service.ts
create mode 100644 packages/frontend/src/app/modules/usager-shared/pipes/referrer-name.pipe.ts
diff --git a/packages/backend/src/_common/model/usager/UsagerLight.type.ts b/packages/backend/src/_common/model/usager/UsagerLight.type.ts
index 1ccd901b2a..2e33f7c392 100644
--- a/packages/backend/src/_common/model/usager/UsagerLight.type.ts
+++ b/packages/backend/src/_common/model/usager/UsagerLight.type.ts
@@ -26,6 +26,7 @@ export type UsagerLight = AppEntity &
| "options"
| "historique"
| "ayantsDroits"
+ | "referrerId"
| "villeNaissance"
| "telephone"
| "import"
diff --git a/packages/backend/src/_migrations/1736291936636-auto-migration.ts b/packages/backend/src/_migrations/1736291936636-auto-migration.ts
new file mode 100644
index 0000000000..714062d277
--- /dev/null
+++ b/packages/backend/src/_migrations/1736291936636-auto-migration.ts
@@ -0,0 +1,20 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+import { domifaConfig } from "../config";
+
+export class AutoMigration1736291936636 implements MigrationInterface {
+ name = "AutoMigration1736291936636";
+
+ public async up(queryRunner: QueryRunner): Promise {
+ if (
+ domifaConfig().envId === "prod" ||
+ domifaConfig().envId === "preprod" ||
+ domifaConfig().envId === "local"
+ ) {
+ await queryRunner.query(`ALTER TABLE "usager" ADD "referrerId" integer`);
+ }
+ }
+
+ public async down(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`ALTER TABLE "usager" DROP COLUMN "referrerId"`);
+ }
+}
diff --git a/packages/backend/src/database/entities/usager/UsagerTable.typeorm.ts b/packages/backend/src/database/entities/usager/UsagerTable.typeorm.ts
index 362f67fb8f..54231b5005 100644
--- a/packages/backend/src/database/entities/usager/UsagerTable.typeorm.ts
+++ b/packages/backend/src/database/entities/usager/UsagerTable.typeorm.ts
@@ -123,6 +123,9 @@ export class UsagerTable
@Column({ type: "integer", default: 0 })
public etapeDemande!: number;
+ @Column({ type: "integer", default: null, nullable: true })
+ public referrerId!: number;
+
@Column({ type: "jsonb", nullable: true })
public rdv!: UsagerRdv | null;
diff --git a/packages/backend/src/usagers/controllers/agenda.controller.ts b/packages/backend/src/usagers/controllers/agenda.controller.ts
index e041c1eabb..a0b70f5ecd 100644
--- a/packages/backend/src/usagers/controllers/agenda.controller.ts
+++ b/packages/backend/src/usagers/controllers/agenda.controller.ts
@@ -23,10 +23,7 @@ import {
usagerRepository,
} from "../../database";
import { ExpressResponse } from "../../util/express";
-import {
- UserStructureAuthenticated,
- UserStructureProfile,
-} from "../../_common/model";
+import { UserStructureAuthenticated } from "../../_common/model";
import { RdvDto } from "../dto/decision-form/rdv.dto";
import { UsagersService } from "../services/usagers.service";
import { getUsagerNomComplet, Usager } from "@domifa/common";
@@ -39,18 +36,6 @@ import { usagerAppointmentCreatedEmailSender } from "../../modules/mails/service
export class AgendaController {
constructor(private readonly usagersService: UsagersService) {}
- @Get("users")
- @ApiOperation({ summary: "Liste des utilisateurs pour l'agenda" })
- @AllowUserStructureRoles("simple", "responsable", "admin")
- public getAllUsersForAgenda(
- @CurrentUser() currentUser: UserStructureAuthenticated
- ): Promise {
- return userStructureRepository.findVerifiedStructureUsersByRoles({
- structureId: currentUser.structureId,
- roles: ["admin", "simple", "responsable"],
- });
- }
-
@Get("")
@ApiOperation({ summary: "Liste des rendez-vous à venir" })
@AllowUserStructureRoles("simple", "responsable", "admin")
diff --git a/packages/backend/src/usagers/dto/UsagerAyantDroitDto.ts b/packages/backend/src/usagers/dto/UsagerAyantDroitDto.ts
index 4bd8304722..5113a9f1e3 100644
--- a/packages/backend/src/usagers/dto/UsagerAyantDroitDto.ts
+++ b/packages/backend/src/usagers/dto/UsagerAyantDroitDto.ts
@@ -51,6 +51,7 @@ export class UsagerAyantDroitDto {
example: "20/12/2002",
description: "Date de naissance de l'ayant-droit",
type: Date,
+ required: true,
})
@IsNotEmpty()
@IsDateString()
diff --git a/packages/backend/src/usagers/dto/decision-form/create-usager.dto.ts b/packages/backend/src/usagers/dto/decision-form/create-usager.dto.ts
index 9d164afbac..467b06e49a 100644
--- a/packages/backend/src/usagers/dto/decision-form/create-usager.dto.ts
+++ b/packages/backend/src/usagers/dto/decision-form/create-usager.dto.ts
@@ -19,6 +19,7 @@ import {
IsArray,
ValidateIf,
ValidateNested,
+ IsNumber,
} from "class-validator";
import {
Trim,
@@ -128,6 +129,8 @@ export class CreateUsagerDto {
public customRef!: string;
@ApiProperty({
+ required: false,
+ type: "string",
example: "test@test.fr",
description: "Email du domicilié",
})
@@ -137,6 +140,16 @@ export class CreateUsagerDto {
@LowerCaseTransform()
public email!: string;
+ @ApiProperty({
+ required: false,
+ example: 10,
+ type: Number,
+ description: "Id du référent",
+ })
+ @IsOptional()
+ @IsNumber()
+ public referrerId!: number;
+
@ApiProperty({
type: Object,
required: false,
diff --git a/packages/backend/src/users/controllers/users.controller.ts b/packages/backend/src/users/controllers/users.controller.ts
index 5ed07831fe..61c9b16836 100644
--- a/packages/backend/src/users/controllers/users.controller.ts
+++ b/packages/backend/src/users/controllers/users.controller.ts
@@ -58,6 +58,7 @@ export class UsersController {
},
select: {
uuid: true,
+ id: true,
role: true,
nom: true,
prenom: true,
diff --git a/packages/common/src/usager/interfaces/Usager.interface.ts b/packages/common/src/usager/interfaces/Usager.interface.ts
index eb280e4196..bd54cc3bd7 100644
--- a/packages/common/src/usager/interfaces/Usager.interface.ts
+++ b/packages/common/src/usager/interfaces/Usager.interface.ts
@@ -55,6 +55,7 @@ export interface Usager extends AppEntity {
numeroDistribution: string | null;
pinnedNote: UsagerPinnedNote;
+ referrerId?: number | null;
nbNotes?: number;
statusInfos?: any;
diff --git a/packages/common/src/usager/interfaces/UsagerDecision.interface.ts b/packages/common/src/usager/interfaces/UsagerDecision.interface.ts
index d1afd37d4a..27c36615e5 100644
--- a/packages/common/src/usager/interfaces/UsagerDecision.interface.ts
+++ b/packages/common/src/usager/interfaces/UsagerDecision.interface.ts
@@ -1,7 +1,9 @@
-import { type UsagerDecisionMotif } from "../types/UsagerDecisionMotif.type";
-import { type UsagerDecisionOrientation } from "../types/UsagerDecisionOrientation.type";
-import { type UsagerDecisionStatut } from "../types/UsagerDecisionStatut.type";
-import { type UsagerTypeDom } from "../types/UsagerTypeDom.type";
+import {
+ UsagerTypeDom,
+ UsagerDecisionStatut,
+ UsagerDecisionMotif,
+ UsagerDecisionOrientation,
+} from "../types";
export interface UsagerDecision {
uuid: string; // permet d'identifier une décision en cas de suppression de l'historique
diff --git a/packages/common/src/usager/types/UsagerDecisionMotif.type.ts b/packages/common/src/usager/types/decision/UsagerDecisionMotif.type.ts
similarity index 100%
rename from packages/common/src/usager/types/UsagerDecisionMotif.type.ts
rename to packages/common/src/usager/types/decision/UsagerDecisionMotif.type.ts
diff --git a/packages/common/src/usager/types/UsagerDecisionOrientation.type.ts b/packages/common/src/usager/types/decision/UsagerDecisionOrientation.type.ts
similarity index 100%
rename from packages/common/src/usager/types/UsagerDecisionOrientation.type.ts
rename to packages/common/src/usager/types/decision/UsagerDecisionOrientation.type.ts
diff --git a/packages/common/src/usager/types/UsagerDecisionStatut.type.ts b/packages/common/src/usager/types/decision/UsagerDecisionStatut.type.ts
similarity index 100%
rename from packages/common/src/usager/types/UsagerDecisionStatut.type.ts
rename to packages/common/src/usager/types/decision/UsagerDecisionStatut.type.ts
diff --git a/packages/common/src/usager/types/decision/index.ts b/packages/common/src/usager/types/decision/index.ts
new file mode 100644
index 0000000000..5faf15fd36
--- /dev/null
+++ b/packages/common/src/usager/types/decision/index.ts
@@ -0,0 +1,4 @@
+// @index('./*', f => `export * from '${f.path}'`)
+export * from "./UsagerDecisionMotif.type";
+export * from "./UsagerDecisionOrientation.type";
+export * from "./UsagerDecisionStatut.type";
diff --git a/packages/common/src/usager/types/index.ts b/packages/common/src/usager/types/index.ts
index bebb77bd97..23778fab8b 100644
--- a/packages/common/src/usager/types/index.ts
+++ b/packages/common/src/usager/types/index.ts
@@ -1,9 +1,7 @@
// @index('./*', f => `export * from '${f.path}'`)
export * from "./AyantDroitLienParente.type";
+export * from "./decision";
export * from "./entretien";
-export * from "./UsagerDecisionMotif.type";
-export * from "./UsagerDecisionOrientation.type";
-export * from "./UsagerDecisionStatut.type";
export * from "./UsagerImport.type";
export * from "./UsagerPinnedNote.type";
export * from "./UsagerSexe.type";
diff --git a/packages/frontend/src/_common/model/usager/form/UsagerEtatCivilFormData.type.ts b/packages/frontend/src/_common/model/usager/form/UsagerEtatCivilFormData.type.ts
index 3f432c2de8..0fbb4e9764 100644
--- a/packages/frontend/src/_common/model/usager/form/UsagerEtatCivilFormData.type.ts
+++ b/packages/frontend/src/_common/model/usager/form/UsagerEtatCivilFormData.type.ts
@@ -16,5 +16,6 @@ export type UsagerEtatCivilFormData = {
nationalite: string | null;
telephone: Telephone;
contactByPhone: boolean;
+ referrerId: number | null;
ayantsDroits: UsagerAyantDroit[];
};
diff --git a/packages/frontend/src/_common/model/user-structure/UserStructureProfile.type.ts b/packages/frontend/src/_common/model/user-structure/UserStructureProfile.type.ts
index 68ba84e260..431deff858 100644
--- a/packages/frontend/src/_common/model/user-structure/UserStructureProfile.type.ts
+++ b/packages/frontend/src/_common/model/user-structure/UserStructureProfile.type.ts
@@ -6,6 +6,7 @@ export type UserStructureProfile = Pick<
| "nom"
| "prenom"
| "role"
+ | "id"
| "verified"
| "uuid"
| "createdAt"
diff --git a/packages/frontend/src/app/app-routing.module.ts b/packages/frontend/src/app/app-routing.module.ts
index a5cfd8739d..ae1ef82b9e 100644
--- a/packages/frontend/src/app/app-routing.module.ts
+++ b/packages/frontend/src/app/app-routing.module.ts
@@ -71,6 +71,14 @@ export const routes: Routes = [
),
path: "manage",
},
+ {
+ canActivate: [AuthGuard],
+ loadChildren: () =>
+ import("./modules/manage-users/manage-users.module").then(
+ (m) => m.ManageUsersModule
+ ),
+ path: "manage-users",
+ },
{
canActivate: [AuthGuard, FacteurGuard],
loadChildren: () =>
diff --git a/packages/frontend/src/app/modules/general/components/login/login.component.html b/packages/frontend/src/app/modules/general/components/login/login.component.html
index aefedef41d..f5291146f9 100644
--- a/packages/frontend/src/app/modules/general/components/login/login.component.html
+++ b/packages/frontend/src/app/modules/general/components/login/login.component.html
@@ -143,7 +143,7 @@
+
+
+ Référent.e au sein de la structure
+
+ {{ usager.referrerId | referrerName }}
+
+
diff --git a/packages/frontend/src/app/modules/usager-dossier/components/step-etat-civil/step-etat-civil.component.html b/packages/frontend/src/app/modules/usager-dossier/components/step-etat-civil/step-etat-civil.component.html
index faac9424e2..f94eb0dc26 100644
--- a/packages/frontend/src/app/modules/usager-dossier/components/step-etat-civil/step-etat-civil.component.html
+++ b/packages/frontend/src/app/modules/usager-dossier/components/step-etat-civil/step-etat-civil.component.html
@@ -392,6 +392,22 @@
/>
Exemple : BP 102, TSA 11000
+
+
+
+
required
>
-
,
private readonly formBuilder: UntypedFormBuilder,
private readonly documentService: DocumentService,
- private readonly nbgDate: NgbDateCustomParserFormatter
+ private readonly nbgDate: NgbDateCustomParserFormatter,
+ private readonly manageUsersService: ManageUsersService
) {
super(
authService,
@@ -166,20 +171,19 @@ export class StepRdvComponent
);
this.rdvForm.controls.jourRdv.setValue(this.usager.rdv.jourRdv);
-
this.editRdv = this.usager.rdv.userId === null;
- this.subscription.add(
- this.usagerDossierService
- .getAllUsersForAgenda()
- .subscribe((users: UserStructure[]) => {
- this.agents = users;
+ this.subscription.add(
+ this.manageUsersService.users$.subscribe(
+ (users: UserStructureProfile[]) => {
+ this.users = users.filter((user) => user.role !== "facteur");
const userIdRdv = this.usager.rdv?.userId || this.me?.id;
this.rdvForm.controls.userId.setValue(userIdRdv, {
onlySelf: true,
});
- })
+ }
+ )
);
}
@@ -277,7 +281,6 @@ export class StepRdvComponent
}
const heureRdv = control.value.split(":");
-
const dateRdv: Date = setMinutes(
setHours(new Date(), heureRdv[0]),
heureRdv[1]
diff --git a/packages/frontend/src/app/modules/usager-dossier/services/usager-dossier.service.ts b/packages/frontend/src/app/modules/usager-dossier/services/usager-dossier.service.ts
index 07783e6e77..c55ba25aba 100644
--- a/packages/frontend/src/app/modules/usager-dossier/services/usager-dossier.service.ts
+++ b/packages/frontend/src/app/modules/usager-dossier/services/usager-dossier.service.ts
@@ -1,16 +1,15 @@
import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs";
-import { map, tap } from "rxjs/operators";
+import { tap } from "rxjs/operators";
import { environment } from "src/environments/environment";
import {
UsagerEtatCivilFormData,
UsagerLight,
} from "../../../../_common/model";
-import { userStructureBuilder } from "../../users/services";
import { Store } from "@ngrx/store";
-import { UserStructure, Usager } from "@domifa/common";
+import { Usager } from "@domifa/common";
import { usagerActions, UsagerState } from "../../../shared";
import { RdvForm } from "../types";
@@ -102,16 +101,4 @@ export class UsagerDossierService {
})
);
}
-
- public getAllUsersForAgenda(): Observable {
- return this.http.get(environment.apiUrl + "agenda/users").pipe(
- map((response) => {
- return Array.isArray(response)
- ? response.map((item) =>
- userStructureBuilder.buildUserStructure(item)
- )
- : [userStructureBuilder.buildUserStructure(response)];
- })
- );
- }
}
diff --git a/packages/frontend/src/app/modules/usager-profil/components/_general-section/display-etat-civil/display-etat-civil.component.html b/packages/frontend/src/app/modules/usager-profil/components/_general-section/display-etat-civil/display-etat-civil.component.html
index 6b38f2d35c..48ecf0b5bf 100644
--- a/packages/frontend/src/app/modules/usager-profil/components/_general-section/display-etat-civil/display-etat-civil.component.html
+++ b/packages/frontend/src/app/modules/usager-profil/components/_general-section/display-etat-civil/display-etat-civil.component.html
@@ -49,6 +49,13 @@
{{ usager.numeroDistribution || "Non renseigné" }}
+
+
+ Référent.e au sein de la structure
+
+ {{ usager.referrerId | referrerName }}
+
+
diff --git a/packages/frontend/src/app/modules/usager-shared/components/etat-civil-parent-form/etat-civil-parent-form.component.ts b/packages/frontend/src/app/modules/usager-shared/components/etat-civil-parent-form/etat-civil-parent-form.component.ts
index ffff0789d5..1fd7d6e833 100644
--- a/packages/frontend/src/app/modules/usager-shared/components/etat-civil-parent-form/etat-civil-parent-form.component.ts
+++ b/packages/frontend/src/app/modules/usager-shared/components/etat-civil-parent-form/etat-civil-parent-form.component.ts
@@ -34,6 +34,7 @@ import {
UsagerEtatCivilFormData,
UsagerFormAyantDroit,
PREFERRED_COUNTRIES,
+ UserStructureProfile,
} from "../../../../../_common/model";
import {
minDateToday,
@@ -62,6 +63,7 @@ import {
} from "@domifa/common";
import { COUNTRIES } from "@domifa/common";
import { languagesAutocomplete } from "../../utils/languages";
+import { ManageUsersService } from "../../../manage-users/services/manage-users.service";
@Component({
selector: "app-etat-civil-parent-form",
@@ -100,8 +102,8 @@ export class EtatCivilParentFormComponent implements OnDestroy {
});
public subscription = new Subscription();
-
public currentUserSubject$: Observable;
+ public users: UserStructureProfile[] = [];
@ViewChildren("adName")
public firstInputs!: QueryList;
@@ -117,7 +119,8 @@ export class EtatCivilParentFormComponent implements OnDestroy {
constructor(
protected readonly formBuilder: UntypedFormBuilder,
protected readonly authService: AuthService,
- protected readonly changeDetectorRef: ChangeDetectorRef
+ protected readonly changeDetectorRef: ChangeDetectorRef,
+ protected readonly manageUsersService: ManageUsersService
) {
this.submitted = false;
this.loading = false;
@@ -125,7 +128,7 @@ export class EtatCivilParentFormComponent implements OnDestroy {
this.minDateToday = minDateToday;
this.minDateNaissance = minDateNaissance;
this.maxDateNaissance = formatDateToNgb(new Date());
-
+ this.users = this.manageUsersService.users;
this.currentUserSubject$ = this.authService.currentUserSubject;
}
@@ -166,6 +169,7 @@ export class EtatCivilParentFormComponent implements OnDestroy {
],
sexe: [this.usager.sexe, Validators.required],
surnom: [this.usager.surnom, [Validators.maxLength(100)]],
+ referrerId: [this.usager.referrerId],
villeNaissance: [
this.usager.villeNaissance,
[Validators.required, NoWhiteSpaceValidator, Validators.maxLength(100)],
@@ -195,7 +199,6 @@ export class EtatCivilParentFormComponent implements OnDestroy {
this.updatePlaceHolder(this.usagerForm.value?.telephone?.countryCode);
}
- // Gestion des ayant-droits
public addAyantDroit(ayantDroit: AyantDroit = new AyantDroit()): void {
(this.usagerForm.controls.ayantsDroits as UntypedFormArray).push(
this.newAyantDroit(ayantDroit)
@@ -286,6 +289,9 @@ export class EtatCivilParentFormComponent implements OnDestroy {
email: formValue?.email.toLowerCase().trim() || null,
telephone,
numeroDistribution: formValue?.numeroDistribution || null,
+ referrerId: formValue?.referrerId
+ ? parseInt(formValue?.referrerId)
+ : null,
ayantsDroits,
contactByPhone: formValue?.contactByPhone,
dateNaissance: endOfDay(parseDateFromNgb(formValue.dateNaissance)),
diff --git a/packages/frontend/src/app/modules/usager-shared/components/profil-etat-civil-form/profil-etat-civil-form.component.html b/packages/frontend/src/app/modules/usager-shared/components/profil-etat-civil-form/profil-etat-civil-form.component.html
index 5027607fe8..87d1e4dd13 100644
--- a/packages/frontend/src/app/modules/usager-shared/components/profil-etat-civil-form/profil-etat-civil-form.component.html
+++ b/packages/frontend/src/app/modules/usager-shared/components/profil-etat-civil-form/profil-etat-civil-form.component.html
@@ -284,6 +284,21 @@
/>
Exemple : BP 102, TSA 11000
+
+
+
+
+
diff --git a/packages/frontend/src/app/modules/usager-shared/components/profil-etat-civil-form/profil-etat-civil-form.component.ts b/packages/frontend/src/app/modules/usager-shared/components/profil-etat-civil-form/profil-etat-civil-form.component.ts
index 141e9a9ecb..1940c28498 100644
--- a/packages/frontend/src/app/modules/usager-shared/components/profil-etat-civil-form/profil-etat-civil-form.component.ts
+++ b/packages/frontend/src/app/modules/usager-shared/components/profil-etat-civil-form/profil-etat-civil-form.component.ts
@@ -19,6 +19,7 @@ import { CustomToastService } from "src/app/modules/shared/services/custom-toast
import { UsagerFormModel } from "../../interfaces";
import { AuthService } from "../../../shared/services/auth.service";
+import { ManageUsersService } from "../../../manage-users/services/manage-users.service";
@Component({
selector: "app-profil-etat-civil-form",
@@ -38,10 +39,11 @@ export class ProfilEtatCivilFormComponent
public authService: AuthService,
public formBuilder: UntypedFormBuilder,
public changeDetectorRef: ChangeDetectorRef,
+ public manageUsersService: ManageUsersService,
private readonly toastService: CustomToastService,
private readonly etatCivilService: UsagerService
) {
- super(formBuilder, authService, changeDetectorRef);
+ super(formBuilder, authService, changeDetectorRef, manageUsersService);
this.displayContactDetails = false;
}
diff --git a/packages/frontend/src/app/modules/usager-shared/interfaces/UsagerFormModel.ts b/packages/frontend/src/app/modules/usager-shared/interfaces/UsagerFormModel.ts
index 709e9ecfb4..ea8c1cf86b 100644
--- a/packages/frontend/src/app/modules/usager-shared/interfaces/UsagerFormModel.ts
+++ b/packages/frontend/src/app/modules/usager-shared/interfaces/UsagerFormModel.ts
@@ -82,6 +82,7 @@ export class UsagerFormModel implements Usager {
public nationalite: string | null;
public nbNotes?: number = 0;
+ public referrerId?: number | null;
constructor(usager?: Usager) {
this.pinnedNote = usager?.pinnedNote || null;
@@ -94,6 +95,7 @@ export class UsagerFormModel implements Usager {
this.prenom = usager?.prenom || "";
this.langue = usager?.langue || "";
this.numeroDistribution = usager?.numeroDistribution || null;
+ this.referrerId = usager?.referrerId || null;
this.surnom = usager?.surnom || "";
this.dateNaissance = usager?.dateNaissance
diff --git a/packages/frontend/src/app/modules/usager-shared/pipes/referrer-name.pipe.ts b/packages/frontend/src/app/modules/usager-shared/pipes/referrer-name.pipe.ts
new file mode 100644
index 0000000000..a5e10184fb
--- /dev/null
+++ b/packages/frontend/src/app/modules/usager-shared/pipes/referrer-name.pipe.ts
@@ -0,0 +1,16 @@
+import { Pipe, PipeTransform } from "@angular/core";
+import { ManageUsersService } from "../../manage-users/services/manage-users.service";
+
+@Pipe({
+ name: "referrerName",
+})
+export class ReferrerNamePipe implements PipeTransform {
+ constructor(private manageUsersService: ManageUsersService) {}
+
+ transform(referrerId: number | null): string {
+ if (!referrerId) {
+ return "Aucun référent";
+ }
+ return this.manageUsersService.usersMap[referrerId] || "Aucun référent";
+ }
+}
diff --git a/packages/frontend/src/app/modules/usager-shared/usager-shared.module.ts b/packages/frontend/src/app/modules/usager-shared/usager-shared.module.ts
index e6f5e632a1..d699cd5779 100644
--- a/packages/frontend/src/app/modules/usager-shared/usager-shared.module.ts
+++ b/packages/frontend/src/app/modules/usager-shared/usager-shared.module.ts
@@ -37,6 +37,7 @@ import { SortArrayPipe } from "../shared/pipes";
import { DisplayTableImageComponent } from "../shared/components/display-table-image/display-table-image.component";
import { UsagerNomCompletPipe } from "./pipes";
import { EditUsagerDocComponent } from "./components/edit-usager-doc/edit-usager-doc.component";
+import { ReferrerNamePipe } from "./pipes/referrer-name.pipe";
@NgModule({
declarations: [
@@ -57,6 +58,7 @@ import { EditUsagerDocComponent } from "./components/edit-usager-doc/edit-usager
SetInteractionOutFormComponent,
UploadComponent,
EditUsagerDocComponent,
+ ReferrerNamePipe,
],
imports: [
CommonModule,
@@ -75,6 +77,7 @@ import { EditUsagerDocComponent } from "./components/edit-usager-doc/edit-usager
],
exports: [
DecisionRadiationFormComponent,
+ ReferrerNamePipe,
DeleteUsagerComponent,
DeleteUsagerMenuComponent,
DisplayAyantsDroitsComponent,
diff --git a/packages/frontend/src/app/modules/users/components/reset-password/reset-password.component.ts b/packages/frontend/src/app/modules/users/components/reset-password/reset-password.component.ts
index 8e911592e1..51a78fc9ff 100644
--- a/packages/frontend/src/app/modules/users/components/reset-password/reset-password.component.ts
+++ b/packages/frontend/src/app/modules/users/components/reset-password/reset-password.component.ts
@@ -66,7 +66,7 @@ export class ResetPasswordComponent implements OnInit, OnDestroy {
}
public ngOnInit(): void {
- this.titleService.setTitle("Renouveller mon mot de passe DomiFa");
+ this.titleService.setTitle("Renouveler mon mot de passe DomiFa");
if (this.route.snapshot.params.token) {
const token = this.route.snapshot.params.token;
diff --git a/packages/frontend/src/app/modules/users/services/users.service.ts b/packages/frontend/src/app/modules/users/services/users.service.ts
index 3bd232a732..35e96f2314 100644
--- a/packages/frontend/src/app/modules/users/services/users.service.ts
+++ b/packages/frontend/src/app/modules/users/services/users.service.ts
@@ -1,16 +1,8 @@
import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs";
-import { map } from "rxjs/operators";
import { environment } from "src/environments/environment";
-import {
- UsagerLight,
- UserStructureEditProfile,
- UserStructureProfile,
-} from "../../../../_common/model";
-import { userStructureBuilder } from "./userStructureBuilder.service";
-
-import { UserStructure, ApiMessage, UserStructureRole } from "@domifa/common";
+import { ApiMessage } from "@domifa/common";
@Injectable({
providedIn: "root",
@@ -26,42 +18,10 @@ export class UsersService {
});
}
- public patch(userInfos: UserStructureEditProfile): Observable
{
- return this.http.patch(`${this.endPoint}`, userInfos).pipe(
- map((response) => {
- return userStructureBuilder.buildUserStructure(response);
- })
- );
- }
-
- public getUsers(): Observable {
- return this.http.get(`${this.endPoint}`);
- }
-
- public updateRole(
- uuid: string,
- role: UserStructureRole
- ): Observable {
- return this.http.patch(
- `${this.endPoint}/update-role/${uuid}`,
- {
- role,
- }
- );
- }
-
- public deleteUser(uuid: string): Observable {
- return this.http.delete(`${this.endPoint}/${uuid}`);
- }
-
public getPasswordToken(data: string) {
return this.http.post(`${this.endPoint}/get-password-token`, data);
}
- public getLastPasswordUpdate(): Observable {
- return this.http.get(`${this.endPoint}/last-password-update`);
- }
-
public checkPasswordToken({
userId,
token,
@@ -83,22 +43,7 @@ export class UsersService {
return this.http.post(`${this.endPoint}/reset-password`, data);
}
- public updateMyPassword(data: {
- passwordConfirmation: string;
- password: string;
- oldPassword: string;
- }): Observable {
- return this.http.post(
- `${this.endPoint}/edit-my-password`,
- data
- );
- }
-
public registerUser(data: string): Observable {
return this.http.post(`${this.endPoint}/register`, data);
}
-
- public agenda(): Observable {
- return this.http.get(`${environment.apiUrl}agenda`);
- }
}
diff --git a/packages/frontend/src/app/modules/users/users-routing.module.ts b/packages/frontend/src/app/modules/users/users-routing.module.ts
index cb7ea2c340..c0c98e3a70 100644
--- a/packages/frontend/src/app/modules/users/users-routing.module.ts
+++ b/packages/frontend/src/app/modules/users/users-routing.module.ts
@@ -1,22 +1,17 @@
import { NgModule } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";
-import { AuthGuard, LoggedGuard, ResponsableGuard } from "../../guards";
-import { EditUserComponent } from "./components/edit-user/edit-user.component";
+import { LoggedGuard } from "../../guards";
import { ResetPasswordComponent } from "./components/reset-password/reset-password.component";
-import { UserProfilComponent } from "./components/user-profil/user-profil.component";
const routes: Routes = [
{
- canActivate: [AuthGuard],
path: "mon-compte",
- component: EditUserComponent,
+ redirectTo: "/manage-users/my-account",
},
-
{
- canActivate: [AuthGuard, ResponsableGuard],
- component: UserProfilComponent,
path: "comptes",
+ redirectTo: "/manage-users/accounts",
},
{
canActivate: [LoggedGuard],
diff --git a/packages/frontend/src/app/modules/users/users.module.ts b/packages/frontend/src/app/modules/users/users.module.ts
index 1135682059..2a17a77bff 100644
--- a/packages/frontend/src/app/modules/users/users.module.ts
+++ b/packages/frontend/src/app/modules/users/users.module.ts
@@ -6,27 +6,15 @@ import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { NgbModule } from "@ng-bootstrap/ng-bootstrap";
import { ResetPasswordComponent } from "./components/reset-password/reset-password.component";
-import { UserProfilComponent } from "./components/user-profil/user-profil.component";
-import { RegisterUserAdminComponent } from "./components/register-user-admin/register-user-admin.component";
-import { EditUserComponent } from "./components/edit-user/edit-user.component";
import { SharedModule } from "../shared/shared.module";
-import { UsersRoutingModule } from "./users-routing.module";
import { UserStructurePasswordFormComponent } from "./components/user-structure-password-form/user-structure-password-form.component";
-import { TableHeadSortComponent } from "../shared/components/table-head-sort/table-head-sort.component";
-import { SortArrayPipe } from "../shared/pipes";
+import { UsersRoutingModule } from "./users-routing.module";
@NgModule({
- declarations: [
- ResetPasswordComponent,
- UserProfilComponent,
- RegisterUserAdminComponent,
- EditUserComponent,
- UserStructurePasswordFormComponent,
- ],
+ declarations: [ResetPasswordComponent, UserStructurePasswordFormComponent],
exports: [UserStructurePasswordFormComponent],
imports: [
- TableHeadSortComponent,
FormsModule,
HttpClientModule,
NgbModule,
@@ -34,7 +22,6 @@ import { SortArrayPipe } from "../shared/pipes";
SharedModule,
CommonModule,
UsersRoutingModule,
- SortArrayPipe,
],
providers: [],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
From 1a9cbf4d1b0b97588f332065e9b7a885a0f26bfb Mon Sep 17 00:00:00 2001
From: "Yassine R."
Date: Sun, 26 Jan 2025 23:43:31 +0100
Subject: [PATCH 2/5] fix(frontend): add referrer
---
.../db/dumps/domifa_test.postgres.custom.gz | Bin 101469 -> 100944 bytes
...domifa_test.postgres.restore-data-only.sql | 48 ++++-------
...st.postgres.truncate-restore-data-only.sql | 48 ++++-------
.../mocks/VERIFIED_USERS_STRUCTURE.const.ts | 22 +++++
packages/backend/src/_common/mocks/index.ts | 3 +-
.../_common/mocks/usagers/POST_USAGER.mock.ts | 1 +
.../constants/CUSTOM_DOCS_LABELS.const.ts | 1 +
.../types/StructureCustomDocKeys.type.ts | 1 +
.../user-structure/UserStructure.type.ts | 30 -------
.../UserStructureProfile.type.ts | 14 ----
.../UserStructurePublic.type.ts | 2 +-
.../src/_common/model/user-structure/index.ts | 2 -
.../1603812391580-pr-env-create-database.ts | 1 +
.../src/auth/services/auth-checker.service.ts | 8 +-
.../auth/services/structures-auth.service.ts | 3 +-
...tructureSecurityPasswordChecker.service.ts | 4 +-
...eSecurityResetPasswordInitiator.service.ts | 2 +-
...ureSecurityResetPasswordUpdater.service.ts | 6 +-
.../USAGER_LIGHT_ATTRIBUTES.const.ts | 1 +
.../userStructureRepository.service.ts | 30 ++++++-
.../export-structure-usagers.controller.ts | 6 +-
.../usagersImportCreator.service.ts | 9 +-
.../usager-structure-docs.controller.ts | 13 ++-
.../custom-docs/buildCustomDoc.service.ts | 16 ++++
.../tests/buildCustomDoc.service.spec.ts | 8 ++
.../src/usagers/services/usagers.service.ts | 10 +--
.../renderStructureUsagersRows.ts | 49 ++++++-----
.../tests/renderStructureUsagersRows.spec.ts | 7 +-
.../src/users/controllers/users.controller.ts | 47 ++++-------
.../services/user-usager-creator.service.ts | 4 +-
.../types}/UserStructureProfile.type.ts | 13 +--
.../common/src/user-structure/types/index.ts | 1 +
.../_common/model/usager/UsagerLight.type.ts | 1 +
.../src/_common/model/user-structure/index.ts | 1 -
.../manage-filters.component.html | 79 ++++++++++++++++++
.../manage-filters.component.ts | 9 ++
.../usager-filter/UsagersFilterCriteria.ts | 2 +
.../usager-filter/usagersFilter.service.ts | 44 +++++-----
.../user-profil/user-profil.component.ts | 12 +--
.../services/manage-users.service.ts | 17 +++-
...ay-contact-details-decision.component.html | 2 +-
...display-etat-civil-decision.component.html | 8 +-
.../components/step-rdv/step-rdv.component.ts | 23 ++---
.../profil-general-section.component.html | 53 +++++++-----
.../etat-civil-parent-form.component.ts | 7 +-
.../usager-shared/pipes/referrer-name.pipe.ts | 2 +-
46 files changed, 388 insertions(+), 282 deletions(-)
create mode 100644 packages/backend/src/_common/mocks/VERIFIED_USERS_STRUCTURE.const.ts
delete mode 100644 packages/backend/src/_common/model/user-structure/UserStructure.type.ts
delete mode 100644 packages/backend/src/_common/model/user-structure/UserStructureProfile.type.ts
rename packages/{frontend/src/_common/model/user-structure => common/src/user-structure/types}/UserStructureProfile.type.ts (72%)
diff --git a/_scripts/db/dumps/domifa_test.postgres.custom.gz b/_scripts/db/dumps/domifa_test.postgres.custom.gz
index 46662dcc77a662010331e17fbc3ed36ac84415d3..18ac948886bb3f64f912d8115e099abd9961f266 100644
GIT binary patch
delta 6994
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
delta 7545
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
N[] = [
+ {
+ id: 1,
+ nom: "Martin",
+ prenom: "Sophie",
+ },
+ {
+ id: 2,
+ nom: "Dubois",
+ prenom: "Pierre",
+ },
+ {
+ id: 3,
+ nom: "Laurent",
+ prenom: "Marie",
+ },
+];
diff --git a/packages/backend/src/_common/mocks/index.ts b/packages/backend/src/_common/mocks/index.ts
index acc95cbd0a..8bf45d55e7 100644
--- a/packages/backend/src/_common/mocks/index.ts
+++ b/packages/backend/src/_common/mocks/index.ts
@@ -1,4 +1,5 @@
// @index('./*', f => `export * from '${f.path}'`)
+export * from "./POST_USER_STRUCTURE_BODY.mock";
export * from "./STRUCTURE_MOCK.const";
export * from "./usagers";
-export * from "./POST_USER_STRUCTURE_BODY.mock";
+export * from "./VERIFIED_USERS_STRUCTURE.const";
diff --git a/packages/backend/src/_common/mocks/usagers/POST_USAGER.mock.ts b/packages/backend/src/_common/mocks/usagers/POST_USAGER.mock.ts
index 17012e056a..c94a06229f 100644
--- a/packages/backend/src/_common/mocks/usagers/POST_USAGER.mock.ts
+++ b/packages/backend/src/_common/mocks/usagers/POST_USAGER.mock.ts
@@ -28,6 +28,7 @@ export const POST_USAGER: {
surnom: "Surnom ",
villeNaissance: "Monaco",
nationalite: null,
+ referrerId: null,
},
response: {
nationalite: null,
diff --git a/packages/backend/src/_common/model/structure-doc/constants/CUSTOM_DOCS_LABELS.const.ts b/packages/backend/src/_common/model/structure-doc/constants/CUSTOM_DOCS_LABELS.const.ts
index ae4fec2a17..542c7ec038 100644
--- a/packages/backend/src/_common/model/structure-doc/constants/CUSTOM_DOCS_LABELS.const.ts
+++ b/packages/backend/src/_common/model/structure-doc/constants/CUSTOM_DOCS_LABELS.const.ts
@@ -40,6 +40,7 @@ export const CUSTOM_DOCS_LABELS: {
USAGER_NATIONALITE: "Nationalité",
USAGER_DATE_NAISSANCE: "Date naissance",
USAGER_LIEU_NAISSANCE: "Lieu naissance",
+ REFERENT: "Référent.e dans la structure",
AYANTS_DROITS_NOMBRE: "Nombre d'ayants-droit",
AYANTS_DROITS_LISTE:
"La liste des ayants droits avec nom prénom et date de naissance",
diff --git a/packages/backend/src/_common/model/structure-doc/types/StructureCustomDocKeys.type.ts b/packages/backend/src/_common/model/structure-doc/types/StructureCustomDocKeys.type.ts
index 0a7e29b25c..fc9862c8ca 100644
--- a/packages/backend/src/_common/model/structure-doc/types/StructureCustomDocKeys.type.ts
+++ b/packages/backend/src/_common/model/structure-doc/types/StructureCustomDocKeys.type.ts
@@ -39,6 +39,7 @@ export type StructureCustomDocKeys =
| "USAGER_NUMERO_DISTRIBUTION_SPECIALE"
| "AYANTS_DROITS_LISTE"
| "AYANTS_DROITS_NOMBRE"
+ | "REFERENT"
// DECISION
| "STATUT_DOM"
| "TYPE_DOM"
diff --git a/packages/backend/src/_common/model/user-structure/UserStructure.type.ts b/packages/backend/src/_common/model/user-structure/UserStructure.type.ts
deleted file mode 100644
index be2b1c284e..0000000000
--- a/packages/backend/src/_common/model/user-structure/UserStructure.type.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import {
- UserStructureRole,
- UserStructureMails,
- StructureCommon,
- AppEntity,
-} from "@domifa/common";
-
-export type UserStructure = AppEntity & {
- id: number;
-
- prenom: string;
- nom: string;
- fonction?: string;
- structureId: number;
-
- // login tokens
- email: string;
- password: string;
-
- lastLogin: Date;
- passwordLastUpdate: Date;
-
- verified: boolean;
-
- role: UserStructureRole; // security profile
-
- mails: UserStructureMails;
- acceptTerms: Date | null;
- structure?: StructureCommon;
-};
diff --git a/packages/backend/src/_common/model/user-structure/UserStructureProfile.type.ts b/packages/backend/src/_common/model/user-structure/UserStructureProfile.type.ts
deleted file mode 100644
index 25febf22e5..0000000000
--- a/packages/backend/src/_common/model/user-structure/UserStructureProfile.type.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { UserStructure } from "./UserStructure.type";
-
-export type UserStructureProfile = Pick<
- UserStructure,
- | "id"
- | "email"
- | "nom"
- | "prenom"
- | "role"
- | "verified"
- | "structureId"
- | "structure"
- | "fonction"
->;
diff --git a/packages/backend/src/_common/model/user-structure/UserStructurePublic.type.ts b/packages/backend/src/_common/model/user-structure/UserStructurePublic.type.ts
index 504a2fa64e..caa3750735 100644
--- a/packages/backend/src/_common/model/user-structure/UserStructurePublic.type.ts
+++ b/packages/backend/src/_common/model/user-structure/UserStructurePublic.type.ts
@@ -1,4 +1,4 @@
-import { UserStructure } from "./UserStructure.type";
+import { UserStructure } from "@domifa/common";
// UserStructure: attributs publics (retournés au frontend via UserStructureAuthenticated)
export type UserStructurePublic = Pick<
diff --git a/packages/backend/src/_common/model/user-structure/index.ts b/packages/backend/src/_common/model/user-structure/index.ts
index 70c834d938..3a4ad214e3 100644
--- a/packages/backend/src/_common/model/user-structure/index.ts
+++ b/packages/backend/src/_common/model/user-structure/index.ts
@@ -1,8 +1,6 @@
// @index('./*', f => `export * from '${f.path}'`)
export * from "./_constants";
-export * from "./UserStructure.type";
export * from "./UserStructureAuthenticated.type";
-export * from "./UserStructureProfile.type";
export * from "./UserStructurePublic.type";
export * from "./UserStructureSecurity.type";
export * from "./UserStructureSecurityEvent.type";
diff --git a/packages/backend/src/_migrations/_init-db/1603812391580-pr-env-create-database.ts b/packages/backend/src/_migrations/_init-db/1603812391580-pr-env-create-database.ts
index 93ce428fcf..3710d89b52 100644
--- a/packages/backend/src/_migrations/_init-db/1603812391580-pr-env-create-database.ts
+++ b/packages/backend/src/_migrations/_init-db/1603812391580-pr-env-create-database.ts
@@ -430,6 +430,7 @@ async function createTables(queryRunner: QueryRunner) {
"numeroDistribution" text NULL,
"pinnedNote" jsonb NULL,
nationalite text NULL,
+ "referrerId" int4 NULL,
statut text DEFAULT 'INSTRUCTION'::text NOT NULL,
nom_prenom_surnom_ref varchar NOT NULL,
CONSTRAINT "PK_1bb36e24229bec446a281573612" PRIMARY KEY (uuid),
diff --git a/packages/backend/src/auth/services/auth-checker.service.ts b/packages/backend/src/auth/services/auth-checker.service.ts
index c698cdf1fa..6b168691e8 100644
--- a/packages/backend/src/auth/services/auth-checker.service.ts
+++ b/packages/backend/src/auth/services/auth-checker.service.ts
@@ -1,11 +1,7 @@
import { appLogger } from "../../util";
-import {
- UserAuthenticated,
- UserProfile,
- UserStructure,
-} from "../../_common/model";
+import { UserAuthenticated, UserProfile } from "../../_common/model";
import { DOMIFA_ADMIN_STRUCTURE_ID } from "./DOMIFA_ADMIN_STRUCTURE_ID.const";
-import { UserStructureRole } from "@domifa/common";
+import { UserStructure, UserStructureRole } from "@domifa/common";
export const authChecker = {
checkRole,
diff --git a/packages/backend/src/auth/services/structures-auth.service.ts b/packages/backend/src/auth/services/structures-auth.service.ts
index bed1429df2..13cde57f2b 100644
--- a/packages/backend/src/auth/services/structures-auth.service.ts
+++ b/packages/backend/src/auth/services/structures-auth.service.ts
@@ -5,13 +5,12 @@ import { domifaConfig } from "../../config";
import { userStructureRepository, structureRepository } from "../../database";
import {
CURRENT_JWT_PAYLOAD_VERSION,
- UserStructure,
UserStructureAuthenticated,
UserStructureJwtPayload,
UserStructurePublic,
} from "../../_common/model";
import { isDomifaAdmin } from "./auth-checker.service";
-import { StructureCommon } from "@domifa/common";
+import { UserStructure, StructureCommon } from "@domifa/common";
export const APP_USER_PUBLIC_ATTRIBUTES: (keyof UserStructurePublic)[] = [
"uuid",
diff --git a/packages/backend/src/database/services/app-log/user-structure-security/userStructureSecurityPasswordChecker.service.ts b/packages/backend/src/database/services/app-log/user-structure-security/userStructureSecurityPasswordChecker.service.ts
index 43f183393d..cc3482ec6f 100644
--- a/packages/backend/src/database/services/app-log/user-structure-security/userStructureSecurityPasswordChecker.service.ts
+++ b/packages/backend/src/database/services/app-log/user-structure-security/userStructureSecurityPasswordChecker.service.ts
@@ -1,6 +1,6 @@
+import { UserStructure } from "@domifa/common";
+import { passwordGenerator } from "../../../../util";
import { userStructureRepository } from "../../user-structure";
-import { passwordGenerator } from "../../../../util/encoding/passwordGenerator.service";
-import { UserStructure } from "../../../../_common/model";
import { userStructureSecurityEventHistoryManager } from "./userStructureSecurityEventHistoryManager.service";
import { userStructureSecurityRepository } from "./userStructureSecurityRepository.service";
diff --git a/packages/backend/src/database/services/app-log/user-structure-security/userStructureSecurityResetPasswordInitiator.service.ts b/packages/backend/src/database/services/app-log/user-structure-security/userStructureSecurityResetPasswordInitiator.service.ts
index b55efe52ad..84906a6a77 100644
--- a/packages/backend/src/database/services/app-log/user-structure-security/userStructureSecurityResetPasswordInitiator.service.ts
+++ b/packages/backend/src/database/services/app-log/user-structure-security/userStructureSecurityResetPasswordInitiator.service.ts
@@ -3,7 +3,6 @@ import { addDays } from "date-fns";
import { domifaConfig } from "../../../../config";
import { tokenGenerator } from "../../../../util";
import {
- UserStructureProfile,
UserStructureSecurity,
UserStructureTokens,
UserStructureTokenType,
@@ -11,6 +10,7 @@ import {
import { userStructureRepository } from "../../user-structure";
import { userStructureSecurityEventHistoryManager } from "./userStructureSecurityEventHistoryManager.service";
import { userStructureSecurityRepository } from "./userStructureSecurityRepository.service";
+import { UserStructureProfile } from "@domifa/common";
export const userStructureSecurityResetPasswordInitiator = {
buildResetPasswordLink,
diff --git a/packages/backend/src/database/services/app-log/user-structure-security/userStructureSecurityResetPasswordUpdater.service.ts b/packages/backend/src/database/services/app-log/user-structure-security/userStructureSecurityResetPasswordUpdater.service.ts
index c95e6c603c..d10600426f 100644
--- a/packages/backend/src/database/services/app-log/user-structure-security/userStructureSecurityResetPasswordUpdater.service.ts
+++ b/packages/backend/src/database/services/app-log/user-structure-security/userStructureSecurityResetPasswordUpdater.service.ts
@@ -1,11 +1,9 @@
import { passwordGenerator } from "../../../../util/encoding/passwordGenerator.service";
-import {
- UserStructureProfile,
- UserStructureSecurity,
-} from "../../../../_common/model";
+import { UserStructureSecurity } from "../../../../_common/model";
import { userStructureRepository } from "../../user-structure/userStructureRepository.service";
import { userStructureSecurityEventHistoryManager } from "./userStructureSecurityEventHistoryManager.service";
import { userStructureSecurityRepository } from "./userStructureSecurityRepository.service";
+import { UserStructureProfile } from "@domifa/common";
export const userStructureSecurityResetPasswordUpdater = {
checkResetPasswordToken,
diff --git a/packages/backend/src/database/services/usager/constants/USAGER_LIGHT_ATTRIBUTES.const.ts b/packages/backend/src/database/services/usager/constants/USAGER_LIGHT_ATTRIBUTES.const.ts
index 37d55aa990..409106ddb6 100644
--- a/packages/backend/src/database/services/usager/constants/USAGER_LIGHT_ATTRIBUTES.const.ts
+++ b/packages/backend/src/database/services/usager/constants/USAGER_LIGHT_ATTRIBUTES.const.ts
@@ -23,6 +23,7 @@ export const USAGER_LIGHT_ATTRIBUTES: (keyof Usager)[] = [
"lastInteraction",
"options",
"historique",
+ "referrerId",
"ayantsDroits",
//"villeNaissance",
"telephone",
diff --git a/packages/backend/src/database/services/user-structure/userStructureRepository.service.ts b/packages/backend/src/database/services/user-structure/userStructureRepository.service.ts
index 3bcdc7de4a..a3dc330213 100644
--- a/packages/backend/src/database/services/user-structure/userStructureRepository.service.ts
+++ b/packages/backend/src/database/services/user-structure/userStructureRepository.service.ts
@@ -1,8 +1,11 @@
import { In } from "typeorm";
-import { UserStructureProfile } from "../../../_common/model";
import { UserStructureTable } from "../../entities";
import { myDataSource } from "../_postgres";
-import { UserStructureRole, UserStructure } from "@domifa/common";
+import {
+ UserStructureRole,
+ UserStructure,
+ UserStructureProfile,
+} from "@domifa/common";
export type AppUserForAdminEmail = Pick<
UserStructure,
@@ -12,6 +15,29 @@ export type AppUserForAdminEmail = Pick<
export const userStructureRepository = myDataSource
.getRepository(UserStructureTable)
.extend({
+ getVerifiedUsersByStructureId(
+ structureId: number
+ ): Promise {
+ return userStructureRepository.find({
+ where: {
+ structureId,
+ },
+ select: {
+ uuid: true,
+ id: true,
+ role: true,
+ nom: true,
+ prenom: true,
+ email: true,
+ createdAt: true,
+ lastLogin: true,
+ verified: true,
+ },
+ order: {
+ nom: "ASC",
+ },
+ });
+ },
findVerifiedStructureUsersByRoles({
structureId,
roles,
diff --git a/packages/backend/src/usagers/controllers/export-structure-usagers.controller.ts b/packages/backend/src/usagers/controllers/export-structure-usagers.controller.ts
index 67883b7a1e..f38c39392e 100644
--- a/packages/backend/src/usagers/controllers/export-structure-usagers.controller.ts
+++ b/packages/backend/src/usagers/controllers/export-structure-usagers.controller.ts
@@ -28,6 +28,7 @@ import { AppLogsService } from "../../modules/app-logs/app-logs.service";
import { domifaConfig } from "../../config";
import { UsagersFilterCriteriaStatut } from "@domifa/common";
+import { userStructureRepository } from "../../database";
let lastCpuUsage = process.cpuUsage();
let lastTime = Date.now();
@@ -91,6 +92,9 @@ export class ExportStructureUsagersController {
const workbook = XLSX.utils.book_new();
+ const users = await userStructureRepository.getVerifiedUsersByStructureId(
+ user.structureId
+ );
const { firstSheetHeaders, secondSheetHeaders } =
renderStructureUsagersHeaders(user.structure);
@@ -128,7 +132,7 @@ export class ExportStructureUsagersController {
logProcessState(`Processing chunk (${currentRowUsagers}/${count})`);
const { firstSheetUsagers, secondSheetEntretiens } =
- renderStructureUsagersRows(chunk, user.structure);
+ renderStructureUsagersRows(chunk, user.structure, users);
// Application du format des dates
applyDateFormat(firstSheetUsagers, [
diff --git a/packages/backend/src/usagers/controllers/import/step3-create/usagersImportCreator.service.ts b/packages/backend/src/usagers/controllers/import/step3-create/usagersImportCreator.service.ts
index 0ffe7b5e49..002800985e 100644
--- a/packages/backend/src/usagers/controllers/import/step3-create/usagersImportCreator.service.ts
+++ b/packages/backend/src/usagers/controllers/import/step3-create/usagersImportCreator.service.ts
@@ -1,4 +1,3 @@
-import { usagerHistoryStatesRepository } from "./../../../../database/services/usager/usagerHistoryStatesRepository.service";
import { ImportProcessTracker } from "../ImportProcessTracker.type";
import { UsagersImportUsager } from "../step2-validate-row";
import { usagersImportBuilder } from "./usagersImportBuilder.service";
@@ -8,11 +7,13 @@ import {
usagerRepository,
usagerEntretienRepository,
UsagerEntretienTable,
+ usagerHistoryStatesRepository,
} from "../../../../database";
-import { UserStructure } from "../../../../_common/model";
-import { usagersCreator } from "../../../services";
-import { UsagerHistoryStateService } from "../../../services/usagerHistoryState.service";
+
+import { UsagerHistoryStateService, usagersCreator } from "../../../services";
+
import { Injectable } from "@nestjs/common";
+import { UserStructure } from "@domifa/common";
@Injectable()
export class ImportCreatorService {
diff --git a/packages/backend/src/usagers/controllers/usager-structure-docs.controller.ts b/packages/backend/src/usagers/controllers/usager-structure-docs.controller.ts
index 1dc398ef5b..317b6c77d0 100644
--- a/packages/backend/src/usagers/controllers/usager-structure-docs.controller.ts
+++ b/packages/backend/src/usagers/controllers/usager-structure-docs.controller.ts
@@ -19,7 +19,10 @@ import { CurrentUsager } from "../../auth/decorators/current-usager.decorator";
import { CurrentUser } from "../../auth/decorators/current-user.decorator";
import { AppUserGuard } from "../../auth/guards";
import { UsagerAccessGuard } from "../../auth/guards/usager-access.guard";
-import { structureDocRepository } from "../../database";
+import {
+ structureDocRepository,
+ userStructureRepository,
+} from "../../database";
import { UserStructureAuthenticated } from "../../_common/model";
import {
buildCustomDoc,
@@ -62,6 +65,9 @@ export class UsagerStructureDocsController {
uuid: structureDocUuid,
});
+ const users = await userStructureRepository.getVerifiedUsersByStructureId(
+ user.structureId
+ );
if (!doc) {
return res
.status(HttpStatus.BAD_REQUEST)
@@ -98,6 +104,7 @@ export class UsagerStructureDocsController {
structure: user.structure,
date: new Date(),
extraParameters: null,
+ users,
});
try {
@@ -136,6 +143,9 @@ export class UsagerStructureDocsController {
let content = "";
+ const users = await userStructureRepository.getVerifiedUsersByStructureId(
+ user.structureId
+ );
if (doc) {
const filePath = join(
"structure-documents",
@@ -172,6 +182,7 @@ export class UsagerStructureDocsController {
structure: user.structure,
extraParameters,
date: new Date(),
+ users,
});
if (docType === "acces_espace_domicilie") {
diff --git a/packages/backend/src/usagers/services/custom-docs/buildCustomDoc.service.ts b/packages/backend/src/usagers/services/custom-docs/buildCustomDoc.service.ts
index ad8cce4a05..1fecd35284 100644
--- a/packages/backend/src/usagers/services/custom-docs/buildCustomDoc.service.ts
+++ b/packages/backend/src/usagers/services/custom-docs/buildCustomDoc.service.ts
@@ -15,6 +15,7 @@ import {
UsagerOptionsProcuration,
Usager,
ENTRETIEN_LIEN_COMMUNE,
+ UserStructureProfile,
} from "@domifa/common";
import {
StructureCustomDocKeys,
@@ -40,6 +41,7 @@ export function buildCustomDoc({
structure,
date,
extraParameters = null,
+ users,
}: {
usager: Usager;
structure: StructureCommon;
@@ -48,6 +50,7 @@ export function buildCustomDoc({
ESPACE_DOM_ID: string;
ESPACE_DOM_MDP: string;
} | null;
+ users: Pick[];
}): {
[key in StructureCustomDocKeys]: string | Date | number;
} {
@@ -135,6 +138,7 @@ export function buildCustomDoc({
...buildEntretienForDocs(usager),
...buildDecision(usager, structure, DATE_FORMAT.JOUR_LONG),
...buildMonDomifaForDocs(usager, extraParameters),
+ REFERENT: buildReferrer(usager, users),
SMS_ACTIVATION: formatBoolean(usager.contactByPhone),
// Transferts
@@ -171,6 +175,18 @@ export function buildCustomDoc({
};
}
+export const buildReferrer = (
+ usager: Pick,
+ users: Pick[]
+): string => {
+ if (!usager.referrerId) {
+ return "";
+ }
+
+ const referrer = users.find((user) => user.id === usager.referrerId);
+ return referrer ? `${referrer.nom} ${referrer.prenom}` : "Compte supprimé";
+};
+
export const buildDecision = (
usager: Pick<
Usager,
diff --git a/packages/backend/src/usagers/services/custom-docs/tests/buildCustomDoc.service.spec.ts b/packages/backend/src/usagers/services/custom-docs/tests/buildCustomDoc.service.spec.ts
index c0f7856d3c..dff8df63df 100644
--- a/packages/backend/src/usagers/services/custom-docs/tests/buildCustomDoc.service.spec.ts
+++ b/packages/backend/src/usagers/services/custom-docs/tests/buildCustomDoc.service.spec.ts
@@ -4,6 +4,7 @@ import {
STRUCTURE_MOCK,
USAGER_REFUS_MOCK,
USAGER_VALIDE_MOCK,
+ VERIFIED_USERS_STRUCTURE,
} from "../../../../_common/mocks";
import { StructureCustomDocTags } from "../../../../_common/model";
@@ -29,6 +30,7 @@ describe("buildCustomDoc.service", () => {
structure: STRUCTURE_MOCK,
date,
extraParameters,
+ users: [...VERIFIED_USERS_STRUCTURE],
});
expect(docRadiation).toEqual({
@@ -46,6 +48,7 @@ describe("buildCustomDoc.service", () => {
structure: STRUCTURE_MOCK,
date,
extraParameters: null,
+ users: [...VERIFIED_USERS_STRUCTURE],
});
expect(docActif).toEqual(CUSTOM_DOC_ATTESTATION_POSTALE);
@@ -63,6 +66,7 @@ describe("buildCustomDoc.service", () => {
structure: STRUCTURE_MOCK,
date,
extraParameters: null,
+ users: [...VERIFIED_USERS_STRUCTURE],
});
expect(docActif).toEqual(CUSTOM_DOC_COURRIER_REFUS);
@@ -73,6 +77,7 @@ describe("buildCustomDoc.service", () => {
structure: STRUCTURE_MOCK,
date,
extraParameters: null,
+ users: [...VERIFIED_USERS_STRUCTURE],
});
expect(docNumeroDistribution.USAGER_NUMERO_DISTRIBUTION_SPECIALE).toEqual(
@@ -118,6 +123,7 @@ describe("buildCustomDoc.service", () => {
structure: STRUCTURE_MOCK,
date,
extraParameters: null,
+ users: [...VERIFIED_USERS_STRUCTURE],
});
expect(customDocGenerated.TRANSFERT_ACTIF).toEqual("OUI");
@@ -163,6 +169,7 @@ describe("buildCustomDoc.service", () => {
structure: STRUCTURE_MOCK,
date,
extraParameters: null,
+ users: [...VERIFIED_USERS_STRUCTURE],
});
expect(testDoc.DATE_JOUR_HEURE).toEqual("12/04/2022 à 10:43");
@@ -182,6 +189,7 @@ describe("buildCustomDoc.service", () => {
structure: STRUCTURE_MOCK,
date,
extraParameters: null,
+ users: [...VERIFIED_USERS_STRUCTURE],
});
expect(testDoc.DATE_JOUR_HEURE).toEqual("23/03/2022 à 05:32");
diff --git a/packages/backend/src/usagers/services/usagers.service.ts b/packages/backend/src/usagers/services/usagers.service.ts
index e823be5b3e..d22958fa19 100644
--- a/packages/backend/src/usagers/services/usagers.service.ts
+++ b/packages/backend/src/usagers/services/usagers.service.ts
@@ -5,11 +5,7 @@ import {
usagerRepository,
UsagerTable,
} from "../../database";
-import {
- UserStructure,
- UserStructureProfile,
- UserStructureAuthenticated,
-} from "../../_common/model";
+import { UserStructureAuthenticated } from "../../_common/model";
import { usagersCreator } from "./usagersCreator.service";
import { usagerVisibleHistoryManager } from "./usagerVisibleHistoryManager.service";
@@ -27,6 +23,8 @@ import {
UsagerDecision,
Usager,
UsagersFilterCriteriaStatut,
+ UserStructure,
+ UserStructureProfile,
} from "@domifa/common";
import { UsagerHistoryStateService } from "./usagerHistoryState.service";
import { StructureUsagerExport } from "./xlsx-structure-usagers-renderer";
@@ -38,7 +36,7 @@ export class UsagersService {
) {}
public async create(
usagerDto: CreateUsagerDto,
- user: UserStructureProfile
+ user: Pick
): Promise {
const usager = new UsagerTable(usagerDto);
usagersCreator.setUsagerDefaultAttributes(usager);
diff --git a/packages/backend/src/usagers/services/xlsx-structure-usagers-renderer/renderStructureUsagersRows.ts b/packages/backend/src/usagers/services/xlsx-structure-usagers-renderer/renderStructureUsagersRows.ts
index 83da926821..ee6cdd0d5b 100644
--- a/packages/backend/src/usagers/services/xlsx-structure-usagers-renderer/renderStructureUsagersRows.ts
+++ b/packages/backend/src/usagers/services/xlsx-structure-usagers-renderer/renderStructureUsagersRows.ts
@@ -1,4 +1,8 @@
-import { StructureCommon, UsagerAyantDroit } from "@domifa/common";
+import {
+ StructureCommon,
+ UsagerAyantDroit,
+ UserStructureProfile,
+} from "@domifa/common";
import set from "lodash.set";
import {
@@ -72,6 +76,8 @@ export const renderStructureUsagersHeaders = (
CUSTOM_DOCS_LABELS.ENTRETIEN_ORIENTATION_DETAIL,
ENTRETIEN_DOMICILIATION_EXISTANTE:
CUSTOM_DOCS_LABELS.ENTRETIEN_DOMICILIATION_EXISTANTE,
+ ENTRETIEN_SITUATION_PROFESSIONNELLE:
+ CUSTOM_DOCS_LABELS.ENTRETIEN_SITUATION_PROFESSIONNELLE,
ENTRETIEN_REVENUS: CUSTOM_DOCS_LABELS.ENTRETIEN_REVENUS,
ENTRETIEN_REVENUS_DETAIL: CUSTOM_DOCS_LABELS.ENTRETIEN_REVENUS_DETAIL,
ENTRETIEN_LIEN_COMMUNE: CUSTOM_DOCS_LABELS.ENTRETIEN_LIEN_COMMUNE,
@@ -85,8 +91,7 @@ export const renderStructureUsagersHeaders = (
ENTRETIEN_ACCOMPAGNEMENT_DETAIL:
CUSTOM_DOCS_LABELS.ENTRETIEN_ACCOMPAGNEMENT_DETAIL,
ENTRETIEN_RATTACHEMENT: CUSTOM_DOCS_LABELS.ENTRETIEN_RATTACHEMENT,
- ENTRETIEN_SITUATION_PROFESSIONNELLE:
- CUSTOM_DOCS_LABELS.ENTRETIEN_SITUATION_PROFESSIONNELLE,
+
ENTRETIEN_COMMENTAIRE: CUSTOM_DOCS_LABELS.ENTRETIEN_COMMENTAIRE,
};
@@ -123,7 +128,8 @@ export const renderStructureUsagersHeaders = (
export const renderStructureUsagersRows = (
usagers: StructureUsagerExport[],
- structure: StructureCommon
+ structure: StructureCommon,
+ users: Pick[]
): {
firstSheetUsagers: StructureCustomDocTags[];
secondSheetEntretiens: StructureCustomDocTags[];
@@ -133,21 +139,23 @@ export const renderStructureUsagersRows = (
for (const usagerToExport of usagers) {
try {
+ const firstPartOfData = buildCustomDoc({
+ usager: {
+ ...usagerToExport,
+ structureId: structure.id,
+ contactByPhone: null,
+ etapeDemande: null,
+ statut: usagerToExport.decision.statut,
+ rdv: null,
+ pinnedNote: null,
+ },
+ structure,
+ date: new Date(),
+ extraParameters: null,
+ users,
+ });
const customData = {
- ...buildCustomDoc({
- usager: {
- ...usagerToExport,
- structureId: structure.id,
- contactByPhone: null,
- etapeDemande: null,
- statut: usagerToExport.decision.statut,
- rdv: null,
- pinnedNote: null,
- },
- structure,
- date: new Date(),
- extraParameters: null,
- }),
+ ...firstPartOfData,
...buildDecision(usagerToExport, structure, DATE_FORMAT.JOUR),
};
@@ -210,6 +218,7 @@ export const renderFirstSheetData = (
DATE_FIN_DOM: usager.DATE_FIN_DOM,
DATE_PREMIERE_DOM: usager.DATE_PREMIERE_DOM,
DATE_DERNIER_PASSAGE: usager.DATE_DERNIER_PASSAGE,
+ REFERENT: usager.REFERENT,
AYANTS_DROITS_NOMBRE: usager.AYANTS_DROITS_NOMBRE,
TRANSFERT_ACTIF: usager.TRANSFERT_ACTIF,
TRANSFERT_NOM: usager.TRANSFERT_NOM,
@@ -236,6 +245,8 @@ export const renderSecondSheetData = (
ENTRETIEN_ORIENTATION: usager.ENTRETIEN_ORIENTATION,
ENTRETIEN_ORIENTATION_DETAIL: usager.ENTRETIEN_ORIENTATION_DETAIL,
ENTRETIEN_DOMICILIATION_EXISTANTE: usager.ENTRETIEN_DOMICILIATION_EXISTANTE,
+ ENTRETIEN_SITUATION_PROFESSIONNELLE:
+ usager.ENTRETIEN_SITUATION_PROFESSIONNELLE,
ENTRETIEN_REVENUS: usager.ENTRETIEN_REVENUS,
ENTRETIEN_REVENUS_DETAIL: usager.ENTRETIEN_REVENUS_DETAIL,
ENTRETIEN_LIEN_COMMUNE: usager.ENTRETIEN_LIEN_COMMUNE,
@@ -246,8 +257,6 @@ export const renderSecondSheetData = (
ENTRETIEN_ACCOMPAGNEMENT: usager.ENTRETIEN_ACCOMPAGNEMENT,
ENTRETIEN_ACCOMPAGNEMENT_DETAIL: usager.ENTRETIEN_ACCOMPAGNEMENT_DETAIL,
ENTRETIEN_RATTACHEMENT: usager.ENTRETIEN_RATTACHEMENT,
- ENTRETIEN_SITUATION_PROFESSIONNELLE:
- usager.ENTRETIEN_SITUATION_PROFESSIONNELLE,
ENTRETIEN_COMMENTAIRE: usager.ENTRETIEN_COMMENTAIRE,
};
};
diff --git a/packages/backend/src/usagers/services/xlsx-structure-usagers-renderer/tests/renderStructureUsagersRows.spec.ts b/packages/backend/src/usagers/services/xlsx-structure-usagers-renderer/tests/renderStructureUsagersRows.spec.ts
index c744fc3527..902270f79f 100644
--- a/packages/backend/src/usagers/services/xlsx-structure-usagers-renderer/tests/renderStructureUsagersRows.spec.ts
+++ b/packages/backend/src/usagers/services/xlsx-structure-usagers-renderer/tests/renderStructureUsagersRows.spec.ts
@@ -3,6 +3,7 @@ import {
STRUCTURE_MOCK,
USAGER_REFUS_MOCK,
USAGER_VALIDE_MOCK,
+ VERIFIED_USERS_STRUCTURE,
} from "../../../../_common/mocks";
import { renderStructureUsagersRows } from "../renderStructureUsagersRows";
import { FIRST_SHEET_USAGERS } from "./FIRST_SHEET_USAGERS.mock";
@@ -14,7 +15,11 @@ describe("renderStructureUsagersRows", () => {
];
it("Generate sheets", async () => {
- const chips = renderStructureUsagersRows(usagers, STRUCTURE_MOCK);
+ const chips = renderStructureUsagersRows(
+ usagers,
+ STRUCTURE_MOCK,
+ VERIFIED_USERS_STRUCTURE
+ );
expect(chips.firstSheetUsagers.length).toEqual(2);
expect(chips.firstSheetUsagers[0]).toEqual(FIRST_SHEET_USAGERS[0]);
expect(chips.firstSheetUsagers[1]).toEqual(FIRST_SHEET_USAGERS[1]);
diff --git a/packages/backend/src/users/controllers/users.controller.ts b/packages/backend/src/users/controllers/users.controller.ts
index 61c9b16836..c09ab12296 100644
--- a/packages/backend/src/users/controllers/users.controller.ts
+++ b/packages/backend/src/users/controllers/users.controller.ts
@@ -14,11 +14,6 @@ import {
import { AuthGuard } from "@nestjs/passport";
import { ApiBearerAuth, ApiOperation, ApiTags } from "@nestjs/swagger";
-import { AllowUserStructureRoles } from "../../auth/decorators";
-import { CurrentChosenUserStructure } from "../../auth/decorators/current-chosen-user-structure.decorator";
-import { CurrentUser } from "../../auth/decorators/current-user.decorator";
-import { AppUserGuard } from "../../auth/guards";
-import { CanGetUserStructureGuard } from "../../auth/guards/CanGetUserStructure.guard";
import {
userStructureRepository,
structureRepository,
@@ -28,19 +23,27 @@ import {
import { Response } from "express";
import {
- UserStructure,
UserStructureAuthenticated,
- UserStructureProfile,
USER_STRUCTURE_ROLE_ALL,
} from "../../_common/model";
-import { EditMyPasswordDto } from "../dto/edit-my-password.dto";
-import { RegisterUserAdminDto } from "../dto/register-user-admin.dto";
-import { UpdateRoleDto } from "../dto/update-role.dto";
-import { UserEditDto } from "../dto/user-edit.dto";
+
import { usersDeletor } from "../services";
import { userStructureCreator } from "../services/user-structure-creator.service";
+import { UserStructureProfile, UserStructure } from "@domifa/common";
import { userAccountCreatedByAdminEmailSender } from "../../modules/mails/services/templates-renderers/user-account-created-by-admin";
+import {
+ UpdateRoleDto,
+ UserEditDto,
+ RegisterUserAdminDto,
+ EditMyPasswordDto,
+} from "../dto";
+import {
+ AllowUserStructureRoles,
+ CurrentUser,
+ CurrentChosenUserStructure,
+} from "../../auth/decorators";
+import { AppUserGuard, CanGetUserStructureGuard } from "../../auth/guards";
@Controller("users")
@ApiTags("users")
@UseGuards(AuthGuard("jwt"), AppUserGuard)
@@ -52,25 +55,9 @@ export class UsersController {
public getUsers(
@CurrentUser() user: UserStructureAuthenticated
): Promise {
- return userStructureRepository.find({
- where: {
- structureId: user.structureId,
- },
- select: {
- uuid: true,
- id: true,
- role: true,
- nom: true,
- prenom: true,
- email: true,
- createdAt: true,
- lastLogin: true,
- verified: true,
- },
- order: {
- nom: "ASC",
- },
- });
+ return userStructureRepository.getVerifiedUsersByStructureId(
+ user.structureId
+ );
}
@AllowUserStructureRoles(...USER_STRUCTURE_ROLE_ALL)
diff --git a/packages/backend/src/users/services/user-usager-creator.service.ts b/packages/backend/src/users/services/user-usager-creator.service.ts
index 3b991dc0b1..5c3dc53d76 100644
--- a/packages/backend/src/users/services/user-usager-creator.service.ts
+++ b/packages/backend/src/users/services/user-usager-creator.service.ts
@@ -3,9 +3,9 @@ import {
userUsagerSecurityRepository,
UserUsagerTable,
} from "../../database";
-import { UserStructure, UserUsagerSecurity } from "../../_common/model";
+import { UserUsagerSecurity } from "../../_common/model";
import { userUsagerLoginPasswordGenerator } from "./user-usager-login-password-generator.service";
-import { UserUsager } from "@domifa/common";
+import { UserStructure, UserUsager } from "@domifa/common";
export const userUsagerCreator = {
createUserWithTmpPassword,
diff --git a/packages/frontend/src/_common/model/user-structure/UserStructureProfile.type.ts b/packages/common/src/user-structure/types/UserStructureProfile.type.ts
similarity index 72%
rename from packages/frontend/src/_common/model/user-structure/UserStructureProfile.type.ts
rename to packages/common/src/user-structure/types/UserStructureProfile.type.ts
index 431deff858..346acc7fe8 100644
--- a/packages/frontend/src/_common/model/user-structure/UserStructureProfile.type.ts
+++ b/packages/common/src/user-structure/types/UserStructureProfile.type.ts
@@ -1,14 +1,15 @@
-import { UserStructure } from "@domifa/common";
+import { UserStructure } from "../interfaces";
export type UserStructureProfile = Pick<
UserStructure,
- | "email"
+ | "uuid"
+ | "id"
+ | "role"
| "nom"
| "prenom"
- | "role"
- | "id"
- | "verified"
- | "uuid"
+ | "email"
| "createdAt"
| "lastLogin"
+ | "structureId"
+ | "verified"
>;
diff --git a/packages/common/src/user-structure/types/index.ts b/packages/common/src/user-structure/types/index.ts
index 85f3522d99..ff23fdc2dc 100644
--- a/packages/common/src/user-structure/types/index.ts
+++ b/packages/common/src/user-structure/types/index.ts
@@ -1,4 +1,5 @@
// @index('./*', f => `export * from '${f.path}'`)
export * from "./UserRightStatus.type";
export * from "./UserStructureCreatedBy.type";
+export * from "./UserStructureProfile.type";
export * from "./UserStructureRole.type";
diff --git a/packages/frontend/src/_common/model/usager/UsagerLight.type.ts b/packages/frontend/src/_common/model/usager/UsagerLight.type.ts
index 8afa9e7283..9b80594efb 100644
--- a/packages/frontend/src/_common/model/usager/UsagerLight.type.ts
+++ b/packages/frontend/src/_common/model/usager/UsagerLight.type.ts
@@ -33,6 +33,7 @@ export type UsagerLight = AppEntity &
| "rdvInfo"
| "pinnedNote"
| "datePremiereDom"
+ | "referrerId"
| "nbNotes"
> & {
phoneNumber?: string;
diff --git a/packages/frontend/src/_common/model/user-structure/index.ts b/packages/frontend/src/_common/model/user-structure/index.ts
index 9bc71f3305..014dcbe5bc 100644
--- a/packages/frontend/src/_common/model/user-structure/index.ts
+++ b/packages/frontend/src/_common/model/user-structure/index.ts
@@ -1,2 +1 @@
export * from "./UserStructureEditProfile.type";
-export * from "./UserStructureProfile.type";
diff --git a/packages/frontend/src/app/modules/manage-usagers/components/manage-filters/manage-filters.component.html b/packages/frontend/src/app/modules/manage-usagers/components/manage-filters/manage-filters.component.html
index 2f7da0367f..2b171fe98b 100644
--- a/packages/frontend/src/app/modules/manage-usagers/components/manage-filters/manage-filters.component.html
+++ b/packages/frontend/src/app/modules/manage-usagers/components/manage-filters/manage-filters.component.html
@@ -301,6 +301,85 @@
+
+
+
+
+
+
+
+
= [];
+ public users: UserStructureProfile[] = [];
+ public subscription: Subscription = new Subscription();
+
+ constructor(private readonly manageUsersService: ManageUsersService) {}
+
ngOnInit(): void {
this.sortMenuItems = this.getSortKeys();
+ this.users = this.manageUsersService.referrers;
}
ngOnChanges() {
diff --git a/packages/frontend/src/app/modules/manage-usagers/components/usager-filter/UsagersFilterCriteria.ts b/packages/frontend/src/app/modules/manage-usagers/components/usager-filter/UsagersFilterCriteria.ts
index dae46d59f5..930734fb41 100644
--- a/packages/frontend/src/app/modules/manage-usagers/components/usager-filter/UsagersFilterCriteria.ts
+++ b/packages/frontend/src/app/modules/manage-usagers/components/usager-filter/UsagersFilterCriteria.ts
@@ -25,6 +25,7 @@ export class UsagersFilterCriteria extends Search {
public interactionType: "courrierIn" | null;
public lastInteractionDate: UsagersFilterCriteriaDernierPassage | null;
public entretien: UsagersFilterCriteriaEntretien | null;
+ public referrerId?: number | null;
// order by
public sortKey: UsagersFilterCriteriaSortKey;
@@ -41,5 +42,6 @@ export class UsagersFilterCriteria extends Search {
this.page = search?.page || 1;
this.sortKey = search?.sortKey || "NOM";
this.sortValue = search?.sortValue || "asc";
+ this.referrerId = search?.referrerId || undefined;
}
}
diff --git a/packages/frontend/src/app/modules/manage-usagers/components/usager-filter/usagersFilter.service.ts b/packages/frontend/src/app/modules/manage-usagers/components/usager-filter/usagersFilter.service.ts
index 6f7aaa97fe..509f4bf612 100644
--- a/packages/frontend/src/app/modules/manage-usagers/components/usager-filter/usagersFilter.service.ts
+++ b/packages/frontend/src/app/modules/manage-usagers/components/usager-filter/usagersFilter.service.ts
@@ -26,22 +26,17 @@ function filter(
}: {
criteria: UsagersFilterCriteria;
}
-) {
+): UsagerLight[] {
return filterByCriteria(usagers, criteria);
}
function filterByCriteria(
usagers: UsagerLight[],
criteria: UsagersFilterCriteria
-) {
- const now = new Date().toISOString().split("T")[0];
-
- if (criteria.entretien) {
- return filterByEntretien(usagers, criteria.entretien, now);
- }
-
+): UsagerLight[] {
// Si pas de filtres ni de recherche textuelle après le traitement entretien
const activeFilters = buildActiveFilters(criteria);
+
if (!criteria.searchString && !activeFilters.length) {
return usagers;
}
@@ -94,6 +89,18 @@ function buildActiveFilters(criteria: UsagersFilterCriteria) {
// Créer un tableau de fonctions de filtrage actives
const activeFilters = [];
+ if (criteria.entretien) {
+ activeFilters.push((usager: UsagerLight) =>
+ filterByEntretien(usager, criteria.entretien)
+ );
+ }
+
+ if (typeof criteria.referrerId !== "undefined") {
+ activeFilters.push(
+ (usager: UsagerLight) => usager.referrerId === criteria.referrerId
+ );
+ }
+
if (criteria.statut) {
activeFilters.push((usager: UsagerLight) =>
usagerStatutChecker.check({ usager, statut: criteria.statut })
@@ -127,16 +134,15 @@ function buildActiveFilters(criteria: UsagersFilterCriteria) {
}
function filterByEntretien(
- usagers: UsagerLight[],
- entretien: string,
- now: string
-): UsagerLight[] {
- return usagers.filter((usager) => {
- if (!usager.rdv?.dateRdv || usager.etapeDemande > ETAPE_ENTRETIEN) {
- return false;
- }
+ usager: UsagerLight,
+ entretien: "COMING" | "OVERDUE"
+): boolean {
+ const now = new Date().toISOString().split("T")[0];
- const dateRdv = new Date(usager.rdv.dateRdv).toISOString().split("T")[0];
- return entretien === "COMING" ? dateRdv > now : dateRdv < now;
- });
+ if (!usager.rdv?.dateRdv || usager.etapeDemande > ETAPE_ENTRETIEN) {
+ return false;
+ }
+
+ const dateRdv = new Date(usager.rdv.dateRdv).toISOString().split("T")[0];
+ return entretien === "COMING" ? dateRdv > now : dateRdv < now;
}
diff --git a/packages/frontend/src/app/modules/manage-users/components/user-profil/user-profil.component.ts b/packages/frontend/src/app/modules/manage-users/components/user-profil/user-profil.component.ts
index 374b9a2b9e..a78ae8fc50 100644
--- a/packages/frontend/src/app/modules/manage-users/components/user-profil/user-profil.component.ts
+++ b/packages/frontend/src/app/modules/manage-users/components/user-profil/user-profil.component.ts
@@ -5,14 +5,16 @@ import { NgbModal, NgbModalRef } from "@ng-bootstrap/ng-bootstrap";
import { CustomToastService } from "src/app/modules/shared/services/custom-toast.service";
-import {
- DEFAULT_MODAL_OPTIONS,
- UserStructureProfile,
-} from "../../../../../_common/model";
+import { DEFAULT_MODAL_OPTIONS } from "../../../../../_common/model";
import { AuthService } from "../../../shared/services/auth.service";
import { differenceInCalendarDays } from "date-fns";
-import { SortValues, UserStructure, UserStructureRole } from "@domifa/common";
+import {
+ UserStructureProfile,
+ SortValues,
+ UserStructure,
+ UserStructureRole,
+} from "@domifa/common";
import { ManageUsersService } from "../../services/manage-users.service";
@Component({
diff --git a/packages/frontend/src/app/modules/manage-users/services/manage-users.service.ts b/packages/frontend/src/app/modules/manage-users/services/manage-users.service.ts
index 859a2f960b..4d170b80df 100644
--- a/packages/frontend/src/app/modules/manage-users/services/manage-users.service.ts
+++ b/packages/frontend/src/app/modules/manage-users/services/manage-users.service.ts
@@ -1,10 +1,14 @@
import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
-import { UserStructure, UserStructureRole, ApiMessage } from "@domifa/common";
+import {
+ UserStructure,
+ UserStructureRole,
+ ApiMessage,
+ UserStructureProfile,
+} from "@domifa/common";
import { BehaviorSubject, Observable, map } from "rxjs";
import {
UserStructureEditProfile,
- UserStructureProfile,
UsagerLight,
} from "../../../../_common/model";
import { environment } from "../../../../environments/environment";
@@ -18,15 +22,20 @@ export class ManageUsersService {
private usersSubject = new BehaviorSubject
([]);
readonly users$ = this.usersSubject.asObservable();
- readonly usersMap: { [key: number]: string } = {};
+ readonly referrersMap: { [key: number]: string } = {};
+
public users: UserStructureProfile[] = [];
+ public referrers: UserStructureProfile[] = [];
constructor(private readonly http: HttpClient) {
this.http.get(this.endPoint).subscribe((users) => {
this.usersSubject.next(users);
this.users = users;
users.forEach((user) => {
- this.usersMap[user.id] = `${user.nom} ${user.prenom}`;
+ if (user.role !== "facteur") {
+ this.referrers.push(user);
+ this.referrersMap[user.id] = `${user.nom} ${user.prenom}`;
+ }
});
});
}
diff --git a/packages/frontend/src/app/modules/usager-dossier/components/display-contact-details-decision/display-contact-details-decision.component.html b/packages/frontend/src/app/modules/usager-dossier/components/display-contact-details-decision/display-contact-details-decision.component.html
index 0396c21915..aa7e4cf99d 100644
--- a/packages/frontend/src/app/modules/usager-dossier/components/display-contact-details-decision/display-contact-details-decision.component.html
+++ b/packages/frontend/src/app/modules/usager-dossier/components/display-contact-details-decision/display-contact-details-decision.component.html
@@ -1,5 +1,5 @@
- Téléphone:
+ Téléphone:
{{
usager.telephone | formatInternationalPhoneNumber
}}
diff --git a/packages/frontend/src/app/modules/usager-dossier/components/display-etat-civil-decision/display-etat-civil-decision.component.html b/packages/frontend/src/app/modules/usager-dossier/components/display-etat-civil-decision/display-etat-civil-decision.component.html
index 24e46096a4..9eeb73634c 100644
--- a/packages/frontend/src/app/modules/usager-dossier/components/display-etat-civil-decision/display-etat-civil-decision.component.html
+++ b/packages/frontend/src/app/modules/usager-dossier/components/display-etat-civil-decision/display-etat-civil-decision.component.html
@@ -31,11 +31,9 @@
-
- Référent.e au sein de la structure
-
- {{ usager.referrerId | referrerName }}
-
+
+ Référent:
+ {{ usager.referrerId | referrerName }}
diff --git a/packages/frontend/src/app/modules/usager-dossier/components/step-rdv/step-rdv.component.ts b/packages/frontend/src/app/modules/usager-dossier/components/step-rdv/step-rdv.component.ts
index 25fb7c2bc2..207bb6e0f1 100644
--- a/packages/frontend/src/app/modules/usager-dossier/components/step-rdv/step-rdv.component.ts
+++ b/packages/frontend/src/app/modules/usager-dossier/components/step-rdv/step-rdv.component.ts
@@ -10,10 +10,7 @@ import {
import { ActivatedRoute, Router } from "@angular/router";
import { NgbDateStruct } from "@ng-bootstrap/ng-bootstrap";
-import {
- UsagerLight,
- UserStructureProfile,
-} from "../../../../../_common/model";
+import { UsagerLight } from "../../../../../_common/model";
import { DocumentService } from "../../../usager-shared/services/document.service";
import { UsagerDossierService } from "../../services/usager-dossier.service";
import {
@@ -40,7 +37,7 @@ import {
AuthService,
CustomToastService,
} from "../../../shared/services";
-import { CerfaDocType, Usager } from "@domifa/common";
+import { CerfaDocType, Usager, UserStructureProfile } from "@domifa/common";
import { RdvForm } from "../../types";
import { ManageUsersService } from "../../../manage-users/services/manage-users.service";
@@ -173,18 +170,12 @@ export class StepRdvComponent
this.rdvForm.controls.jourRdv.setValue(this.usager.rdv.jourRdv);
this.editRdv = this.usager.rdv.userId === null;
- this.subscription.add(
- this.manageUsersService.users$.subscribe(
- (users: UserStructureProfile[]) => {
- this.users = users.filter((user) => user.role !== "facteur");
- const userIdRdv = this.usager.rdv?.userId || this.me?.id;
+ const userIdRdv = this.usager.rdv?.userId || this.me?.id;
- this.rdvForm.controls.userId.setValue(userIdRdv, {
- onlySelf: true,
- });
- }
- )
- );
+ this.rdvForm.controls.userId.setValue(userIdRdv, {
+ onlySelf: true,
+ });
+ this.users = this.manageUsersService.referrers;
}
public setValueRdv(value: boolean): void {
diff --git a/packages/frontend/src/app/modules/usager-profil/components/pages/profil-general-section/profil-general-section.component.html b/packages/frontend/src/app/modules/usager-profil/components/pages/profil-general-section/profil-general-section.component.html
index fd8c76be62..509eeac605 100644
--- a/packages/frontend/src/app/modules/usager-profil/components/pages/profil-general-section/profil-general-section.component.html
+++ b/packages/frontend/src/app/modules/usager-profil/components/pages/profil-general-section/profil-general-section.component.html
@@ -249,9 +249,11 @@ Dossier
Référence dossier
+
{{ usager.customRef }}
+
Statut
@@ -263,15 +265,24 @@ Dossier
-
- Ayants-droits
-
-
-
+
+ Type de domiciliation
+
+
+ Renouvellement
+
+
+ Première demande
+
+
Échéance
{{ usager?.echeanceInfos?.dateToDisplay | date : "dd MMMM yyyy" }}
@@ -291,25 +302,21 @@
Dossier
{{ usager.datePremiereDom | date : "dd MMMM yyyy" }}
-
-
Type de domiciliation
+
+
+ Ayants-droits
+
+
+
+ Référent au sein de la structure
-
- Renouvellement
-
-
-
- Première demande
-
+ {{ usager.referrerId | referrerName }}
-
Date: Mon, 27 Jan 2025 15:16:20 +0100
Subject: [PATCH 3/5] fix(backend): fix referrerId and unit tests
---
.../agenda.controller.security-tests.ts | 14 --------------
.../tests/CUSTOM_DOC_ATTESTATION_POSTALE.const.ts | 1 +
.../custom-docs/tests/CUSTOM_DOC_COURRIER_REFUS.ts | 2 +-
.../src/usagers/services/usagersCreator.service.ts | 1 +
.../tests/FIRST_SHEET_USAGERS.mock.ts | 2 ++
.../controllers/users.controller.security-tests.ts | 3 ++-
.../src/users/controllers/users.controller.ts | 14 ++++++++++++--
packages/common/src/search/classes/Search.class.ts | 2 +-
.../types/UsagersFilterCriteriaEntretien.enum.ts | 4 ++++
packages/common/src/search/types/index.ts | 1 +
.../etat-civil-parent-form.component.spec.ts | 1 +
11 files changed, 26 insertions(+), 19 deletions(-)
create mode 100644 packages/common/src/search/types/UsagersFilterCriteriaEntretien.enum.ts
diff --git a/packages/backend/src/usagers/controllers/security-tests/agenda.controller.security-tests.ts b/packages/backend/src/usagers/controllers/security-tests/agenda.controller.security-tests.ts
index 25e0a9dc72..d0fe41face 100644
--- a/packages/backend/src/usagers/controllers/security-tests/agenda.controller.security-tests.ts
+++ b/packages/backend/src/usagers/controllers/security-tests/agenda.controller.security-tests.ts
@@ -28,18 +28,4 @@ export const AgendaControllerSecurityTests: AppTestHttpClientSecurityTestDef[] =
),
}),
},
- {
- label: `${CONTROLLER}.getAllUsersForAgenda`,
- query: async (context: AppTestContext) => ({
- response: await AppTestHttpClient.get("/agenda/users", {
- context,
- }),
- expectedStatus: expectedResponseStatusBuilder.allowStructureOnly(
- context.user,
- {
- roles: ["simple", "responsable", "admin"],
- }
- ),
- }),
- },
];
diff --git a/packages/backend/src/usagers/services/custom-docs/tests/CUSTOM_DOC_ATTESTATION_POSTALE.const.ts b/packages/backend/src/usagers/services/custom-docs/tests/CUSTOM_DOC_ATTESTATION_POSTALE.const.ts
index d9cfbab7c6..1ee33960a3 100644
--- a/packages/backend/src/usagers/services/custom-docs/tests/CUSTOM_DOC_ATTESTATION_POSTALE.const.ts
+++ b/packages/backend/src/usagers/services/custom-docs/tests/CUSTOM_DOC_ATTESTATION_POSTALE.const.ts
@@ -87,4 +87,5 @@ export const CUSTOM_DOC_ATTESTATION_POSTALE: StructureCustomDocTags = {
PROCURATION_DATE_FIN: "",
PROCURATION_DATE_NAISSANCE: "",
PROCURATIONS_NOMBRE: 0,
+ REFERENT: "",
};
diff --git a/packages/backend/src/usagers/services/custom-docs/tests/CUSTOM_DOC_COURRIER_REFUS.ts b/packages/backend/src/usagers/services/custom-docs/tests/CUSTOM_DOC_COURRIER_REFUS.ts
index eb4ff53686..75eba7b418 100644
--- a/packages/backend/src/usagers/services/custom-docs/tests/CUSTOM_DOC_COURRIER_REFUS.ts
+++ b/packages/backend/src/usagers/services/custom-docs/tests/CUSTOM_DOC_COURRIER_REFUS.ts
@@ -40,7 +40,7 @@ export const CUSTOM_DOC_COURRIER_REFUS: StructureCustomDocTags = {
DATE_PREMIERE_DOM: "11 janvier 2018",
DATE_RADIATION: "",
PREMIERE_DOM_NOM_AGENT: "",
-
+ REFERENT: "",
ENTRETIEN_ACCOMPAGNEMENT: "NON",
ENTRETIEN_ACCOMPAGNEMENT_DETAIL: "",
ENTRETIEN_ORIENTATION: "OUI",
diff --git a/packages/backend/src/usagers/services/usagersCreator.service.ts b/packages/backend/src/usagers/services/usagersCreator.service.ts
index 14a2116ba2..9c26b24622 100644
--- a/packages/backend/src/usagers/services/usagersCreator.service.ts
+++ b/packages/backend/src/usagers/services/usagersCreator.service.ts
@@ -31,6 +31,7 @@ function setUsagerDefaultAttributes(usager: Partial): void {
};
usager.typeDom = usager?.typeDom ?? "PREMIERE_DOM";
usager.pinnedNote = null;
+ usager.referrerId = null;
if (!usager.ayantsDroits) {
usager.ayantsDroits = [];
diff --git a/packages/backend/src/usagers/services/xlsx-structure-usagers-renderer/tests/FIRST_SHEET_USAGERS.mock.ts b/packages/backend/src/usagers/services/xlsx-structure-usagers-renderer/tests/FIRST_SHEET_USAGERS.mock.ts
index 8fdebe759e..09341a0d27 100644
--- a/packages/backend/src/usagers/services/xlsx-structure-usagers-renderer/tests/FIRST_SHEET_USAGERS.mock.ts
+++ b/packages/backend/src/usagers/services/xlsx-structure-usagers-renderer/tests/FIRST_SHEET_USAGERS.mock.ts
@@ -34,6 +34,7 @@ export const FIRST_SHEET_USAGERS = [
TRANSFERT_NOM: "",
MON_DOMIFA_ACTIVATION: "NON",
SMS_ACTIVATION: "NON",
+ REFERENT: "",
},
{
AD_DATE_NAISSANCE_0: "20/12/1978",
@@ -74,5 +75,6 @@ export const FIRST_SHEET_USAGERS = [
TRANSFERT_NOM: "",
MON_DOMIFA_ACTIVATION: "NON",
SMS_ACTIVATION: "NON",
+ REFERENT: "",
},
];
diff --git a/packages/backend/src/users/controllers/users.controller.security-tests.ts b/packages/backend/src/users/controllers/users.controller.security-tests.ts
index eb51ae1c12..83706e6f37 100644
--- a/packages/backend/src/users/controllers/users.controller.security-tests.ts
+++ b/packages/backend/src/users/controllers/users.controller.security-tests.ts
@@ -11,6 +11,7 @@ import {
expectedResponseStatusBuilder,
securityTestDataBuilder,
} from "../../_tests";
+import { USER_STRUCTURE_ROLE_ALL } from "../../_common/model";
const CONTROLLER = "UserController";
@@ -24,7 +25,7 @@ export const UserControllerSecurityTests: AppTestHttpClientSecurityTestDef[] = [
expectedStatus: expectedResponseStatusBuilder.allowStructureOnly(
context.user,
{
- roles: ["responsable", "admin"],
+ roles: USER_STRUCTURE_ROLE_ALL,
}
),
}),
diff --git a/packages/backend/src/users/controllers/users.controller.ts b/packages/backend/src/users/controllers/users.controller.ts
index c09ab12296..d87b90275f 100644
--- a/packages/backend/src/users/controllers/users.controller.ts
+++ b/packages/backend/src/users/controllers/users.controller.ts
@@ -52,12 +52,22 @@ export class UsersController {
@ApiBearerAuth()
@ApiOperation({ summary: "Liste des utilisateurs" })
@Get("")
- public getUsers(
+ public async getUsers(
@CurrentUser() user: UserStructureAuthenticated
): Promise {
- return userStructureRepository.getVerifiedUsersByStructureId(
+ const users = await userStructureRepository.getVerifiedUsersByStructureId(
user.structureId
);
+ if (user.role === "facteur" || user.role === "simple") {
+ return users.map((user) => {
+ return {
+ id: user.id,
+ nom: user.nom,
+ prenom: user.prenom,
+ };
+ }) as UserStructureProfile[];
+ }
+ return users;
}
@AllowUserStructureRoles(...USER_STRUCTURE_ROLE_ALL)
diff --git a/packages/common/src/search/classes/Search.class.ts b/packages/common/src/search/classes/Search.class.ts
index 2efcabe254..84a6375dea 100644
--- a/packages/common/src/search/classes/Search.class.ts
+++ b/packages/common/src/search/classes/Search.class.ts
@@ -4,7 +4,7 @@ export class Search {
public searchString: string | null;
public sortKey: string;
public sortValue: SortValues;
- public page: number;
+ public page = 1;
constructor(search?: any) {
this.searchString = search?.searchString ?? null;
diff --git a/packages/common/src/search/types/UsagersFilterCriteriaEntretien.enum.ts b/packages/common/src/search/types/UsagersFilterCriteriaEntretien.enum.ts
new file mode 100644
index 0000000000..a2f9c3e1b2
--- /dev/null
+++ b/packages/common/src/search/types/UsagersFilterCriteriaEntretien.enum.ts
@@ -0,0 +1,4 @@
+export enum UsagersFilterCriteriaEntretien {
+ COMING = "COMING",
+ OVERDUE = "OVERDUE",
+}
diff --git a/packages/common/src/search/types/index.ts b/packages/common/src/search/types/index.ts
index 08fa2e722b..045d56ced0 100644
--- a/packages/common/src/search/types/index.ts
+++ b/packages/common/src/search/types/index.ts
@@ -2,4 +2,5 @@
export * from "./CriteriaSearchField.enum";
export * from "./SortValues.type";
export * from "./Timings.type";
+export * from "./UsagersFilterCriteriaEntretien.enum";
export * from "./UsagersFilterCriteriaStatut.enum";
diff --git a/packages/frontend/src/app/modules/usager-shared/components/etat-civil-parent-form/etat-civil-parent-form.component.spec.ts b/packages/frontend/src/app/modules/usager-shared/components/etat-civil-parent-form/etat-civil-parent-form.component.spec.ts
index 2680628960..6744b15ddf 100644
--- a/packages/frontend/src/app/modules/usager-shared/components/etat-civil-parent-form/etat-civil-parent-form.component.spec.ts
+++ b/packages/frontend/src/app/modules/usager-shared/components/etat-civil-parent-form/etat-civil-parent-form.component.spec.ts
@@ -71,6 +71,7 @@ describe("EtatCivilParentFormComponent", () => {
nom: "TEST",
prenom: "TEST PRENOM ",
sexe: "homme",
+ referrerId: null,
surnom: "Chips",
numeroDistribution: "TSA 1000",
telephone: {
From 2a42f9d5caa5396c9e47730c712f25b3f315c6c3 Mon Sep 17 00:00:00 2001
From: "Yassine R."
Date: Mon, 27 Jan 2025 19:15:39 +0100
Subject: [PATCH 4/5] fix(backend): add validators to search
---
.../backend/src/_common/decorators/index.ts | 12 +-
.../{ => parse-pipes}/ParseRegion.pipe.ts | 0
.../{ => parse-pipes}/ParseString.pipe.ts | 0
.../_common/decorators/parse-pipes/index.ts | 5 +
.../parse-hard-reset-token.pipe.ts | 0
.../{ => parse-pipes}/parse-token.pipe.ts | 0
.../tests/parse-hard-reset-token-pipe.spec.ts | 2 +-
.../decorators/tests/parse-token-pipe.spec.ts | 2 +-
.../{ => transformers}/LowerCaseDecorator.ts | 0
.../PhoneTransformDecorator.ts | 0
.../{ => transformers}/StripTagsDecorator.ts | 0
.../{ => transformers}/TrimDecorator.ts | 0
.../{ => transformers}/TrimOrNullDecorator.ts | 0
.../{ => transformers}/UpperCaseDecorator.ts | 0
.../_common/decorators/transformers/index.ts | 7 +
packages/backend/src/app.bootstrap.ts | 4 +
.../controllers/search-usagers.controller.ts | 212 ++++++++++++++++++
...earch-usagers.controller.security-tests.ts | 35 +++
.../usagers.controller.security-tests.ts | 18 --
.../tests/search-usagers.controller.spec.ts | 132 +++++++++++
.../tests/usagers.controller.spec.ts | 2 -
.../usagers/controllers/usagers.controller.ts | 165 +-------------
.../src/usagers/dto/search-usager.dto.ts | 60 ++---
.../backend/src/usagers/usagers.module.ts | 2 +
packages/backend/src/usagers/utils/index.ts | 3 +
.../utils/validate-search-field.decorator.ts | 33 +++
.../usagers/utils/validate-search-field.ts | 55 +++++
.../users.public.controller.spec.ts | 1 -
.../manage-filters.component.html | 4 +-
.../manage-filters.component.ts | 7 +-
.../usager-filter/UsagersFilterCriteria.ts | 3 +-
.../usager-filter/usagersFilter.service.ts | 7 +-
.../services/manage-usagers.service.ts | 33 ++-
33 files changed, 551 insertions(+), 253 deletions(-)
rename packages/backend/src/_common/decorators/{ => parse-pipes}/ParseRegion.pipe.ts (100%)
rename packages/backend/src/_common/decorators/{ => parse-pipes}/ParseString.pipe.ts (100%)
create mode 100644 packages/backend/src/_common/decorators/parse-pipes/index.ts
rename packages/backend/src/_common/decorators/{ => parse-pipes}/parse-hard-reset-token.pipe.ts (100%)
rename packages/backend/src/_common/decorators/{ => parse-pipes}/parse-token.pipe.ts (100%)
rename packages/backend/src/_common/decorators/{ => transformers}/LowerCaseDecorator.ts (100%)
rename packages/backend/src/_common/decorators/{ => transformers}/PhoneTransformDecorator.ts (100%)
rename packages/backend/src/_common/decorators/{ => transformers}/StripTagsDecorator.ts (100%)
rename packages/backend/src/_common/decorators/{ => transformers}/TrimDecorator.ts (100%)
rename packages/backend/src/_common/decorators/{ => transformers}/TrimOrNullDecorator.ts (100%)
rename packages/backend/src/_common/decorators/{ => transformers}/UpperCaseDecorator.ts (100%)
create mode 100644 packages/backend/src/_common/decorators/transformers/index.ts
create mode 100644 packages/backend/src/usagers/controllers/search-usagers.controller.ts
create mode 100644 packages/backend/src/usagers/controllers/security-tests/search-usagers.controller.security-tests.ts
create mode 100644 packages/backend/src/usagers/controllers/tests/search-usagers.controller.spec.ts
create mode 100644 packages/backend/src/usagers/utils/index.ts
create mode 100644 packages/backend/src/usagers/utils/validate-search-field.decorator.ts
create mode 100644 packages/backend/src/usagers/utils/validate-search-field.ts
diff --git a/packages/backend/src/_common/decorators/index.ts b/packages/backend/src/_common/decorators/index.ts
index 16cc1c51ea..a163f7809a 100644
--- a/packages/backend/src/_common/decorators/index.ts
+++ b/packages/backend/src/_common/decorators/index.ts
@@ -1,13 +1,5 @@
//@index('./*.ts', f => `export * from '${f.path}'`)
export * from "./IsValidPasswordDecorator";
export * from "./IsValidPhoneDecorator";
-export * from "./LowerCaseDecorator";
-export * from "./parse-hard-reset-token.pipe";
-export * from "./parse-token.pipe";
-export * from "./ParseRegion.pipe";
-export * from "./ParseString.pipe";
-export * from "./PhoneTransformDecorator";
-export * from "./StripTagsDecorator";
-export * from "./TrimDecorator";
-export * from "./TrimOrNullDecorator";
-export * from "./UpperCaseDecorator";
+export * from "./transformers";
+export * from "./parse-pipes";
diff --git a/packages/backend/src/_common/decorators/ParseRegion.pipe.ts b/packages/backend/src/_common/decorators/parse-pipes/ParseRegion.pipe.ts
similarity index 100%
rename from packages/backend/src/_common/decorators/ParseRegion.pipe.ts
rename to packages/backend/src/_common/decorators/parse-pipes/ParseRegion.pipe.ts
diff --git a/packages/backend/src/_common/decorators/ParseString.pipe.ts b/packages/backend/src/_common/decorators/parse-pipes/ParseString.pipe.ts
similarity index 100%
rename from packages/backend/src/_common/decorators/ParseString.pipe.ts
rename to packages/backend/src/_common/decorators/parse-pipes/ParseString.pipe.ts
diff --git a/packages/backend/src/_common/decorators/parse-pipes/index.ts b/packages/backend/src/_common/decorators/parse-pipes/index.ts
new file mode 100644
index 0000000000..374b767877
--- /dev/null
+++ b/packages/backend/src/_common/decorators/parse-pipes/index.ts
@@ -0,0 +1,5 @@
+//@index('./*.ts', f => `export * from '${f.path}'`)
+export * from "./parse-hard-reset-token.pipe";
+export * from "./parse-token.pipe";
+export * from "./ParseRegion.pipe";
+export * from "./ParseString.pipe";
diff --git a/packages/backend/src/_common/decorators/parse-hard-reset-token.pipe.ts b/packages/backend/src/_common/decorators/parse-pipes/parse-hard-reset-token.pipe.ts
similarity index 100%
rename from packages/backend/src/_common/decorators/parse-hard-reset-token.pipe.ts
rename to packages/backend/src/_common/decorators/parse-pipes/parse-hard-reset-token.pipe.ts
diff --git a/packages/backend/src/_common/decorators/parse-token.pipe.ts b/packages/backend/src/_common/decorators/parse-pipes/parse-token.pipe.ts
similarity index 100%
rename from packages/backend/src/_common/decorators/parse-token.pipe.ts
rename to packages/backend/src/_common/decorators/parse-pipes/parse-token.pipe.ts
diff --git a/packages/backend/src/_common/decorators/tests/parse-hard-reset-token-pipe.spec.ts b/packages/backend/src/_common/decorators/tests/parse-hard-reset-token-pipe.spec.ts
index 9f4dc94889..ad164dd814 100644
--- a/packages/backend/src/_common/decorators/tests/parse-hard-reset-token-pipe.spec.ts
+++ b/packages/backend/src/_common/decorators/tests/parse-hard-reset-token-pipe.spec.ts
@@ -1,5 +1,5 @@
import { BadRequestException } from "@nestjs/common";
-import { ParseHardResetTokenPipe } from "../parse-hard-reset-token.pipe";
+import { ParseHardResetTokenPipe } from "../parse-pipes/parse-hard-reset-token.pipe";
describe("ParseHardResetTokenPipe", () => {
let pipe: ParseHardResetTokenPipe;
diff --git a/packages/backend/src/_common/decorators/tests/parse-token-pipe.spec.ts b/packages/backend/src/_common/decorators/tests/parse-token-pipe.spec.ts
index de3abfef4a..a70c1464e8 100644
--- a/packages/backend/src/_common/decorators/tests/parse-token-pipe.spec.ts
+++ b/packages/backend/src/_common/decorators/tests/parse-token-pipe.spec.ts
@@ -1,6 +1,6 @@
import { BadRequestException } from "@nestjs/common";
import { tokenGenerator } from "../../../util";
-import { ParseTokenPipe } from "../parse-token.pipe";
+import { ParseTokenPipe } from "../parse-pipes/parse-token.pipe";
describe("ParseTokenPipe", () => {
let pipe: ParseTokenPipe;
diff --git a/packages/backend/src/_common/decorators/LowerCaseDecorator.ts b/packages/backend/src/_common/decorators/transformers/LowerCaseDecorator.ts
similarity index 100%
rename from packages/backend/src/_common/decorators/LowerCaseDecorator.ts
rename to packages/backend/src/_common/decorators/transformers/LowerCaseDecorator.ts
diff --git a/packages/backend/src/_common/decorators/PhoneTransformDecorator.ts b/packages/backend/src/_common/decorators/transformers/PhoneTransformDecorator.ts
similarity index 100%
rename from packages/backend/src/_common/decorators/PhoneTransformDecorator.ts
rename to packages/backend/src/_common/decorators/transformers/PhoneTransformDecorator.ts
diff --git a/packages/backend/src/_common/decorators/StripTagsDecorator.ts b/packages/backend/src/_common/decorators/transformers/StripTagsDecorator.ts
similarity index 100%
rename from packages/backend/src/_common/decorators/StripTagsDecorator.ts
rename to packages/backend/src/_common/decorators/transformers/StripTagsDecorator.ts
diff --git a/packages/backend/src/_common/decorators/TrimDecorator.ts b/packages/backend/src/_common/decorators/transformers/TrimDecorator.ts
similarity index 100%
rename from packages/backend/src/_common/decorators/TrimDecorator.ts
rename to packages/backend/src/_common/decorators/transformers/TrimDecorator.ts
diff --git a/packages/backend/src/_common/decorators/TrimOrNullDecorator.ts b/packages/backend/src/_common/decorators/transformers/TrimOrNullDecorator.ts
similarity index 100%
rename from packages/backend/src/_common/decorators/TrimOrNullDecorator.ts
rename to packages/backend/src/_common/decorators/transformers/TrimOrNullDecorator.ts
diff --git a/packages/backend/src/_common/decorators/UpperCaseDecorator.ts b/packages/backend/src/_common/decorators/transformers/UpperCaseDecorator.ts
similarity index 100%
rename from packages/backend/src/_common/decorators/UpperCaseDecorator.ts
rename to packages/backend/src/_common/decorators/transformers/UpperCaseDecorator.ts
diff --git a/packages/backend/src/_common/decorators/transformers/index.ts b/packages/backend/src/_common/decorators/transformers/index.ts
new file mode 100644
index 0000000000..61d50631fe
--- /dev/null
+++ b/packages/backend/src/_common/decorators/transformers/index.ts
@@ -0,0 +1,7 @@
+//@index('./*.ts', f => `export * from '${f.path}'`)
+export * from "./LowerCaseDecorator";
+export * from "./PhoneTransformDecorator";
+export * from "./StripTagsDecorator";
+export * from "./TrimDecorator";
+export * from "./TrimOrNullDecorator";
+export * from "./UpperCaseDecorator";
diff --git a/packages/backend/src/app.bootstrap.ts b/packages/backend/src/app.bootstrap.ts
index a562d02067..2ab04e3cbb 100644
--- a/packages/backend/src/app.bootstrap.ts
+++ b/packages/backend/src/app.bootstrap.ts
@@ -74,6 +74,10 @@ export async function bootstrapApplication(): Promise<{
stopAtFirstError: true,
enableDebugMessages: true,
disableErrorMessages: domifaConfig().envId !== "local",
+ transform: true,
+ transformOptions: {
+ enableImplicitConversion: false,
+ },
})
);
diff --git a/packages/backend/src/usagers/controllers/search-usagers.controller.ts b/packages/backend/src/usagers/controllers/search-usagers.controller.ts
new file mode 100644
index 0000000000..56a58f6100
--- /dev/null
+++ b/packages/backend/src/usagers/controllers/search-usagers.controller.ts
@@ -0,0 +1,212 @@
+import {
+ Usager,
+ UsagerDecision,
+ CriteriaSearchField,
+ getUsagerDeadlines,
+ ETAPE_ENTRETIEN,
+} from "@domifa/common";
+import {
+ Body,
+ Controller,
+ Get,
+ ParseBoolPipe,
+ Post,
+ Query,
+ UseGuards,
+} from "@nestjs/common";
+import { AuthGuard } from "@nestjs/passport";
+import { ApiBearerAuth } from "@nestjs/swagger";
+import { format, parse, subMinutes } from "date-fns";
+import { Not } from "typeorm";
+import {
+ USER_STRUCTURE_ROLE_ALL,
+ UserStructureAuthenticated,
+} from "../../_common/model";
+import { AllowUserStructureRoles, CurrentUser } from "../../auth/decorators";
+import { AppUserGuard } from "../../auth/guards";
+import {
+ usagerRepository,
+ USAGER_LIGHT_ATTRIBUTES,
+ joinSelectFields,
+} from "../../database";
+
+import { SearchUsagerDto } from "../dto";
+
+@Controller("search-usagers")
+@UseGuards(AuthGuard("jwt"), AppUserGuard)
+@ApiBearerAuth()
+export class SearchUsagersController {
+ @Get()
+ @AllowUserStructureRoles(...USER_STRUCTURE_ROLE_ALL)
+ public async findAllByStructure(
+ @Query("chargerTousRadies", new ParseBoolPipe())
+ chargerTousRadies: boolean,
+ @CurrentUser() user: UserStructureAuthenticated
+ ) {
+ const usagersNonRadies = await usagerRepository.find({
+ where: {
+ statut: Not("RADIE"),
+ structureId: user.structureId,
+ },
+ select: USAGER_LIGHT_ATTRIBUTES,
+ });
+
+ const usagersRadiesFirsts = await usagerRepository.find({
+ where: {
+ statut: "RADIE",
+ structureId: user.structureId,
+ },
+ select: USAGER_LIGHT_ATTRIBUTES,
+ take: chargerTousRadies ? undefined : 1600,
+ });
+
+ const usagersRadiesTotalCount = chargerTousRadies
+ ? usagersRadiesFirsts.length
+ : await usagerRepository.count({
+ where: {
+ statut: "RADIE",
+ structureId: user.structureId,
+ },
+ });
+
+ const filterHistorique = (usager: Usager) => {
+ if (usager.historique && Array.isArray(usager.historique)) {
+ usager.historique = usager.historique.map((item: UsagerDecision) => ({
+ statut: item.statut,
+ dateDecision: item.dateDecision,
+ dateDebut: item.dateDebut,
+ dateFin: item.dateFin,
+ })) as UsagerDecision[];
+ }
+ return usager;
+ };
+
+ const usagersMerges = [...usagersNonRadies, ...usagersRadiesFirsts].map(
+ filterHistorique
+ );
+
+ return {
+ usagersRadiesTotalCount,
+ usagers: usagersMerges,
+ };
+ }
+
+ @Get("update-manage")
+ @AllowUserStructureRoles(...USER_STRUCTURE_ROLE_ALL)
+ public async updateManage(@CurrentUser() user: UserStructureAuthenticated) {
+ return await usagerRepository
+ .createQueryBuilder()
+ .select(joinSelectFields(USAGER_LIGHT_ATTRIBUTES))
+ .where(
+ `"structureId" = :structureId AND "updatedAt" >= :fiveMinutesAgo`,
+ {
+ structureId: user.structureId,
+ fiveMinutesAgo: subMinutes(new Date(), 5),
+ }
+ )
+ .getRawMany();
+ }
+
+ @Post("search-radies")
+ @AllowUserStructureRoles(...USER_STRUCTURE_ROLE_ALL)
+ public async searchInRadies(
+ @Body() search: SearchUsagerDto,
+ @CurrentUser() user: UserStructureAuthenticated
+ ) {
+ const query = usagerRepository
+ .createQueryBuilder("usager")
+ .select(joinSelectFields(USAGER_LIGHT_ATTRIBUTES))
+ .where(`"structureId" = :structureId and statut = 'RADIE'`, {
+ structureId: user.structureId,
+ });
+
+ if (search.searchString) {
+ if (search.searchStringField === CriteriaSearchField.DEFAULT) {
+ query.andWhere("nom_prenom_surnom_ref ILIKE :str", {
+ str: `%${search.searchString}%`,
+ });
+ } else if (search.searchStringField === CriteriaSearchField.BIRTH_DATE) {
+ const formattedDate = format(
+ parse(search.searchString, "ddMMyyyy", new Date()),
+ "yyyy-MM-dd"
+ );
+ query.andWhere(`DATE("dateNaissance") = DATE(:date)`, {
+ date: formattedDate,
+ });
+ } else if (
+ search.searchStringField === CriteriaSearchField.PHONE_NUMBER
+ ) {
+ query.andWhere(`telephone->>'numero' ILIKE :phone`, {
+ phone: `%${search.searchString}%`,
+ });
+ }
+ }
+
+ if (search?.lastInteractionDate) {
+ const deadlines = getUsagerDeadlines();
+ const date = deadlines[search.lastInteractionDate].value;
+
+ query.andWhere(
+ `("lastInteraction"->>'dateInteraction')::timestamp >= :dateRef::timestamp`,
+ {
+ dateRef: date,
+ }
+ );
+ }
+
+ if (typeof search?.referrerId !== "undefined") {
+ query.andWhere(
+ search.referrerId === null
+ ? `"referrerId" IS NULL`
+ : `"referrerId" = :referrerId`,
+ { referrerId: search.referrerId }
+ );
+ }
+
+ if (search?.entretien) {
+ query.andWhere(
+ `rdv->>'dateRdv' IS NOT NULL AND "etapeDemande" <= :step AND (rdv->>'dateRdv')::date ${
+ search.entretien === "COMING" ? ">" : "<"
+ } CURRENT_DATE`,
+ { step: ETAPE_ENTRETIEN }
+ );
+ }
+
+ if (search?.echeance) {
+ const deadlines = getUsagerDeadlines();
+ const now = new Date();
+ const deadline = deadlines[search.echeance];
+
+ if (search.echeance === "EXCEEDED") {
+ query.andWhere(`(decision->>'dateDecision')::timestamp < :now`, {
+ now,
+ });
+ } else if (search.echeance.startsWith("NEXT_")) {
+ query.andWhere(
+ `(decision->>'dateDecision')::timestamp <= :deadline AND (decision->>'dateDecision')::timestamp > :now`,
+ {
+ deadline: deadline.value,
+ now,
+ }
+ );
+ } else if (search?.echeance.startsWith("PREVIOUS_")) {
+ query.andWhere(`(decision->>'dateDecision')::timestamp < :deadline`, {
+ deadline: deadline.value,
+ now,
+ });
+ }
+ }
+
+ if (
+ !search.searchString &&
+ !search?.echeance &&
+ !search?.entretien &&
+ typeof search?.referrerId !== undefined &&
+ !search?.lastInteractionDate
+ ) {
+ query.take(100);
+ }
+
+ return await query.getRawMany();
+ }
+}
diff --git a/packages/backend/src/usagers/controllers/security-tests/search-usagers.controller.security-tests.ts b/packages/backend/src/usagers/controllers/security-tests/search-usagers.controller.security-tests.ts
new file mode 100644
index 0000000000..423faa0408
--- /dev/null
+++ b/packages/backend/src/usagers/controllers/security-tests/search-usagers.controller.security-tests.ts
@@ -0,0 +1,35 @@
+import { AppTestContext, AppTestHttpClient } from "../../../util/test";
+import { USER_STRUCTURE_ROLE_ALL } from "../../../_common/model";
+import {
+ AppTestHttpClientSecurityTestDef,
+ expectedResponseStatusBuilder,
+} from "../../../_tests";
+
+////////////////// IMPORTANT //////////////////
+//
+// Ce fichier doit être importé dans :
+// - API_SECURITY_STRUCTURE_CONTROLLER_TEST_DEFS
+//
+
+const CONTROLLER = "SearchUsagersController";
+
+export const UsagersControllerSecurityTests: AppTestHttpClientSecurityTestDef[] =
+ [
+ {
+ label: `${CONTROLLER}.findAllByStructure`,
+ query: async (context: AppTestContext) => ({
+ response: await AppTestHttpClient.get(
+ "/usagers?chargerTousRadies=false",
+ {
+ context,
+ }
+ ),
+ expectedStatus: expectedResponseStatusBuilder.allowStructureOnly(
+ context.user,
+ {
+ roles: USER_STRUCTURE_ROLE_ALL,
+ }
+ ),
+ }),
+ },
+ ];
diff --git a/packages/backend/src/usagers/controllers/security-tests/usagers.controller.security-tests.ts b/packages/backend/src/usagers/controllers/security-tests/usagers.controller.security-tests.ts
index 41798ac9a9..08050d6885 100644
--- a/packages/backend/src/usagers/controllers/security-tests/usagers.controller.security-tests.ts
+++ b/packages/backend/src/usagers/controllers/security-tests/usagers.controller.security-tests.ts
@@ -1,6 +1,5 @@
import { HttpStatus } from "@nestjs/common";
import { AppTestContext, AppTestHttpClient } from "../../../util/test";
-import { USER_STRUCTURE_ROLE_ALL } from "../../../_common/model";
import {
AppTestHttpClientSecurityTestDef,
expectedResponseStatusBuilder,
@@ -16,23 +15,6 @@ const CONTROLLER = "UsagersController";
export const UsagersControllerSecurityTests: AppTestHttpClientSecurityTestDef[] =
[
- {
- label: `${CONTROLLER}.findAllByStructure`,
- query: async (context: AppTestContext) => ({
- response: await AppTestHttpClient.get(
- "/usagers?chargerTousRadies=false",
- {
- context,
- }
- ),
- expectedStatus: expectedResponseStatusBuilder.allowStructureOnly(
- context.user,
- {
- roles: USER_STRUCTURE_ROLE_ALL,
- }
- ),
- }),
- },
{
label: `${CONTROLLER}.checkDuplicates`,
query: async (context: AppTestContext) => ({
diff --git a/packages/backend/src/usagers/controllers/tests/search-usagers.controller.spec.ts b/packages/backend/src/usagers/controllers/tests/search-usagers.controller.spec.ts
new file mode 100644
index 0000000000..0ef168c9fa
--- /dev/null
+++ b/packages/backend/src/usagers/controllers/tests/search-usagers.controller.spec.ts
@@ -0,0 +1,132 @@
+import { SearchUsagersController } from "../search-usagers.controller";
+import { TESTS_USERS_STRUCTURE } from "../../../_tests";
+import { UsersModule } from "../../../users/users.module";
+import {
+ AppTestContext,
+ AppTestHelper,
+ AppTestHttpClient,
+} from "../../../util/test";
+import { UsagersModule } from "../../usagers.module";
+import { CriteriaSearchField } from "@domifa/common";
+
+describe("SearchUsagersController", () => {
+ let controller: SearchUsagersController;
+ let context: AppTestContext;
+
+ afterAll(async () => {
+ await AppTestHelper.tearDownTestApp(context);
+ });
+
+ beforeAll(async () => {
+ context = await AppTestHelper.bootstrapTestApp(
+ {
+ controllers: [SearchUsagersController],
+ imports: [UsagersModule, UsersModule],
+ },
+ { initApp: true }
+ );
+
+ const authInfo =
+ TESTS_USERS_STRUCTURE.BY_EMAIL["preprod.domifa@fabrique.social.gouv.fr"];
+ await AppTestHelper.authenticateStructure(authInfo, { context });
+
+ controller = context.module.get(
+ SearchUsagersController
+ );
+ });
+
+ it("should be defined", () => {
+ expect(controller).toBeDefined();
+ });
+
+ it("should search with all parameters", async () => {
+ const response = await AppTestHttpClient.post(
+ "/search-usagers/search-radies",
+ {
+ context,
+ body: {
+ searchString: "dupuis",
+ searchStringField: CriteriaSearchField.DEFAULT,
+ echeance: "NEXT_TWO_WEEKS",
+ lastInteractionDate: "PREVIOUS_TWO_MONTHS",
+ entretien: "COMING",
+ referrerId: 42,
+ },
+ }
+ ).expect(201);
+
+ expect(response.body).toBeDefined();
+ });
+
+ it("should search with null referrerId", async () => {
+ const response = await AppTestHttpClient.post(
+ "/search-usagers/search-radies",
+ {
+ context,
+ body: {
+ searchString: " DIé",
+ searchStringField: CriteriaSearchField.DEFAULT,
+ referrerId: null,
+ },
+ }
+ ).expect(201);
+ expect(response.body).toBeDefined();
+ expect(response.body.length).toEqual(1);
+ expect(response.body[0].nom).toEqual("Rara");
+ });
+
+ it("should handle phone number search", async () => {
+ const response = await AppTestHttpClient.post(
+ "/search-usagers/search-radies",
+ {
+ context,
+ body: {
+ searchString: "06. 06-06/06-06",
+ searchStringField: CriteriaSearchField.PHONE_NUMBER,
+ },
+ }
+ ).expect(201);
+
+ expect(response.body).toBeDefined();
+ expect(response.body.length).toEqual(1);
+ expect(response.body[0].nom).toEqual("Loumiel");
+ });
+
+ it("should handle birth date search", async () => {
+ const response = await AppTestHttpClient.post(
+ "/search-usagers/search-radies",
+ {
+ context,
+ body: {
+ searchString: "18/04/1990",
+ searchStringField: CriteriaSearchField.BIRTH_DATE,
+ },
+ }
+ ).expect(201);
+
+ expect(response.body).toBeDefined();
+ expect(response.body.length).toEqual(1);
+ expect(response.body[0].nom).toEqual("Loumiel");
+ });
+
+ it("should reject invalid birth date", async () => {
+ await AppTestHttpClient.post("/search-usagers/search-radies", {
+ context,
+ body: {
+ searchString: "32/13/1999",
+ searchStringField: CriteriaSearchField.BIRTH_DATE,
+ },
+ }).expect(400);
+ });
+
+ it("should reject invalid echeance value", async () => {
+ await AppTestHttpClient.post("/search-usagers/search-radies", {
+ context,
+ body: {
+ searchString: "dupuis",
+ searchStringField: CriteriaSearchField.DEFAULT,
+ echeance: "INVALID_VALUE",
+ },
+ }).expect(400);
+ });
+});
diff --git a/packages/backend/src/usagers/controllers/tests/usagers.controller.spec.ts b/packages/backend/src/usagers/controllers/tests/usagers.controller.spec.ts
index bc0314d767..344016636a 100644
--- a/packages/backend/src/usagers/controllers/tests/usagers.controller.spec.ts
+++ b/packages/backend/src/usagers/controllers/tests/usagers.controller.spec.ts
@@ -77,11 +77,9 @@ describe("Usagers Controller", () => {
expect(new Date(usager.decision.dateDecision)).toEqual(new Date());
expect(new Date(usager.historique[0].dateDecision)).toEqual(new Date());
- // Type de dom
expect(usager.typeDom).toEqual("PREMIERE_DOM");
expect(usager.decision.typeDom).toEqual("PREMIERE_DOM");
expect(usager.historique[0].typeDom).toEqual("PREMIERE_DOM");
- // Trim et nettoyage des données
expect(usager.nom).toEqual(exceptedResponse.nom);
expect(usager.prenom).toEqual(exceptedResponse.prenom);
diff --git a/packages/backend/src/usagers/controllers/usagers.controller.ts b/packages/backend/src/usagers/controllers/usagers.controller.ts
index 1784d8abe8..4d8003a898 100644
--- a/packages/backend/src/usagers/controllers/usagers.controller.ts
+++ b/packages/backend/src/usagers/controllers/usagers.controller.ts
@@ -5,12 +5,10 @@ import {
Get,
HttpStatus,
Param,
- ParseBoolPipe,
ParseEnumPipe,
ParseIntPipe,
Patch,
Post,
- Query,
Res,
UseGuards,
} from "@nestjs/common";
@@ -25,7 +23,6 @@ import { AppUserGuard } from "../../auth/guards";
import { UsagerAccessGuard } from "../../auth/guards/usager-access.guard";
import {
usagerRepository,
- USAGER_LIGHT_ATTRIBUTES,
joinSelectFields,
messageSmsRepository,
usagerDocsRepository,
@@ -43,7 +40,6 @@ import {
EntretienDto,
ContactDetailsDto,
} from "../dto";
-import { SearchUsagerDto } from "../dto/search-usager.dto";
import { UsagersService } from "../services";
import { AppLogsService } from "../../modules/app-logs/app-logs.service";
import { generateCerfaData } from "../services/cerfa";
@@ -53,19 +49,10 @@ import pdftk = require("node-pdftk");
import { join, resolve } from "path";
import { readFile } from "fs-extra";
import { ExpressResponse } from "../../util/express";
-import {
- Usager,
- ETAPE_DOCUMENTS,
- CerfaDocType,
- UsagerDecision,
- getUsagerDeadlines,
- CriteriaSearchField,
-} from "@domifa/common";
+import { Usager, ETAPE_DOCUMENTS, CerfaDocType } from "@domifa/common";
import { UsagerHistoryStateService } from "../services/usagerHistoryState.service";
import { domifaConfig } from "../../config";
import { FileManagerService } from "../../util/file-manager/file-manager.service";
-import { Not } from "typeorm";
-import { subMinutes } from "date-fns";
@Controller("usagers")
@ApiTags("usagers")
@@ -79,156 +66,6 @@ export class UsagersController {
private readonly fileManagerService: FileManagerService
) {}
- @Get()
- @AllowUserStructureRoles(...USER_STRUCTURE_ROLE_ALL)
- public async findAllByStructure(
- @Query("chargerTousRadies", new ParseBoolPipe())
- chargerTousRadies: boolean,
- @CurrentUser() user: UserStructureAuthenticated
- ) {
- const usagersNonRadies = await usagerRepository.find({
- where: {
- statut: Not("RADIE"),
- structureId: user.structureId,
- },
- select: USAGER_LIGHT_ATTRIBUTES,
- });
-
- const usagersRadiesFirsts = await usagerRepository.find({
- where: {
- statut: "RADIE",
- structureId: user.structureId,
- },
- select: USAGER_LIGHT_ATTRIBUTES,
- take: chargerTousRadies ? undefined : 1600,
- });
-
- const usagersRadiesTotalCount = chargerTousRadies
- ? usagersRadiesFirsts.length
- : await usagerRepository.count({
- where: {
- statut: "RADIE",
- structureId: user.structureId,
- },
- });
-
- const filterHistorique = (usager: Usager) => {
- if (usager.historique && Array.isArray(usager.historique)) {
- usager.historique = usager.historique.map((item: UsagerDecision) => ({
- statut: item.statut,
- dateDecision: item.dateDecision,
- dateDebut: item.dateDebut,
- dateFin: item.dateFin,
- })) as UsagerDecision[];
- }
- return usager;
- };
-
- const usagersMerges = [...usagersNonRadies, ...usagersRadiesFirsts].map(
- filterHistorique
- );
-
- return {
- usagersRadiesTotalCount,
- usagers: usagersMerges,
- };
- }
-
- @Get("update-manage")
- @AllowUserStructureRoles(...USER_STRUCTURE_ROLE_ALL)
- public async updateManage(@CurrentUser() user: UserStructureAuthenticated) {
- return await usagerRepository
- .createQueryBuilder()
- .select(joinSelectFields(USAGER_LIGHT_ATTRIBUTES))
- .where(
- `"structureId" = :structureId AND "updatedAt" >= :fiveMinutesAgo`,
- {
- structureId: user.structureId,
- fiveMinutesAgo: subMinutes(new Date(), 5),
- }
- )
- .getRawMany();
- }
-
- @Post("search-radies")
- @AllowUserStructureRoles(...USER_STRUCTURE_ROLE_ALL)
- public async searchInRadies(
- @Body() search: SearchUsagerDto,
- @CurrentUser() user: UserStructureAuthenticated
- ) {
- const query = usagerRepository
- .createQueryBuilder("usager")
- .select(joinSelectFields(USAGER_LIGHT_ATTRIBUTES))
- .where(`"structureId" = :structureId and statut = 'RADIE'`, {
- structureId: user.structureId,
- });
-
- if (search.searchString) {
- if (search.searchStringField === CriteriaSearchField.DEFAULT) {
- query.andWhere("nom_prenom_surnom_ref ILIKE :str", {
- str: `%${search.searchString}%`,
- });
- } else if (search.searchStringField === CriteriaSearchField.BIRTH_DATE) {
- query.andWhere(`DATE("dateNaissance") = DATE(:date)`, {
- date: search.searchString,
- });
- } else if (
- search.searchStringField === CriteriaSearchField.PHONE_NUMBER
- ) {
- query.andWhere(`telephone->>'numero' ILIKE :phone`, {
- phone: `%${search.searchString}%`,
- });
- }
- }
-
- if (search?.lastInteractionDate) {
- const deadlines = getUsagerDeadlines();
- const date = deadlines[search.lastInteractionDate].value;
-
- query.andWhere(
- `("lastInteraction"->>'dateInteraction')::timestamp >= :date`,
- {
- date,
- }
- );
- }
-
- if (search?.echeance) {
- const deadlines = getUsagerDeadlines();
- const now = new Date();
- const deadline = deadlines[search.echeance];
-
- if (search.echeance === "EXCEEDED") {
- query.andWhere(`(decision->>'dateDecision')::timestamp < :now`, {
- now,
- });
- } else if (search.echeance.startsWith("NEXT_")) {
- query.andWhere(
- `(decision->>'dateDecision')::timestamp <= :deadline AND (decision->>'dateDecision')::timestamp > :now`,
- {
- deadline: deadline.value,
- now,
- }
- );
- } else if (search?.echeance.startsWith("PREVIOUS_")) {
- query.andWhere(`(decision->>'dateDecision')::timestamp < :deadline`, {
- deadline: deadline.value,
- now,
- });
- }
- }
-
- if (
- !search.searchString &&
- !search?.echeance &&
- !search?.lastInteractionDate
- ) {
- query.take(100);
- }
-
- return await query.getRawMany();
- }
-
@Post()
@AllowUserStructureRoles("simple", "responsable", "admin")
public createUsager(
diff --git a/packages/backend/src/usagers/dto/search-usager.dto.ts b/packages/backend/src/usagers/dto/search-usager.dto.ts
index eee69f646e..05c3c3f36e 100644
--- a/packages/backend/src/usagers/dto/search-usager.dto.ts
+++ b/packages/backend/src/usagers/dto/search-usager.dto.ts
@@ -1,54 +1,47 @@
import { ApiProperty } from "@nestjs/swagger";
-import { IsIn, IsOptional, IsString, MinLength } from "class-validator";
import {
- LowerCaseTransform,
- StripTagsTransform,
-} from "../../_common/decorators";
+ IsIn,
+ IsNumber,
+ IsOptional,
+ IsString,
+ MinLength,
+ ValidateIf,
+} from "class-validator";
import {
CriteriaSearchField,
normalizeString,
UsagersFilterCriteriaDernierPassage,
UsagersFilterCriteriaEcheance,
+ UsagersFilterCriteriaEntretien,
} from "@domifa/common";
import { Transform } from "class-transformer";
-import { isValid, parse } from "date-fns";
-import { BadRequestException } from "@nestjs/common";
+import { ValidateSearchField } from "../utils";
export class SearchUsagerDto {
@ApiProperty({
example: "dupuis",
description: "Nom ou prénom",
})
- @IsOptional()
- @IsString()
- @MinLength(1)
- @StripTagsTransform()
- @LowerCaseTransform()
@Transform(({ value, obj }) => {
if (!value) {
return null;
}
- switch (obj.searchStringField) {
- case CriteriaSearchField.PHONE_NUMBER:
- return value.replace(/\D/g, "");
-
- case CriteriaSearchField.BIRTH_DATE:
- const cleanDate = value.replace(/\D/g, "");
- const parsedDate = parse(cleanDate, "ddMMyyyy", new Date());
-
- if (!isValid(parsedDate)) {
- throw new BadRequestException(
- 'Format de date invalide. Utilisez le format "dd/MM/yyyy"'
- );
- }
- return cleanDate;
-
- case CriteriaSearchField.DEFAULT:
- default:
- return normalizeString(value).trim();
+ if (
+ [
+ CriteriaSearchField.PHONE_NUMBER,
+ CriteriaSearchField.BIRTH_DATE,
+ ].includes(obj.searchStringField)
+ ) {
+ return value.replace(/\D/g, "");
}
+
+ return normalizeString(value).trim();
})
+ @ValidateIf((obj) => obj.searchStringField)
+ @IsString()
+ @MinLength(1)
+ @ValidateSearchField()
public searchString!: string;
@IsIn(Object.values(CriteriaSearchField))
@@ -67,4 +60,13 @@ export class SearchUsagerDto {
@IsIn(["PREVIOUS_TWO_MONTHS", "PREVIOUS_THREE_MONTHS"])
@IsOptional()
public readonly lastInteractionDate: UsagersFilterCriteriaDernierPassage;
+
+ @IsIn(Object.values(UsagersFilterCriteriaEntretien))
+ @IsOptional()
+ public readonly entretien: UsagersFilterCriteriaEntretien;
+
+ @IsNumber()
+ @IsOptional()
+ @ValidateIf((_object, value) => value !== null)
+ public readonly referrerId: number | null;
}
diff --git a/packages/backend/src/usagers/usagers.module.ts b/packages/backend/src/usagers/usagers.module.ts
index d0b689c47a..9b9225e5a4 100644
--- a/packages/backend/src/usagers/usagers.module.ts
+++ b/packages/backend/src/usagers/usagers.module.ts
@@ -23,6 +23,7 @@ import { ImportCreatorService } from "./controllers/import/step3-create";
import { FileManagerService } from "../util/file-manager/file-manager.service";
import { AppLogsService } from "../modules/app-logs/app-logs.service";
import { MailsModule } from "../modules/mails/mails.module";
+import { SearchUsagersController } from "./controllers/search-usagers.controller";
@Module({
controllers: [
@@ -35,6 +36,7 @@ import { MailsModule } from "../modules/mails/mails.module";
UsagerDocsController,
ExportStructureUsagersController,
UsagerOptionsController,
+ SearchUsagersController,
],
exports: [UsagersService, UsagerHistoryStateService, ImportCreatorService],
imports: [
diff --git a/packages/backend/src/usagers/utils/index.ts b/packages/backend/src/usagers/utils/index.ts
new file mode 100644
index 0000000000..c727341e0c
--- /dev/null
+++ b/packages/backend/src/usagers/utils/index.ts
@@ -0,0 +1,3 @@
+// @index('./*', f => `export * from '${f.path}'`)
+export * from "./validate-search-field.decorator";
+export * from "./validate-search-field";
diff --git a/packages/backend/src/usagers/utils/validate-search-field.decorator.ts b/packages/backend/src/usagers/utils/validate-search-field.decorator.ts
new file mode 100644
index 0000000000..42809a8a77
--- /dev/null
+++ b/packages/backend/src/usagers/utils/validate-search-field.decorator.ts
@@ -0,0 +1,33 @@
+import {
+ ValidationOptions,
+ registerDecorator,
+ ValidationArguments,
+} from "class-validator";
+import { validateSearchField } from "./validate-search-field";
+
+export function ValidateSearchField(validationOptions?: ValidationOptions) {
+ return function (object: object, propertyName: string) {
+ registerDecorator({
+ name: "validateSearchField",
+ target: object.constructor,
+ propertyName: propertyName,
+ options: validationOptions,
+ validator: {
+ validate(value: string, args: ValidationArguments) {
+ const searchStringField = args.object["searchStringField"];
+ if (!searchStringField) {
+ return false;
+ }
+ return validateSearchField(value, searchStringField);
+ },
+ defaultMessage(args: ValidationArguments) {
+ const searchStringField = args.object["searchStringField"];
+ if (!searchStringField) {
+ return "Le type de recherche est requis";
+ }
+ return "La valeur de recherche est invalide pour le type spécifié";
+ },
+ },
+ });
+ };
+}
diff --git a/packages/backend/src/usagers/utils/validate-search-field.ts b/packages/backend/src/usagers/utils/validate-search-field.ts
new file mode 100644
index 0000000000..388e8f1756
--- /dev/null
+++ b/packages/backend/src/usagers/utils/validate-search-field.ts
@@ -0,0 +1,55 @@
+import { CriteriaSearchField, normalizeString } from "@domifa/common";
+import { BadRequestException } from "@nestjs/common";
+import { isValid, parse } from "date-fns";
+
+export function validateSearchField(
+ value: string,
+ searchField: CriteriaSearchField
+): boolean {
+ if (!value || !searchField) {
+ return false;
+ }
+
+ try {
+ switch (searchField) {
+ case CriteriaSearchField.BIRTH_DATE:
+ const cleanDate = value.replace(/\D/g, "");
+ if (cleanDate.length !== 8) {
+ throw new BadRequestException(
+ 'Format de date invalide. La date doit être au format "jj/mm/aaaa"'
+ );
+ }
+
+ const parsedDate = parse(cleanDate, "ddMMyyyy", new Date());
+ if (!isValid(parsedDate)) {
+ throw new BadRequestException(
+ "Date invalide. Vérifiez que le jour et le mois sont corrects"
+ );
+ }
+ return true;
+
+ case CriteriaSearchField.PHONE_NUMBER:
+ const cleanPhone = value.replace(/\D/g, "");
+ if (cleanPhone.length === 0) {
+ throw new BadRequestException(
+ "Le numéro de téléphone doit contenir au moins un chiffre"
+ );
+ }
+ return true;
+
+ default:
+ const cleanText = normalizeString(value).trim();
+ if (cleanText.length === 0) {
+ throw new BadRequestException(
+ "Le texte de recherche doit contenir au moins un caractère"
+ );
+ }
+ return true;
+ }
+ } catch (error) {
+ if (error instanceof BadRequestException) {
+ throw error;
+ }
+ return false;
+ }
+}
diff --git a/packages/backend/src/users/controllers/users.public.controller.spec.ts b/packages/backend/src/users/controllers/users.public.controller.spec.ts
index ce135963e9..b64ee5bbed 100644
--- a/packages/backend/src/users/controllers/users.public.controller.spec.ts
+++ b/packages/backend/src/users/controllers/users.public.controller.spec.ts
@@ -18,7 +18,6 @@ describe("Users Public Controller", () => {
context = await AppTestHelper.bootstrapTestApp({
controllers: [UsersPublicController],
imports: [MailsModule, StructuresModule, UsagersModule, HttpModule],
- providers: [],
});
controller = context.module.get(
UsersPublicController
diff --git a/packages/frontend/src/app/modules/manage-usagers/components/manage-filters/manage-filters.component.html b/packages/frontend/src/app/modules/manage-usagers/components/manage-filters/manage-filters.component.html
index 2b171fe98b..a89f6d22dd 100644
--- a/packages/frontend/src/app/modules/manage-usagers/components/manage-filters/manage-filters.component.html
+++ b/packages/frontend/src/app/modules/manage-usagers/components/manage-filters/manage-filters.component.html
@@ -278,7 +278,7 @@
(click)="
updateFilters.emit({
element: 'entretien',
- value: 'COMING'
+ value: UsagersFilterCriteriaEntretien.COMING
})
"
ngbDropdownItem
@@ -291,7 +291,7 @@
(click)="
updateFilters.emit({
element: 'entretien',
- value: 'OVERDUE'
+ value: UsagersFilterCriteriaEntretien.OVERDUE
})
"
ngbDropdownItem
diff --git a/packages/frontend/src/app/modules/manage-usagers/components/manage-filters/manage-filters.component.ts b/packages/frontend/src/app/modules/manage-usagers/components/manage-filters/manage-filters.component.ts
index cbab4a03f5..f7e4eea4ec 100644
--- a/packages/frontend/src/app/modules/manage-usagers/components/manage-filters/manage-filters.component.ts
+++ b/packages/frontend/src/app/modules/manage-usagers/components/manage-filters/manage-filters.component.ts
@@ -14,6 +14,7 @@ import {
extractDeadlines,
UsagersFilterCriteriaDernierPassage,
UsagersFilterCriteriaEcheance,
+ UsagersFilterCriteriaEntretien,
UsagersFilterCriteriaStatut,
UserStructureProfile,
} from "@domifa/common";
@@ -33,6 +34,8 @@ export class ManageFiltersComponent implements OnInit, OnChanges {
@Output() public readonly updateFilters = new EventEmitter();
public readonly UsagersFilterCriteriaStatut = UsagersFilterCriteriaStatut;
+ public readonly UsagersFilterCriteriaEntretien =
+ UsagersFilterCriteriaEntretien;
public readonly labelsEcheance =
extractDeadlines([
@@ -53,7 +56,9 @@ export class ManageFiltersComponent implements OnInit, OnChanges {
"PREVIOUS_THREE_MONTHS",
]);
- public readonly labelsEntretien = {
+ public readonly labelsEntretien: {
+ [key in UsagersFilterCriteriaEntretien]: string;
+ } = {
COMING: "à venir",
OVERDUE: "date dépassée",
};
diff --git a/packages/frontend/src/app/modules/manage-usagers/components/usager-filter/UsagersFilterCriteria.ts b/packages/frontend/src/app/modules/manage-usagers/components/usager-filter/UsagersFilterCriteria.ts
index 930734fb41..b525920d63 100644
--- a/packages/frontend/src/app/modules/manage-usagers/components/usager-filter/UsagersFilterCriteria.ts
+++ b/packages/frontend/src/app/modules/manage-usagers/components/usager-filter/UsagersFilterCriteria.ts
@@ -3,6 +3,7 @@ import {
Search,
UsagersFilterCriteriaDernierPassage,
UsagersFilterCriteriaEcheance,
+ UsagersFilterCriteriaEntretien,
UsagersFilterCriteriaStatut,
} from "@domifa/common";
@@ -13,8 +14,6 @@ export type UsagersFilterCriteriaSortKey =
| "RDV"
| "ID";
-export type UsagersFilterCriteriaEntretien = "COMING" | "OVERDUE";
-
export class UsagersFilterCriteria extends Search {
// text search filter
// DEFAULT = Nom, prénom du domicilié, nom, prénom d'un des ayant-droits
diff --git a/packages/frontend/src/app/modules/manage-usagers/components/usager-filter/usagersFilter.service.ts b/packages/frontend/src/app/modules/manage-usagers/components/usager-filter/usagersFilter.service.ts
index 509f4bf612..2ba66a24f4 100644
--- a/packages/frontend/src/app/modules/manage-usagers/components/usager-filter/usagersFilter.service.ts
+++ b/packages/frontend/src/app/modules/manage-usagers/components/usager-filter/usagersFilter.service.ts
@@ -3,6 +3,7 @@ import {
CriteriaSearchField,
ETAPE_ENTRETIEN,
search,
+ UsagersFilterCriteriaEntretien,
} from "@domifa/common";
import { UsagerLight } from "../../../../../_common/model";
import {
@@ -135,7 +136,7 @@ function buildActiveFilters(criteria: UsagersFilterCriteria) {
function filterByEntretien(
usager: UsagerLight,
- entretien: "COMING" | "OVERDUE"
+ entretien: UsagersFilterCriteriaEntretien
): boolean {
const now = new Date().toISOString().split("T")[0];
@@ -144,5 +145,7 @@ function filterByEntretien(
}
const dateRdv = new Date(usager.rdv.dateRdv).toISOString().split("T")[0];
- return entretien === "COMING" ? dateRdv > now : dateRdv < now;
+ return entretien === UsagersFilterCriteriaEntretien.COMING
+ ? dateRdv > now
+ : dateRdv < now;
}
diff --git a/packages/frontend/src/app/modules/manage-usagers/services/manage-usagers.service.ts b/packages/frontend/src/app/modules/manage-usagers/services/manage-usagers.service.ts
index 9897cb83b2..a4b5973aba 100644
--- a/packages/frontend/src/app/modules/manage-usagers/services/manage-usagers.service.ts
+++ b/packages/frontend/src/app/modules/manage-usagers/services/manage-usagers.service.ts
@@ -3,9 +3,6 @@ import { Injectable } from "@angular/core";
import { Observable } from "rxjs";
import { map, tap } from "rxjs/operators";
import { environment } from "src/environments/environment";
-
-import { UsagerLight } from "../../../../_common/model/usager/UsagerLight.type";
-
import { Store } from "@ngrx/store";
import {
setUsagerInformation,
@@ -13,12 +10,13 @@ import {
UsagerState,
} from "../../../shared";
import { UsagersFilterCriteria } from "../components/usager-filter";
+import { UsagerLight } from "../../../../_common/model";
@Injectable({
providedIn: "root",
})
export class ManageUsagersService {
- public endPointUsagers = environment.apiUrl + "usagers";
+ public endPoint = environment.apiUrl + "search-usagers";
constructor(
private readonly http: HttpClient,
@@ -32,7 +30,7 @@ export class ManageUsagersService {
}): Observable {
return this.http
.get<{ usagers: UsagerLight[]; usagersRadiesTotalCount: number }>(
- `${environment.apiUrl}usagers/?chargerTousRadies=${chargerTousRadies}`
+ `${this.endPoint}?chargerTousRadies=${chargerTousRadies}`
)
.pipe(
map(
@@ -64,10 +62,7 @@ export class ManageUsagersService {
filters: UsagersFilterCriteria
): Observable {
return this.http
- .post(
- `${environment.apiUrl}usagers/search-radies`,
- filters
- )
+ .post(`${this.endPoint}search-radies`, filters)
.pipe(
tap((usagers: UsagerLight[]) => {
if (usagers?.length) {
@@ -83,16 +78,14 @@ export class ManageUsagersService {
}
public updateManage(): Observable {
- return this.http
- .get(`${environment.apiUrl}usagers/update-manage`)
- .pipe(
- tap((usagers: UsagerLight[]) => {
- if (usagers?.length) {
- this.store.dispatch(
- usagerActions.updateManyUsagersForManage({ usagers })
- );
- }
- })
- );
+ return this.http.get(`${this.endPoint}update-manage`).pipe(
+ tap((usagers: UsagerLight[]) => {
+ if (usagers?.length) {
+ this.store.dispatch(
+ usagerActions.updateManyUsagersForManage({ usagers })
+ );
+ }
+ })
+ );
}
}
From 328bf627ab896852d6d30aa754810b5d25a6add4 Mon Sep 17 00:00:00 2001
From: "Yassine R."
Date: Mon, 27 Jan 2025 19:22:56 +0100
Subject: [PATCH 5/5] fix(front): fix unit tests
---
.../src/usagers/controllers/search-usagers.controller.ts | 2 +-
.../backend/src/users/controllers/users.controller.ts | 2 +-
.../manage-users/services/manage-users.service.spec.ts | 9 ++++++++-
.../etat-civil-parent-form.component.spec.ts | 1 +
4 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/packages/backend/src/usagers/controllers/search-usagers.controller.ts b/packages/backend/src/usagers/controllers/search-usagers.controller.ts
index 56a58f6100..7669ff9044 100644
--- a/packages/backend/src/usagers/controllers/search-usagers.controller.ts
+++ b/packages/backend/src/usagers/controllers/search-usagers.controller.ts
@@ -201,7 +201,7 @@ export class SearchUsagersController {
!search.searchString &&
!search?.echeance &&
!search?.entretien &&
- typeof search?.referrerId !== undefined &&
+ typeof search?.referrerId !== "undefined" &&
!search?.lastInteractionDate
) {
query.take(100);
diff --git a/packages/backend/src/users/controllers/users.controller.ts b/packages/backend/src/users/controllers/users.controller.ts
index d87b90275f..57916bc651 100644
--- a/packages/backend/src/users/controllers/users.controller.ts
+++ b/packages/backend/src/users/controllers/users.controller.ts
@@ -48,9 +48,9 @@ import { AppUserGuard, CanGetUserStructureGuard } from "../../auth/guards";
@ApiTags("users")
@UseGuards(AuthGuard("jwt"), AppUserGuard)
export class UsersController {
- @AllowUserStructureRoles("responsable", "admin")
@ApiBearerAuth()
@ApiOperation({ summary: "Liste des utilisateurs" })
+ @AllowUserStructureRoles(...USER_STRUCTURE_ROLE_ALL)
@Get("")
public async getUsers(
@CurrentUser() user: UserStructureAuthenticated
diff --git a/packages/frontend/src/app/modules/manage-users/services/manage-users.service.spec.ts b/packages/frontend/src/app/modules/manage-users/services/manage-users.service.spec.ts
index 276c155625..778f11be9f 100644
--- a/packages/frontend/src/app/modules/manage-users/services/manage-users.service.spec.ts
+++ b/packages/frontend/src/app/modules/manage-users/services/manage-users.service.spec.ts
@@ -1,12 +1,19 @@
import { TestBed } from "@angular/core/testing";
import { ManageUsersService } from "./manage-users.service";
+import { CommonModule, APP_BASE_HREF } from "@angular/common";
+import { HttpClientTestingModule } from "@angular/common/http/testing";
+import { CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
describe("ManageUsersService", () => {
let service: ManageUsersService;
beforeEach(() => {
- TestBed.configureTestingModule({});
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule, CommonModule],
+ providers: [{ provide: APP_BASE_HREF, useValue: "/" }],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ });
service = TestBed.inject(ManageUsersService);
});
diff --git a/packages/frontend/src/app/modules/usager-shared/components/etat-civil-parent-form/etat-civil-parent-form.component.spec.ts b/packages/frontend/src/app/modules/usager-shared/components/etat-civil-parent-form/etat-civil-parent-form.component.spec.ts
index 6744b15ddf..d8124bd28e 100644
--- a/packages/frontend/src/app/modules/usager-shared/components/etat-civil-parent-form/etat-civil-parent-form.component.spec.ts
+++ b/packages/frontend/src/app/modules/usager-shared/components/etat-civil-parent-form/etat-civil-parent-form.component.spec.ts
@@ -95,6 +95,7 @@ describe("EtatCivilParentFormComponent", () => {
prenom: "AD PRENOM",
},
],
+ referrerId: null,
contactByPhone: true,
customRef: null,
dateNaissance: new Date("2022-08-03T21:59:59.999Z"),