Add endpoint to disable user invitation

This commit is contained in:
faris Aljohari
2025-01-04 19:13:33 -06:00
parent 5f26e7b7d2
commit fe51705730
4 changed files with 190 additions and 6 deletions

View File

@ -766,6 +766,12 @@ export class ControllerRoute {
public static readonly UPDATE_USER_INVITATION_DESCRIPTION =
'This endpoint updates an invitation for a user to assign to role and spaces.';
public static readonly DISABLE_USER_INVITATION_SUMMARY =
'Disable user invitation';
public static readonly DISABLE_USER_INVITATION_DESCRIPTION =
'This endpoint disables an invitation for a user to assign to role and spaces.';
public static readonly ACTIVATION_CODE_SUMMARY =
'Activate Invitation Code';

View File

@ -17,7 +17,10 @@ import { Permissions } from 'src/decorators/permissions.decorator';
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
import { CheckEmailDto } from '../dtos/check-email.dto';
import { ActivateCodeDto } from '../dtos/active-code.dto';
import { UpdateUserInvitationDto } from '../dtos/update.invite-user.dto';
import {
DisableUserInvitationDto,
UpdateUserInvitationDto,
} from '../dtos/update.invite-user.dto';
@ApiTags('Invite User Module')
@Controller({
@ -93,4 +96,22 @@ export class InviteUserController {
invitedUserUuid,
);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Put(':invitedUserUuid/disable')
@ApiOperation({
summary:
ControllerRoute.INVITE_USER.ACTIONS.DISABLE_USER_INVITATION_SUMMARY,
description:
ControllerRoute.INVITE_USER.ACTIONS.DISABLE_USER_INVITATION_DESCRIPTION,
})
async disableUserInvitation(
@Param('invitedUserUuid') invitedUserUuid: string,
@Body() disableUserInvitationDto: DisableUserInvitationDto,
): Promise<BaseResponseDto> {
return await this.inviteUserService.disableUserInvitation(
disableUserInvitationDto,
invitedUserUuid,
);
}
}

View File

@ -2,6 +2,7 @@ import { ApiProperty } from '@nestjs/swagger';
import {
ArrayMinSize,
IsArray,
IsBoolean,
IsNotEmpty,
IsOptional,
IsString,
@ -72,3 +73,24 @@ export class UpdateUserInvitationDto {
Object.assign(this, dto);
}
}
export class DisableUserInvitationDto {
@ApiProperty({
description: 'The disable status of the user',
example: 'true',
required: true,
})
@IsBoolean()
@IsNotEmpty()
public disable: boolean;
@ApiProperty({
description: 'The project uuid of the user',
example: 'd290f1ee-6c54-4b01-90e6-d701748f0851',
required: true,
})
@IsString()
@IsNotEmpty()
public projectUuid: string;
constructor(dto: Partial<UpdateUserInvitationDto>) {
Object.assign(this, dto);
}
}

View File

@ -24,7 +24,10 @@ import { SpaceEntity, SpaceRepository } from '@app/common/modules/space';
import { ActivateCodeDto } from '../dtos/active-code.dto';
import { UserSpaceService } from 'src/users/services';
import { SpaceUserService } from 'src/space/services';
import { UpdateUserInvitationDto } from '../dtos/update.invite-user.dto';
import {
DisableUserInvitationDto,
UpdateUserInvitationDto,
} from '../dtos/update.invite-user.dto';
@Injectable()
export class InviteUserService {
@ -285,10 +288,7 @@ export class InviteUserService {
}
// Perform update actions if status is 'INVITED'
if (
userOldData.status === UserStatusEnum.INVITED ||
userOldData.status === UserStatusEnum.DISABLED
) {
if (userOldData.status === UserStatusEnum.INVITED) {
await this.updateWhenUserIsInviteOrDisable(
queryRunner,
dto,
@ -475,4 +475,139 @@ export class InviteUserService {
}
}
}
async disableUserInvitation(
dto: DisableUserInvitationDto,
invitedUserUuid: string,
): Promise<BaseResponseDto> {
const { disable, projectUuid } = dto;
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.startTransaction();
try {
const userData = await this.inviteUserRepository.findOne({
where: { uuid: invitedUserUuid, project: { uuid: projectUuid } },
relations: ['roleType', 'spaces.space'],
});
if (!userData) {
throw new HttpException('User not found', HttpStatus.NOT_FOUND);
}
if (userData.status === UserStatusEnum.INVITED) {
await this.updateUserStatus(invitedUserUuid, projectUuid, disable);
} else if (userData.status === UserStatusEnum.ACTIVE) {
const user = await this.userRepository.findOne({
where: { inviteUser: { uuid: invitedUserUuid } },
relations: ['userSpaces.space', 'userSpaces.space.community'],
});
if (!user) {
throw new HttpException(
'User account not found',
HttpStatus.NOT_FOUND,
);
}
if (!disable) {
await this.disassociateUserFromSpaces(user, projectUuid);
await this.updateUserStatus(invitedUserUuid, projectUuid, disable);
} else if (disable) {
await this.associateUserToSpaces(
user,
userData,
projectUuid,
invitedUserUuid,
disable,
);
}
} else {
throw new HttpException(
'Invalid user status or action',
HttpStatus.BAD_REQUEST,
);
}
await queryRunner.commitTransaction();
return new SuccessResponseDto({
statusCode: HttpStatus.OK,
success: true,
message: 'User invitation status updated successfully',
});
} catch (error) {
await queryRunner.rollbackTransaction();
throw error;
} finally {
await queryRunner.release();
}
}
private async updateUserStatus(
invitedUserUuid: string,
projectUuid: string,
disable: boolean,
) {
await this.inviteUserRepository.update(
{ uuid: invitedUserUuid, project: { uuid: projectUuid } },
{ isEnabled: disable },
);
}
private async disassociateUserFromSpaces(user: any, projectUuid: string) {
const disassociatePromises = user.userSpaces.map((userSpace) =>
this.spaceUserService.disassociateUserFromSpace({
communityUuid: userSpace.space.community.uuid,
spaceUuid: userSpace.space.uuid,
userUuid: user.uuid,
projectUuid,
}),
);
const results = await Promise.allSettled(disassociatePromises);
results.forEach((result, index) => {
if (result.status === 'rejected') {
console.error(
`Failed to disassociate user from space ${user.userSpaces[index].space.uuid}:`,
result.reason,
);
}
});
}
private async associateUserToSpaces(
user: any,
userData: any,
projectUuid: string,
invitedUserUuid: string,
disable: boolean,
) {
const spaceUuids = userData.spaces.map((space) => space.space.uuid);
const associatePromises = spaceUuids.map(async (spaceUuid) => {
try {
const spaceDetails = await this.getSpaceByUuid(spaceUuid);
const deviceUUIDs =
await this.userSpaceService.getDeviceUUIDsForSpace(spaceUuid);
await this.userSpaceService.addUserPermissionsToDevices(
user.uuid,
deviceUUIDs,
);
await this.spaceUserService.associateUserToSpace({
communityUuid: spaceDetails.communityUuid,
spaceUuid,
userUuid: user.uuid,
projectUuid,
});
await this.updateUserStatus(invitedUserUuid, projectUuid, disable);
} catch (error) {
console.error(`Failed to associate user to space ${spaceUuid}:`, error);
}
});
await Promise.allSettled(associatePromises);
}
}