Skip to content

Commit 80b0446

Browse files
authored
Change password (#41)
* force password * Update identities.module.ts * save
1 parent 3ab26e3 commit 80b0446

12 files changed

+283
-89
lines changed

src/core/backends/backends.service.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export class BackendsService extends AbstractQueueProcessor {
6565
await this.identitiesService.model.findByIdAndUpdate(isSyncedJob?.concernedTo?.id, {
6666
$set: {
6767
state: IdentityState.SYNCED,
68+
lastBackendSync: new Date(),
6869
},
6970
});
7071
this.logger.warn(`Job already completed, syncing... [${job.id}::COMPLETED]`);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { ApiProperty } from '@nestjs/swagger';
2+
import { IsString } from 'class-validator';
3+
4+
export class ForcePasswordDto {
5+
@IsString()
6+
@ApiProperty({ example: '66d80ab41821baca9bf965b2', description: 'User object id', type: String })
7+
public id: string;
8+
9+
@IsString()
10+
@ApiProperty({ example: 'MyNewPassword', description: 'New password', type: String })
11+
public newPassword: string;
12+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { ApiProperty } from '@nestjs/swagger';
2+
import { IsString } from 'class-validator';
3+
4+
export class NeedChangePasswordDto {
5+
@IsString()
6+
@ApiProperty({ example: '66d80ab41821baca9bf965b2', description: 'User object id', type: String })
7+
public id: string;
8+
9+
}

src/management/identities/_enums/data-status.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
//DELETED : soft delete
55
export enum DataStatusEnum {
66
ACTIVE = 1,
7-
INACTIVE = 0,
7+
NOTINITIALIZED = 0,
88
DELETED = -1,
9+
PASSWORDNEEDTOBECHANGED=-2,
10+
INACTIVE = -3,
911
}

src/management/identities/_schemas/identities.schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export class Identities extends AbstractSchema {
2222
@Prop({ type: Number, enum: IdentityLifecycle, default: IdentityLifecycle.INACTIVE })
2323
public lifecycle: IdentityLifecycle;
2424

25-
@Prop({ type: Number, enum: DataStatusEnum, default: DataStatusEnum.INACTIVE })
25+
@Prop({ type: Number, enum: DataStatusEnum, default: DataStatusEnum.NOTINITIALIZED })
2626
public dataStatus: DataStatusEnum;
2727

2828
@Prop({ type: Boolean, default: false })

src/management/identities/abstract-identities.service.ts

Lines changed: 66 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,29 @@
1-
import { BadRequestException, forwardRef, HttpException, Inject, Injectable } from '@nestjs/common';
2-
import { InjectModel } from '@nestjs/mongoose';
3-
import { Document, Model, ModifyResult, Query, Types } from 'mongoose';
4-
import { AbstractServiceSchema } from '~/_common/abstracts/abstract.service.schema';
5-
import { AbstractSchema } from '~/_common/abstracts/schemas/abstract.schema';
6-
import { ValidationConfigException, ValidationSchemaException } from '~/_common/errors/ValidationException';
7-
import { IdentitiesUpsertDto } from './_dto/identities.dto';
8-
import { IdentityState } from './_enums/states.enum';
9-
import { Identities } from './_schemas/identities.schema';
10-
import { IdentitiesValidationService } from './validations/identities.validation.service';
11-
import { FactorydriveService } from '@the-software-compagny/nestjs_module_factorydrive';
12-
import { BackendsService } from '~/core/backends/backends.service';
13-
import { construct, omit } from 'radash';
14-
import { toPlainAndCrush } from '~/_common/functions/to-plain-and-crush';
15-
import { createHash } from 'node:crypto';
1+
import {BadRequestException, forwardRef, HttpException, Inject, Injectable} from '@nestjs/common';
2+
import {InjectModel} from '@nestjs/mongoose';
3+
import {Document, Model, ModifyResult, Query, Types} from 'mongoose';
4+
import {AbstractServiceSchema} from '~/_common/abstracts/abstract.service.schema';
5+
import {AbstractSchema} from '~/_common/abstracts/schemas/abstract.schema';
6+
import {ValidationConfigException, ValidationSchemaException} from '~/_common/errors/ValidationException';
7+
import {IdentitiesUpsertDto} from './_dto/identities.dto';
8+
import {IdentityState} from './_enums/states.enum';
9+
import {Identities} from './_schemas/identities.schema';
10+
import {IdentitiesValidationService} from './validations/identities.validation.service';
11+
import {FactorydriveService} from '@the-software-compagny/nestjs_module_factorydrive';
12+
import {BackendsService} from '~/core/backends/backends.service';
13+
import {construct, omit} from 'radash';
14+
import {toPlainAndCrush} from '~/_common/functions/to-plain-and-crush';
15+
import {createHash} from 'node:crypto';
16+
import {PasswdadmService} from "~/settings/passwdadm.service";
17+
import {DataStatusEnum} from "~/management/identities/_enums/data-status";
18+
import {JobState} from "~/core/jobs/_enums/state.enum";
1619

1720
@Injectable()
1821
export abstract class AbstractIdentitiesService extends AbstractServiceSchema {
1922
public constructor(
2023
@InjectModel(Identities.name) protected _model: Model<Identities>,
2124
protected readonly _validation: IdentitiesValidationService,
2225
protected readonly storage: FactorydriveService,
26+
protected readonly passwdAdmService: PasswdadmService,
2327
@Inject(forwardRef(() => BackendsService)) protected readonly backends: BackendsService,
2428
) {
2529
super();
@@ -138,4 +142,51 @@ export abstract class AbstractIdentitiesService extends AbstractServiceSchema {
138142
hash.update(data);
139143
return hash.digest('hex').toString();
140144
}
145+
public async activation(id: string, status: DataStatusEnum) {
146+
//recherche de l'identité
147+
let identity: Identities = null;
148+
let statusChanged = false;
149+
try {
150+
identity = await this.findById<Identities>(id);
151+
} catch (error) {
152+
throw new HttpException('Id not found', 400);
153+
}
154+
if (identity.lastBackendSync === null) {
155+
throw new HttpException('Identity has never been synced', 400);
156+
}
157+
if (identity.dataStatus !== DataStatusEnum.DELETED) {
158+
identity.dataStatus = status;
159+
statusChanged = true;
160+
} else {
161+
throw new BadRequestException('Identity is in status deleted');
162+
}
163+
//sauvegarde de l'identité
164+
if (statusChanged) {
165+
// le dataStaus à changé on envoye l info aux backend et on enregistre l identité
166+
// Envoi du status au backend
167+
let statusBackend=true
168+
if (status == DataStatusEnum.INACTIVE || status == DataStatusEnum.PASSWORDNEEDTOBECHANGED){
169+
statusBackend= false
170+
}
171+
const result = await this.backends.activationIdentity(identity._id.toString(),statusBackend);
172+
if (result.state === JobState.COMPLETED) {
173+
await super.update(identity._id, identity);
174+
} else {
175+
throw new HttpException('Backend failed', 400);
176+
}
177+
}
178+
}
179+
public async askToChangePassword(id: string){
180+
try {
181+
const identity = await this.findById<Identities>(id);
182+
if (identity.dataStatus === DataStatusEnum.ACTIVE) {
183+
identity.dataStatus = DataStatusEnum.PASSWORDNEEDTOBECHANGED
184+
await super.update(identity._id, identity);
185+
} else {
186+
throw new BadRequestException('Identity not in active');
187+
}
188+
} catch (error) {
189+
throw new HttpException('Id not found', 400);
190+
}
191+
}
141192
}

src/management/identities/identities-activation.controller.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { AbstractController } from '~/_common/abstracts/abstract.controller';
2-
import { IdentitiesActivationService } from '~/management/identities/identities-activation.service';
3-
import { ApiOperation, ApiResponse, ApiTags} from '@nestjs/swagger';
4-
import { Body, Controller, HttpStatus, Post, Res} from '@nestjs/common';
5-
import { Response } from 'express';
6-
import { ActivationDto } from '~/management/identities/_dto/_parts/activation-dto';
1+
import {AbstractController} from '~/_common/abstracts/abstract.controller';
2+
import {IdentitiesActivationService} from '~/management/identities/identities-activation.service';
3+
import {ApiOperation, ApiResponse, ApiTags} from '@nestjs/swagger';
4+
import {Body, Controller, HttpStatus, Post, Res} from '@nestjs/common';
5+
import {Response} from 'express';
6+
import {ActivationDto} from '~/management/identities/_dto/_parts/activation-dto';
7+
import {DataStatusEnum} from "~/management/identities/_enums/data-status";
78

89
@ApiTags('management/identities')
910
@Controller('identities')
@@ -17,7 +18,11 @@ export class IdentitiesActivationController extends AbstractController {
1718
@ApiResponse({ status: HttpStatus.OK })
1819
public async activation(@Res() res: Response, @Body() body: ActivationDto): Promise<Response> {
1920
try {
20-
const data = await this._service.activation(body.id, body.status);
21+
let param = DataStatusEnum.INACTIVE
22+
if ( body.status === true){
23+
param=DataStatusEnum.ACTIVE
24+
}
25+
const data = await this._service.activation(body.id, param);
2126
return res.status(HttpStatus.OK).json({
2227
statusCode: HttpStatus.OK,
2328
data,
Lines changed: 2 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,6 @@
11
import { AbstractIdentitiesService } from '~/management/identities/abstract-identities.service';
2-
import { Identities } from '~/management/identities/_schemas/identities.schema';
3-
import { BadRequestException, HttpException } from '@nestjs/common';
4-
import { DataStatusEnum } from '~/management/identities/_enums/data-status';
5-
import { JobState } from '~/core/jobs/_enums/state.enum';
2+
63

74
export class IdentitiesActivationService extends AbstractIdentitiesService {
8-
public async activation(id: string, status: boolean) {
9-
//recherche de l'identité
10-
let identity: Identities = null;
11-
let statusChanged = false;
12-
try {
13-
identity = await this.findById<Identities>(id);
14-
} catch (error) {
15-
throw new HttpException('Id not found', 400);
16-
}
17-
if (identity.lastBackendSync === null) {
18-
throw new HttpException('Identity has never been synced', 400);
19-
}
20-
if (identity.dataStatus !== DataStatusEnum.DELETED) {
21-
if (status) {
22-
if (identity.dataStatus !== DataStatusEnum.ACTIVE) {
23-
identity.dataStatus = DataStatusEnum.ACTIVE;
24-
statusChanged = true;
25-
}
26-
} else {
27-
if (identity.dataStatus !== DataStatusEnum.INACTIVE) {
28-
identity.dataStatus = DataStatusEnum.INACTIVE;
29-
statusChanged = true;
30-
}
31-
}
32-
} else {
33-
throw new BadRequestException('Identity is in status deleted');
34-
}
35-
//sauvegarde de l'identité
36-
if (statusChanged) {
37-
// le dataStaus à changé on envoye l info aux backend et on enregistre l identité
38-
const result = await this.backends.activationIdentity(identity._id.toString(), status);
39-
if (result.state === JobState.COMPLETED) {
40-
await super.update(identity._id, identity);
41-
} else {
42-
throw new HttpException('Backend failed', 400);
43-
}
44-
}
45-
}
5+
466
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { AbstractController } from '~/_common/abstracts/abstract.controller';
2+
import { IdentitiesActivationService } from '~/management/identities/identities-activation.service';
3+
import { ApiOperation, ApiResponse, ApiTags} from '@nestjs/swagger';
4+
import { Body, Controller, HttpStatus, Post, Res} from '@nestjs/common';
5+
import { Response } from 'express';
6+
import { ActivationDto } from '~/management/identities/_dto/_parts/activation-dto';
7+
import {ForcePasswordDto} from "~/management/identities/_dto/force-password-dto";
8+
import {IdentitiesForcepasswordService} from "~/management/identities/identities-forcepassword.service";
9+
import {NeedChangePasswordDto} from "~/management/identities/_dto/need-change-password.dto";
10+
11+
@ApiTags('management/identities')
12+
@Controller('identities')
13+
export class IdentitiesForcePasswordController extends AbstractController {
14+
public constructor(protected readonly _service: IdentitiesForcepasswordService) {
15+
super();
16+
}
17+
@Post('forcepassword')
18+
@ApiOperation({ summary: 'force le mot de passe de l identite' })
19+
@ApiResponse({ status: HttpStatus.OK })
20+
public async forcePassword(@Res() res: Response, @Body() body: ForcePasswordDto): Promise<Response> {
21+
try {
22+
const data = await this._service.forcePassword(body.id, body.newPassword);
23+
return res.status(HttpStatus.OK).json({
24+
statusCode: HttpStatus.OK,
25+
data,
26+
});
27+
} catch (error) {
28+
return res.status(HttpStatus.BAD_REQUEST).json({
29+
statusCode: HttpStatus.BAD_REQUEST,
30+
message: error.message,
31+
});
32+
}
33+
}
34+
@Post('needtochangepassword')
35+
@ApiOperation({ summary: "force l'utilisateur a changer son mot de passe" })
36+
@ApiResponse({ status: HttpStatus.OK })
37+
public async needToChangePassword(@Res() res: Response, @Body() body: NeedChangePasswordDto): Promise<Response> {
38+
try {
39+
const data = await this._service.needToChangePassword(body.id)
40+
return res.status(HttpStatus.OK).json({
41+
statusCode: HttpStatus.OK,
42+
data,
43+
});
44+
} catch (error) {
45+
return res.status(HttpStatus.BAD_REQUEST).json({
46+
statusCode: HttpStatus.BAD_REQUEST,
47+
message: error.message,
48+
});
49+
}
50+
}
51+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import {AbstractIdentitiesService} from '~/management/identities/abstract-identities.service';
2+
import {Identities} from '~/management/identities/_schemas/identities.schema';
3+
import {BadRequestException, HttpException, Injectable} from '@nestjs/common';
4+
import {DataStatusEnum} from '~/management/identities/_enums/data-status';
5+
import {ActionType} from "~/core/backends/_enum/action-type.enum";
6+
7+
8+
@Injectable()
9+
export class IdentitiesForcepasswordService extends AbstractIdentitiesService {
10+
11+
public async forcePassword(id: string, newPassword: string) {
12+
//recherche de l'identité
13+
let identity: Identities = null;
14+
try {
15+
identity = await this.findById<Identities>(id);
16+
} catch (error) {
17+
throw new HttpException('Id not found', 400);
18+
}
19+
if (identity.lastBackendSync === null) {
20+
throw new HttpException('Identity has never been synced', 400);
21+
}
22+
if (identity.dataStatus === DataStatusEnum.DELETED) {
23+
throw new BadRequestException('Identity is in status deleted');
24+
}
25+
//changement du password check de la policy
26+
if ((await this.passwdAdmService.checkPolicies(newPassword)) === false) {
27+
throw new BadRequestException({
28+
message: 'Une erreur est survenue : Le mot de passe ne respecte pas la politique des mots de passe',
29+
error: 'Bad Request',
30+
statusCode: 400,
31+
});
32+
}
33+
//ok on envoie le changement de mdp
34+
try{
35+
const [_, response] = await this.backends.executeJob(
36+
ActionType.IDENTITY_PASSWORD_RESET,
37+
identity._id,
38+
{ uid: identity.inetOrgPerson.uid, newPassword: newPassword, ...identity.toJSON() },
39+
{
40+
async: false,
41+
timeoutDiscard: true,
42+
disableLogs: false,
43+
switchToProcessing: false,
44+
updateStatus: false,
45+
},
46+
);
47+
if (response?.status === 0) {
48+
//activation de l'identité
49+
await this.activation(id,DataStatusEnum.ACTIVE)
50+
return [_, response];
51+
}
52+
}catch (e) {
53+
this.logger.error('Error while reseting password. ' + e + ` (uid=${identity.inetOrgPerson.uid})`);
54+
throw new BadRequestException(
55+
'Une erreur est survenue : Tentative de réinitialisation de mot de passe impossible',
56+
);
57+
}
58+
}
59+
public async needToChangePassword(id: string){
60+
let identity: Identities = null;
61+
try {
62+
identity = await this.findById<Identities>(id);
63+
} catch (error) {
64+
throw new HttpException('Id not found', 400);
65+
}
66+
if (identity.lastBackendSync === null) {
67+
throw new HttpException('Identity has never been synced', 400);
68+
}
69+
if (identity.dataStatus === DataStatusEnum.DELETED) {
70+
throw new BadRequestException('Identity is in status deleted');
71+
}
72+
if (identity.dataStatus === DataStatusEnum.INACTIVE) {
73+
throw new BadRequestException('Identity is in status disabled');
74+
}
75+
//desactivation du compte
76+
try{
77+
await this.activation(id,DataStatusEnum.PASSWORDNEEDTOBECHANGED)
78+
}catch{
79+
throw new BadRequestException('Error changing status');
80+
}
81+
82+
}
83+
84+
}

0 commit comments

Comments
 (0)