Compare commits
No commits in common. "9aea26805d9530fcd732c46526adacfbea140106" and "61b45cd830bce604a855d072fab2e6255f4611e7" have entirely different histories.
9aea26805d
...
61b45cd830
@ -50,8 +50,8 @@ export class Users {
|
|||||||
@Column({ unique: true, name: 'email' })
|
@Column({ unique: true, name: 'email' })
|
||||||
email: string;
|
email: string;
|
||||||
|
|
||||||
@Column({ name: 'password', nullable: true })
|
@Column({ name: 'password' })
|
||||||
password?: string;
|
password: string;
|
||||||
|
|
||||||
@Column({ name: 'prenom', nullable: true })
|
@Column({ name: 'prenom', nullable: true })
|
||||||
prenom?: string;
|
prenom?: string;
|
||||||
@ -96,6 +96,12 @@ export class Users {
|
|||||||
@Column({ nullable: true, name: 'telephone' })
|
@Column({ nullable: true, name: 'telephone' })
|
||||||
telephone?: string;
|
telephone?: string;
|
||||||
|
|
||||||
|
@Column({ name: 'mobile', nullable: true })
|
||||||
|
mobile?: string;
|
||||||
|
|
||||||
|
@Column({ name: 'telephone_fixe', nullable: true })
|
||||||
|
telephone_fixe?: string;
|
||||||
|
|
||||||
@Column({ nullable: true, name: 'adresse' })
|
@Column({ nullable: true, name: 'adresse' })
|
||||||
adresse?: string;
|
adresse?: string;
|
||||||
|
|
||||||
@ -111,12 +117,6 @@ export class Users {
|
|||||||
@Column({ default: false, name: 'changement_mdp_obligatoire' })
|
@Column({ default: false, name: 'changement_mdp_obligatoire' })
|
||||||
changement_mdp_obligatoire: boolean;
|
changement_mdp_obligatoire: boolean;
|
||||||
|
|
||||||
@Column({ nullable: true, name: 'token_creation_mdp', length: 255 })
|
|
||||||
token_creation_mdp?: string;
|
|
||||||
|
|
||||||
@Column({ type: 'timestamptz', nullable: true, name: 'token_creation_mdp_expire_le' })
|
|
||||||
token_creation_mdp_expire_le?: Date;
|
|
||||||
|
|
||||||
@Column({ nullable: true, name: 'ville' })
|
@Column({ nullable: true, name: 'ville' })
|
||||||
ville?: string;
|
ville?: string;
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { LoginDto } from './dto/login.dto';
|
|||||||
import { AuthService } from './auth.service';
|
import { AuthService } from './auth.service';
|
||||||
import { Public } from 'src/common/decorators/public.decorator';
|
import { Public } from 'src/common/decorators/public.decorator';
|
||||||
import { RegisterDto } from './dto/register.dto';
|
import { RegisterDto } from './dto/register.dto';
|
||||||
import { RegisterParentDto } from './dto/register-parent.dto';
|
|
||||||
import { ApiBearerAuth, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
import { ApiBearerAuth, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||||
import { AuthGuard } from 'src/common/guards/auth.guard';
|
import { AuthGuard } from 'src/common/guards/auth.guard';
|
||||||
import type { Request } from 'express';
|
import type { Request } from 'express';
|
||||||
@ -31,21 +30,11 @@ export class AuthController {
|
|||||||
|
|
||||||
@Public()
|
@Public()
|
||||||
@Post('register')
|
@Post('register')
|
||||||
@ApiOperation({ summary: 'Inscription (OBSOLÈTE - utiliser /register/parent)' })
|
@ApiOperation({ summary: 'Inscription' })
|
||||||
@ApiResponse({ status: 409, description: 'Email déjà utilisé' })
|
|
||||||
async register(@Body() dto: RegisterDto) {
|
async register(@Body() dto: RegisterDto) {
|
||||||
return this.authService.register(dto);
|
return this.authService.register(dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Public()
|
|
||||||
@Post('register/parent')
|
|
||||||
@ApiOperation({ summary: 'Inscription Parent (étape 1/6)' })
|
|
||||||
@ApiResponse({ status: 201, description: 'Inscription réussie' })
|
|
||||||
@ApiResponse({ status: 409, description: 'Email déjà utilisé' })
|
|
||||||
async registerParent(@Body() dto: RegisterParentDto) {
|
|
||||||
return this.authService.registerParent(dto);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Public()
|
@Public()
|
||||||
@Post('refresh')
|
@Post('refresh')
|
||||||
@ApiBearerAuth('refresh_token')
|
@ApiBearerAuth('refresh_token')
|
||||||
|
|||||||
@ -1,19 +1,13 @@
|
|||||||
import { forwardRef, Module } from '@nestjs/common';
|
import { forwardRef, Module } from '@nestjs/common';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
||||||
import { AuthController } from './auth.controller';
|
import { AuthController } from './auth.controller';
|
||||||
import { AuthService } from './auth.service';
|
import { AuthService } from './auth.service';
|
||||||
import { UserModule } from '../user/user.module';
|
import { UserModule } from '../user/user.module';
|
||||||
import { JwtModule } from '@nestjs/jwt';
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||||
import { Users } from 'src/entities/users.entity';
|
|
||||||
import { Parents } from 'src/entities/parents.entity';
|
|
||||||
import { AppConfigModule } from 'src/modules/config';
|
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
TypeOrmModule.forFeature([Users, Parents]),
|
|
||||||
forwardRef(() => UserModule),
|
forwardRef(() => UserModule),
|
||||||
AppConfigModule,
|
|
||||||
JwtModule.registerAsync({
|
JwtModule.registerAsync({
|
||||||
imports: [ConfigModule],
|
imports: [ConfigModule],
|
||||||
useFactory: (config: ConfigService) => ({
|
useFactory: (config: ConfigService) => ({
|
||||||
|
|||||||
@ -3,19 +3,13 @@ import {
|
|||||||
Injectable,
|
Injectable,
|
||||||
UnauthorizedException,
|
UnauthorizedException,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
|
||||||
import { Repository } from 'typeorm';
|
|
||||||
import { UserService } from '../user/user.service';
|
import { UserService } from '../user/user.service';
|
||||||
import { JwtService } from '@nestjs/jwt';
|
import { JwtService } from '@nestjs/jwt';
|
||||||
import * as bcrypt from 'bcrypt';
|
import * as bcrypt from 'bcrypt';
|
||||||
import * as crypto from 'crypto';
|
|
||||||
import { RegisterDto } from './dto/register.dto';
|
import { RegisterDto } from './dto/register.dto';
|
||||||
import { RegisterParentDto } from './dto/register-parent.dto';
|
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { RoleType, StatutUtilisateurType, Users } from 'src/entities/users.entity';
|
import { RoleType, StatutUtilisateurType, Users } from 'src/entities/users.entity';
|
||||||
import { Parents } from 'src/entities/parents.entity';
|
|
||||||
import { LoginDto } from './dto/login.dto';
|
import { LoginDto } from './dto/login.dto';
|
||||||
import { AppConfigService } from 'src/modules/config/config.service';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
@ -23,11 +17,6 @@ export class AuthService {
|
|||||||
private readonly usersService: UserService,
|
private readonly usersService: UserService,
|
||||||
private readonly jwtService: JwtService,
|
private readonly jwtService: JwtService,
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
private readonly appConfigService: AppConfigService,
|
|
||||||
@InjectRepository(Parents)
|
|
||||||
private readonly parentsRepo: Repository<Parents>,
|
|
||||||
@InjectRepository(Users)
|
|
||||||
private readonly usersRepo: Repository<Users>,
|
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,37 +43,29 @@ export class AuthService {
|
|||||||
* Connexion utilisateur
|
* Connexion utilisateur
|
||||||
*/
|
*/
|
||||||
async login(dto: LoginDto) {
|
async login(dto: LoginDto) {
|
||||||
const user = await this.usersService.findByEmailOrNull(dto.email);
|
try {
|
||||||
|
const user = await this.usersService.findByEmailOrNull(dto.email);
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
|
throw new UnauthorizedException('Email invalide');
|
||||||
|
}
|
||||||
|
console.log("Tentative login:", dto.email, JSON.stringify(dto.password));
|
||||||
|
console.log("Utilisateur trouvé:", user.email, user.password);
|
||||||
|
|
||||||
|
const isMatch = await bcrypt.compare(dto.password, user.password);
|
||||||
|
console.log("Résultat bcrypt.compare:", isMatch);
|
||||||
|
if (!isMatch) {
|
||||||
|
throw new UnauthorizedException('Mot de passe invalide');
|
||||||
|
}
|
||||||
|
// if (user.password !== dto.password) {
|
||||||
|
// throw new UnauthorizedException('Mot de passe invalide');
|
||||||
|
// }
|
||||||
|
|
||||||
|
return this.generateTokens(user.id, user.email, user.role);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erreur de connexion :', error);
|
||||||
throw new UnauthorizedException('Identifiants invalides');
|
throw new UnauthorizedException('Identifiants invalides');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vérifier que le mot de passe existe (compte activé)
|
|
||||||
if (!user.password) {
|
|
||||||
throw new UnauthorizedException(
|
|
||||||
'Compte non activé. Veuillez créer votre mot de passe via le lien reçu par email.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifier le mot de passe
|
|
||||||
const isMatch = await bcrypt.compare(dto.password, user.password);
|
|
||||||
if (!isMatch) {
|
|
||||||
throw new UnauthorizedException('Identifiants invalides');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifier le statut du compte
|
|
||||||
if (user.statut === StatutUtilisateurType.EN_ATTENTE) {
|
|
||||||
throw new UnauthorizedException(
|
|
||||||
'Votre compte est en attente de validation par un gestionnaire.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user.statut === StatutUtilisateurType.SUSPENDU) {
|
|
||||||
throw new UnauthorizedException('Votre compte a été suspendu. Contactez un administrateur.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.generateTokens(user.id, user.email, user.role);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -108,8 +89,7 @@ export class AuthService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inscription utilisateur OBSOLÈTE - Utiliser registerParent() ou registerAM()
|
* Inscription utilisateur lambda (parent ou assistante maternelle)
|
||||||
* @deprecated
|
|
||||||
*/
|
*/
|
||||||
async register(registerDto: RegisterDto) {
|
async register(registerDto: RegisterDto) {
|
||||||
const exists = await this.usersService.findByEmailOrNull(registerDto.email);
|
const exists = await this.usersService.findByEmailOrNull(registerDto.email);
|
||||||
@ -149,131 +129,6 @@ export class AuthService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Inscription Parent (étape 1/6 du workflow CDC)
|
|
||||||
* SANS mot de passe - Token de création MDP généré
|
|
||||||
*/
|
|
||||||
async registerParent(dto: RegisterParentDto) {
|
|
||||||
// 1. Vérifier que l'email n'existe pas
|
|
||||||
const exists = await this.usersService.findByEmailOrNull(dto.email);
|
|
||||||
if (exists) {
|
|
||||||
throw new ConflictException('Un compte avec cet email existe déjà');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Vérifier l'email du co-parent s'il existe
|
|
||||||
if (dto.co_parent_email) {
|
|
||||||
const coParentExists = await this.usersService.findByEmailOrNull(dto.co_parent_email);
|
|
||||||
if (coParentExists) {
|
|
||||||
throw new ConflictException('L\'email du co-parent est déjà utilisé');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Récupérer la durée d'expiration du token depuis la config
|
|
||||||
const tokenExpiryDays = await this.appConfigService.get<number>(
|
|
||||||
'password_reset_token_expiry_days',
|
|
||||||
7,
|
|
||||||
);
|
|
||||||
|
|
||||||
// 4. Générer les tokens de création de mot de passe
|
|
||||||
const tokenCreationMdp = crypto.randomUUID();
|
|
||||||
const tokenExpiration = new Date();
|
|
||||||
tokenExpiration.setDate(tokenExpiration.getDate() + tokenExpiryDays);
|
|
||||||
|
|
||||||
// 5. Transaction : Créer Parent 1 + Parent 2 (si existe) + entités parents
|
|
||||||
const result = await this.usersRepo.manager.transaction(async (manager) => {
|
|
||||||
// Créer Parent 1
|
|
||||||
const parent1 = manager.create(Users, {
|
|
||||||
email: dto.email,
|
|
||||||
prenom: dto.prenom,
|
|
||||||
nom: dto.nom,
|
|
||||||
role: RoleType.PARENT,
|
|
||||||
statut: StatutUtilisateurType.EN_ATTENTE,
|
|
||||||
telephone: dto.telephone,
|
|
||||||
adresse: dto.adresse,
|
|
||||||
code_postal: dto.code_postal,
|
|
||||||
ville: dto.ville,
|
|
||||||
profession: dto.profession,
|
|
||||||
situation_familiale: dto.situation_familiale,
|
|
||||||
token_creation_mdp: tokenCreationMdp,
|
|
||||||
token_creation_mdp_expire_le: tokenExpiration,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (dto.date_naissance) {
|
|
||||||
parent1.date_naissance = new Date(dto.date_naissance);
|
|
||||||
}
|
|
||||||
|
|
||||||
const savedParent1 = await manager.save(Users, parent1);
|
|
||||||
|
|
||||||
// Créer Parent 2 si renseigné
|
|
||||||
let savedParent2: Users | null = null;
|
|
||||||
let tokenCoParent: string | null = null;
|
|
||||||
|
|
||||||
if (dto.co_parent_email && dto.co_parent_prenom && dto.co_parent_nom) {
|
|
||||||
tokenCoParent = crypto.randomUUID();
|
|
||||||
const tokenExpirationCoParent = new Date();
|
|
||||||
tokenExpirationCoParent.setDate(tokenExpirationCoParent.getDate() + tokenExpiryDays);
|
|
||||||
|
|
||||||
const parent2 = manager.create(Users, {
|
|
||||||
email: dto.co_parent_email,
|
|
||||||
prenom: dto.co_parent_prenom,
|
|
||||||
nom: dto.co_parent_nom,
|
|
||||||
role: RoleType.PARENT,
|
|
||||||
statut: StatutUtilisateurType.EN_ATTENTE,
|
|
||||||
telephone: dto.co_parent_telephone,
|
|
||||||
adresse: dto.co_parent_meme_adresse ? dto.adresse : dto.co_parent_adresse,
|
|
||||||
code_postal: dto.co_parent_meme_adresse ? dto.code_postal : dto.co_parent_code_postal,
|
|
||||||
ville: dto.co_parent_meme_adresse ? dto.ville : dto.co_parent_ville,
|
|
||||||
token_creation_mdp: tokenCoParent,
|
|
||||||
token_creation_mdp_expire_le: tokenExpirationCoParent,
|
|
||||||
});
|
|
||||||
|
|
||||||
savedParent2 = await manager.save(Users, parent2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Créer l'entité métier Parents pour Parent 1
|
|
||||||
const parentEntity = manager.create(Parents, {
|
|
||||||
user_id: savedParent1.id,
|
|
||||||
});
|
|
||||||
parentEntity.user = savedParent1;
|
|
||||||
if (savedParent2) {
|
|
||||||
parentEntity.co_parent = savedParent2;
|
|
||||||
}
|
|
||||||
|
|
||||||
await manager.save(Parents, parentEntity);
|
|
||||||
|
|
||||||
// Créer l'entité métier Parents pour Parent 2 (si existe)
|
|
||||||
if (savedParent2) {
|
|
||||||
const coParentEntity = manager.create(Parents, {
|
|
||||||
user_id: savedParent2.id,
|
|
||||||
});
|
|
||||||
coParentEntity.user = savedParent2;
|
|
||||||
coParentEntity.co_parent = savedParent1;
|
|
||||||
|
|
||||||
await manager.save(Parents, coParentEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
parent1: savedParent1,
|
|
||||||
parent2: savedParent2,
|
|
||||||
tokenCreationMdp,
|
|
||||||
tokenCoParent,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// 6. TODO: Envoyer email avec lien de création de MDP
|
|
||||||
// await this.mailService.sendPasswordCreationEmail(result.parent1, result.tokenCreationMdp);
|
|
||||||
// if (result.parent2 && result.tokenCoParent) {
|
|
||||||
// await this.mailService.sendPasswordCreationEmail(result.parent2, result.tokenCoParent);
|
|
||||||
// }
|
|
||||||
|
|
||||||
return {
|
|
||||||
message: 'Inscription réussie. Un email de validation vous a été envoyé.',
|
|
||||||
parent_id: result.parent1.id,
|
|
||||||
co_parent_id: result.parent2?.id,
|
|
||||||
statut: StatutUtilisateurType.EN_ATTENTE,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async logout(userId: string) {
|
async logout(userId: string) {
|
||||||
// Pour le moment envoyer un message clair
|
// Pour le moment envoyer un message clair
|
||||||
return { success: true, message: 'Deconnexion'}
|
return { success: true, message: 'Deconnexion'}
|
||||||
|
|||||||
@ -1,121 +0,0 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
|
||||||
import {
|
|
||||||
IsEmail,
|
|
||||||
IsNotEmpty,
|
|
||||||
IsOptional,
|
|
||||||
IsString,
|
|
||||||
IsDateString,
|
|
||||||
IsEnum,
|
|
||||||
MinLength,
|
|
||||||
MaxLength,
|
|
||||||
Matches,
|
|
||||||
} from 'class-validator';
|
|
||||||
import { SituationFamilialeType } from 'src/entities/users.entity';
|
|
||||||
|
|
||||||
export class RegisterParentDto {
|
|
||||||
// === Informations obligatoires ===
|
|
||||||
@ApiProperty({ example: 'claire.martin@ptits-pas.fr' })
|
|
||||||
@IsEmail({}, { message: 'Email invalide' })
|
|
||||||
@IsNotEmpty({ message: 'L\'email est requis' })
|
|
||||||
email: string;
|
|
||||||
|
|
||||||
@ApiProperty({ example: 'Claire' })
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty({ message: 'Le prénom est requis' })
|
|
||||||
@MinLength(2, { message: 'Le prénom doit contenir au moins 2 caractères' })
|
|
||||||
@MaxLength(100, { message: 'Le prénom ne peut pas dépasser 100 caractères' })
|
|
||||||
prenom: string;
|
|
||||||
|
|
||||||
@ApiProperty({ example: 'MARTIN' })
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty({ message: 'Le nom est requis' })
|
|
||||||
@MinLength(2, { message: 'Le nom doit contenir au moins 2 caractères' })
|
|
||||||
@MaxLength(100, { message: 'Le nom ne peut pas dépasser 100 caractères' })
|
|
||||||
nom: string;
|
|
||||||
|
|
||||||
@ApiProperty({ example: '0689567890' })
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty({ message: 'Le téléphone est requis' })
|
|
||||||
@Matches(/^(\+33|0)[1-9](\d{2}){4}$/, {
|
|
||||||
message: 'Le numéro de téléphone doit être valide (ex: 0689567890 ou +33689567890)',
|
|
||||||
})
|
|
||||||
telephone: string;
|
|
||||||
|
|
||||||
// === Informations optionnelles ===
|
|
||||||
@ApiProperty({ example: '5 Avenue du Général de Gaulle', required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
adresse?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ example: '95870', required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
@MaxLength(10)
|
|
||||||
code_postal?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ example: 'Bezons', required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
@MaxLength(150)
|
|
||||||
ville?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ example: 'Infirmière', required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
@MaxLength(150)
|
|
||||||
profession?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ enum: SituationFamilialeType, example: SituationFamilialeType.MARIE, required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsEnum(SituationFamilialeType)
|
|
||||||
situation_familiale?: SituationFamilialeType;
|
|
||||||
|
|
||||||
@ApiProperty({ example: '1990-04-03', required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsDateString()
|
|
||||||
date_naissance?: string;
|
|
||||||
|
|
||||||
// === Informations co-parent (optionnel) ===
|
|
||||||
@ApiProperty({ example: 'thomas.martin@ptits-pas.fr', required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsEmail({}, { message: 'Email du co-parent invalide' })
|
|
||||||
co_parent_email?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ example: 'Thomas', required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
co_parent_prenom?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ example: 'MARTIN', required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
co_parent_nom?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ example: '0612345678', required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
@Matches(/^(\+33|0)[1-9](\d{2}){4}$/, {
|
|
||||||
message: 'Le numéro de téléphone du co-parent doit être valide',
|
|
||||||
})
|
|
||||||
co_parent_telephone?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ example: 'true', description: 'Le co-parent habite à la même adresse', required: false })
|
|
||||||
@IsOptional()
|
|
||||||
co_parent_meme_adresse?: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
co_parent_adresse?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
co_parent_code_postal?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
co_parent_ville?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user