mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-07-16 10:46:17 +00:00
Merge pull request #220 from SyncrowIOT/SP-1086-be-implement-the-user-agreement-flow
Sp 1086 be implement the user agreement flow
This commit is contained in:
@ -48,7 +48,9 @@ export class AuthService {
|
||||
if (!user.isActive) {
|
||||
throw new BadRequestException('User is not active');
|
||||
}
|
||||
|
||||
if (!user.hasAcceptedAppAgreement) {
|
||||
throw new BadRequestException('User has not accepted app agreement');
|
||||
}
|
||||
const passwordMatch = await this.helperHashService.bcryptCompare(
|
||||
pass,
|
||||
user.password,
|
||||
@ -92,6 +94,8 @@ export class AuthService {
|
||||
sessionId: user.sessionId,
|
||||
role: user?.role,
|
||||
googleCode: user.googleCode,
|
||||
hasAcceptedWebAgreement: user.hasAcceptedWebAgreement,
|
||||
hasAcceptedAppAgreement: user.hasAcceptedAppAgreement,
|
||||
};
|
||||
if (payload.googleCode) {
|
||||
const profile = await this.getProfile(payload.googleCode);
|
||||
|
@ -349,6 +349,10 @@ export class ControllerRoute {
|
||||
public static readonly DELETE_USER_SUMMARY = 'Delete user by UUID';
|
||||
public static readonly DELETE_USER_DESCRIPTION =
|
||||
'This endpoint deletes a user identified by their UUID. Accessible only by users with the Super Admin role.';
|
||||
public static readonly UPDATE_USER_WEB_AGREEMENT_SUMMARY =
|
||||
'Update user web agreement by user UUID';
|
||||
public static readonly UPDATE_USER_WEB_AGREEMENT_DESCRIPTION =
|
||||
'This endpoint updates the web agreement for a user identified by their UUID.';
|
||||
};
|
||||
};
|
||||
static AUTHENTICATION = class {
|
||||
|
@ -82,6 +82,18 @@ export class UserEntity extends AbstractEntity<UserDto> {
|
||||
})
|
||||
public isActive: boolean;
|
||||
|
||||
@Column({ default: false })
|
||||
hasAcceptedWebAgreement: boolean;
|
||||
|
||||
@Column({ default: false })
|
||||
hasAcceptedAppAgreement: boolean;
|
||||
|
||||
@Column({ type: 'timestamp', nullable: true })
|
||||
webAgreementAcceptedAt: Date;
|
||||
|
||||
@Column({ type: 'timestamp', nullable: true })
|
||||
appAgreementAcceptedAt: Date;
|
||||
|
||||
@OneToMany(() => UserSpaceEntity, (userSpace) => userSpace.user)
|
||||
userSpaces: UserSpaceEntity[];
|
||||
|
||||
|
@ -1,5 +1,11 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||
import {
|
||||
IsBoolean,
|
||||
IsEmail,
|
||||
IsNotEmpty,
|
||||
IsOptional,
|
||||
IsString,
|
||||
} from 'class-validator';
|
||||
import { IsPasswordStrong } from 'src/validators/password.validator';
|
||||
|
||||
export class UserSignUpDto {
|
||||
@ -39,7 +45,19 @@ export class UserSignUpDto {
|
||||
@IsNotEmpty()
|
||||
public lastName: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'regionUuid',
|
||||
required: false,
|
||||
})
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
public regionUuid?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'hasAcceptedAppAgreement',
|
||||
required: true,
|
||||
})
|
||||
@IsBoolean()
|
||||
@IsNotEmpty()
|
||||
public hasAcceptedAppAgreement: boolean;
|
||||
}
|
||||
|
@ -46,12 +46,17 @@ export class UserAuthService {
|
||||
);
|
||||
|
||||
try {
|
||||
const { regionUuid, ...rest } = userSignUpDto;
|
||||
const { regionUuid, hasAcceptedAppAgreement, ...rest } = userSignUpDto;
|
||||
if (!hasAcceptedAppAgreement) {
|
||||
throw new BadRequestException('Please accept the terms and conditions');
|
||||
}
|
||||
const spaceMemberRole = await this.roleService.findRoleByType(
|
||||
RoleType.SPACE_MEMBER,
|
||||
);
|
||||
const user = await this.userRepository.save({
|
||||
...rest,
|
||||
appAgreementAcceptedAt: new Date(),
|
||||
hasAcceptedAppAgreement,
|
||||
password: hashedPassword,
|
||||
roleType: { uuid: spaceMemberRole.uuid },
|
||||
region: regionUuid
|
||||
@ -65,7 +70,7 @@ export class UserAuthService {
|
||||
|
||||
return user;
|
||||
} catch (error) {
|
||||
throw new BadRequestException('Failed to register user');
|
||||
throw new BadRequestException(error.message || 'Failed to register user');
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,6 +121,7 @@ export class UserAuthService {
|
||||
firstName: googleUserData['given_name'],
|
||||
lastName: googleUserData['family_name'],
|
||||
password: googleUserData['email'],
|
||||
hasAcceptedAppAgreement: true,
|
||||
});
|
||||
}
|
||||
data.email = googleUserData['email'];
|
||||
@ -147,6 +153,8 @@ export class UserAuthService {
|
||||
userId: user.uuid,
|
||||
uuid: user.uuid,
|
||||
role: user.roleType,
|
||||
hasAcceptedWebAgreement: user.hasAcceptedWebAgreement,
|
||||
hasAcceptedAppAgreement: user.hasAcceptedAppAgreement,
|
||||
sessionId: session[1].uuid,
|
||||
});
|
||||
return res;
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
Get,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Patch,
|
||||
Put,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
@ -21,6 +22,7 @@ import { CheckProfilePictureGuard } from 'src/guards/profile.picture.guard';
|
||||
import { SuperAdminRoleGuard } from 'src/guards/super.admin.role.guard';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
import { ControllerRoute } from '@app/common/constants/controller-route';
|
||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||
|
||||
@ApiTags('User Module')
|
||||
@Controller({
|
||||
@ -151,4 +153,18 @@ export class UserController {
|
||||
message: 'User deleted successfully',
|
||||
};
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Patch('agreements/web/:userUuid')
|
||||
@ApiOperation({
|
||||
summary: ControllerRoute.USER.ACTIONS.UPDATE_USER_WEB_AGREEMENT_SUMMARY,
|
||||
description:
|
||||
ControllerRoute.USER.ACTIONS.UPDATE_USER_WEB_AGREEMENT_DESCRIPTION,
|
||||
})
|
||||
async acceptWebAgreement(
|
||||
@Param('userUuid') userUuid: string,
|
||||
): Promise<BaseResponseDto> {
|
||||
return this.userService.acceptWebAgreement(userUuid);
|
||||
}
|
||||
}
|
||||
|
@ -59,10 +59,7 @@ export class UserSpaceService {
|
||||
const { inviteCode } = params;
|
||||
try {
|
||||
const inviteSpace = await this.findInviteSpaceByInviteCode(inviteCode);
|
||||
const user = await this.userService.getUserDetailsByUserUuid(
|
||||
userUuid,
|
||||
true,
|
||||
);
|
||||
const user = await this.userService.getUserDetailsByUserUuid(userUuid);
|
||||
await this.checkSpaceMemberRole(user);
|
||||
await this.addUserToSpace(userUuid, inviteSpace.space.uuid);
|
||||
|
||||
|
@ -15,6 +15,7 @@ import { RegionRepository } from '@app/common/modules/region/repositories';
|
||||
import { TimeZoneRepository } from '@app/common/modules/timezone/repositories';
|
||||
import { removeBase64Prefix } from '@app/common/helper/removeBase64Prefix';
|
||||
import { UserEntity } from '@app/common/modules/user/entities';
|
||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||
|
||||
@Injectable()
|
||||
export class UserService {
|
||||
@ -23,15 +24,13 @@ export class UserService {
|
||||
private readonly regionRepository: RegionRepository,
|
||||
private readonly timeZoneRepository: TimeZoneRepository,
|
||||
) {}
|
||||
async getUserDetailsByUserUuid(userUuid: string, withRole = false) {
|
||||
async getUserDetailsByUserUuid(userUuid: string) {
|
||||
try {
|
||||
const user = await this.userRepository.findOne({
|
||||
where: {
|
||||
uuid: userUuid,
|
||||
},
|
||||
...(withRole
|
||||
? { relations: ['roleType'] }
|
||||
: { relations: ['region', 'timezone'] }),
|
||||
relations: ['region', 'timezone', 'roleType'],
|
||||
});
|
||||
if (!user) {
|
||||
throw new BadRequestException('Invalid room UUID');
|
||||
@ -48,7 +47,11 @@ export class UserService {
|
||||
profilePicture: cleanedProfilePicture,
|
||||
region: user?.region,
|
||||
timeZone: user?.timezone,
|
||||
...(withRole && { role: user?.roleType }),
|
||||
hasAcceptedWebAgreement: user?.hasAcceptedWebAgreement,
|
||||
webAgreementAcceptedAt: user?.webAgreementAcceptedAt,
|
||||
hasAcceptedAppAgreement: user?.hasAcceptedAppAgreement,
|
||||
appAgreementAcceptedAt: user?.appAgreementAcceptedAt,
|
||||
role: user?.roleType,
|
||||
};
|
||||
} catch (err) {
|
||||
if (err instanceof BadRequestException) {
|
||||
@ -241,6 +244,20 @@ export class UserService {
|
||||
);
|
||||
}
|
||||
}
|
||||
async acceptWebAgreement(userUuid: string) {
|
||||
await this.userRepository.update(
|
||||
{ uuid: userUuid },
|
||||
{
|
||||
hasAcceptedWebAgreement: true,
|
||||
webAgreementAcceptedAt: new Date(),
|
||||
},
|
||||
);
|
||||
return new SuccessResponseDto({
|
||||
statusCode: HttpStatus.OK,
|
||||
success: true,
|
||||
message: 'Web agreement accepted successfully',
|
||||
});
|
||||
}
|
||||
async findOneById(id: string): Promise<UserEntity> {
|
||||
return await this.userRepository.findOne({ where: { uuid: id } });
|
||||
}
|
||||
|
Reference in New Issue
Block a user