Merge pull request #197 from SyncrowIOT/SP-904-be-disable-role-and-delete

Sp 904 be disable role and delete
This commit is contained in:
faris Aljohari
2025-01-04 22:47:41 -06:00
committed by GitHub
13 changed files with 510 additions and 28 deletions

View File

@ -58,6 +58,14 @@ MAILTRAP_API_TOKEN=
MAILTRAP_INVITATION_TEMPLATE_UUID= MAILTRAP_INVITATION_TEMPLATE_UUID=
MAILTRAP_EDIT_USER_TEMPLATE_UUID=
MAILTRAP_DISABLE_TEMPLATE_UUID=
MAILTRAP_ENABLE_TEMPLATE_UUID=
MAILTRAP_DELETE_USER_TEMPLATE_UUID=
WEBSITES_ENABLE_APP_SERVICE_STORAGE= WEBSITES_ENABLE_APP_SERVICE_STORAGE=
PORT= PORT=

View File

@ -45,6 +45,9 @@ export class AuthService {
if (!user.isUserVerified) { if (!user.isUserVerified) {
throw new BadRequestException('User is not verified'); throw new BadRequestException('User is not verified');
} }
if (!user.isActive) {
throw new BadRequestException('User is not active');
}
if (user) { if (user) {
const passwordMatch = this.helperHashService.bcryptCompare( const passwordMatch = this.helperHashService.bcryptCompare(
pass, pass,

View File

@ -13,5 +13,11 @@ export default registerAs(
MAILTRAP_API_TOKEN: process.env.MAILTRAP_API_TOKEN, MAILTRAP_API_TOKEN: process.env.MAILTRAP_API_TOKEN,
MAILTRAP_INVITATION_TEMPLATE_UUID: MAILTRAP_INVITATION_TEMPLATE_UUID:
process.env.MAILTRAP_INVITATION_TEMPLATE_UUID, process.env.MAILTRAP_INVITATION_TEMPLATE_UUID,
MAILTRAP_DISABLE_TEMPLATE_UUID: process.env.MAILTRAP_DISABLE_TEMPLATE_UUID,
MAILTRAP_ENABLE_TEMPLATE_UUID: process.env.MAILTRAP_ENABLE_TEMPLATE_UUID,
MAILTRAP_DELETE_USER_TEMPLATE_UUID:
process.env.MAILTRAP_DELETE_USER_TEMPLATE_UUID,
MAILTRAP_EDIT_USER_TEMPLATE_UUID:
process.env.MAILTRAP_EDIT_USER_TEMPLATE_UUID,
}), }),
); );

View File

@ -766,6 +766,18 @@ export class ControllerRoute {
public static readonly UPDATE_USER_INVITATION_DESCRIPTION = public static readonly UPDATE_USER_INVITATION_DESCRIPTION =
'This endpoint updates an invitation for a user to assign to role and spaces.'; '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 DELETE_USER_INVITATION_SUMMARY =
'Delete user invitation';
public static readonly DELETE_USER_INVITATION_DESCRIPTION =
'This endpoint deletes an invitation for a user to assign to role and spaces.';
public static readonly ACTIVATION_CODE_SUMMARY = public static readonly ACTIVATION_CODE_SUMMARY =
'Activate Invitation Code'; 'Activate Invitation Code';

View File

@ -1,5 +1,4 @@
export enum UserStatusEnum { export enum UserStatusEnum {
ACTIVE = 'active', ACTIVE = 'active',
INVITED = 'invited', INVITED = 'invited',
DISABLED = 'disabled',
} }

View File

@ -61,6 +61,11 @@ export class InviteUserEntity extends AbstractEntity<InviteUserDto> {
default: true, default: true,
}) })
public isActive: boolean; public isActive: boolean;
@Column({
nullable: false,
default: true,
})
public isEnabled: boolean;
@Column({ @Column({
nullable: false, nullable: false,
unique: true, unique: true,

View File

@ -83,4 +83,137 @@ export class EmailService {
); );
} }
} }
async sendEmailWithTemplate(
email: string,
name: string,
isEnable: boolean,
isDelete: boolean,
): Promise<void> {
const isProduction = process.env.NODE_ENV === 'production';
const API_TOKEN = this.configService.get<string>(
'email-config.MAILTRAP_API_TOKEN',
);
const API_URL = isProduction
? SEND_EMAIL_API_URL_PROD
: SEND_EMAIL_API_URL_DEV;
// Determine the template UUID based on the arguments
const templateUuid = isDelete
? this.configService.get<string>(
'email-config.MAILTRAP_DELETE_USER_TEMPLATE_UUID',
)
: this.configService.get<string>(
isEnable
? 'email-config.MAILTRAP_ENABLE_TEMPLATE_UUID'
: 'email-config.MAILTRAP_DISABLE_TEMPLATE_UUID',
);
const emailData = {
from: {
email: this.smtpConfig.sender,
},
to: [
{
email,
},
],
template_uuid: templateUuid,
template_variables: {
name,
},
};
try {
await axios.post(API_URL, emailData, {
headers: {
Authorization: `Bearer ${API_TOKEN}`,
'Content-Type': 'application/json',
},
});
} catch (error) {
throw new HttpException(
error.response?.data?.message ||
'Error sending email using Mailtrap template',
error.response?.status || HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
async sendEditUserEmailWithTemplate(
email: string,
emailEditData: any,
): Promise<void> {
const isProduction = process.env.NODE_ENV === 'production';
const API_TOKEN = this.configService.get<string>(
'email-config.MAILTRAP_API_TOKEN',
);
const API_URL = isProduction
? SEND_EMAIL_API_URL_PROD
: SEND_EMAIL_API_URL_DEV;
const TEMPLATE_UUID = this.configService.get<string>(
'email-config.MAILTRAP_EDIT_USER_TEMPLATE_UUID',
);
const emailData = {
from: {
email: this.smtpConfig.sender,
},
to: [
{
email: email,
},
],
template_uuid: TEMPLATE_UUID,
template_variables: emailEditData,
};
try {
await axios.post(API_URL, emailData, {
headers: {
Authorization: `Bearer ${API_TOKEN}`,
'Content-Type': 'application/json',
},
});
} catch (error) {
throw new HttpException(
error.response?.data?.message ||
'Error sending email using Mailtrap template',
error.response?.status || HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
generateUserChangesEmailBody(
addedSpaceNames: string[],
removedSpaceNames: string[],
oldRole: string,
newRole: string,
oldName: string,
newName: string,
) {
const addedSpaceNamesChanged =
addedSpaceNames.length > 0
? `Access to the following spaces were added: ${addedSpaceNames.join(', ')}`
: '';
const removedSpaceNamesChanged =
removedSpaceNames.length > 0
? `Access to the following spaces were deleted: ${removedSpaceNames.join(', ')}`
: '';
const roleChanged =
oldRole !== newRole
? `Your user role has been changed from [${oldRole}] to [${newRole}]`
: '';
const nameChanged =
oldName !== newName
? `The name associated with your account has changed from [${oldName}] to [${newName}]`
: '';
return {
addedSpaceNamesChanged,
removedSpaceNamesChanged,
roleChanged,
nameChanged,
};
}
} }

View File

@ -151,7 +151,7 @@ export class UserAuthService {
}); });
return res; return res;
} catch (error) { } catch (error) {
throw new BadRequestException('Invalid credentials'); throw new BadRequestException(error.message || 'Invalid credentials');
} }
} }

View File

@ -2,6 +2,7 @@ import { InviteUserService } from '../services/invite-user.service';
import { import {
Body, Body,
Controller, Controller,
Delete,
Param, Param,
Post, Post,
Put, Put,
@ -17,7 +18,10 @@ import { Permissions } from 'src/decorators/permissions.decorator';
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard'; import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
import { CheckEmailDto } from '../dtos/check-email.dto'; import { CheckEmailDto } from '../dtos/check-email.dto';
import { ActivateCodeDto } from '../dtos/active-code.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') @ApiTags('Invite User Module')
@Controller({ @Controller({
@ -93,4 +97,35 @@ export class InviteUserController {
invitedUserUuid, 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,
);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Delete(':invitedUserUuid')
@ApiOperation({
summary: ControllerRoute.INVITE_USER.ACTIONS.DELETE_USER_INVITATION_SUMMARY,
description:
ControllerRoute.INVITE_USER.ACTIONS.DELETE_USER_INVITATION_DESCRIPTION,
})
async deleteUserInvitation(
@Param('invitedUserUuid') invitedUserUuid: string,
): Promise<BaseResponseDto> {
return await this.inviteUserService.deleteUserInvitation(invitedUserUuid);
}
} }

View File

@ -2,6 +2,7 @@ import { ApiProperty } from '@nestjs/swagger';
import { import {
ArrayMinSize, ArrayMinSize,
IsArray, IsArray,
IsBoolean,
IsNotEmpty, IsNotEmpty,
IsOptional, IsOptional,
IsString, IsString,
@ -72,3 +73,24 @@ export class UpdateUserInvitationDto {
Object.assign(this, dto); 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

@ -25,6 +25,7 @@ import { UserDevicePermissionService } from 'src/user-device-permission/services
import { DeviceUserPermissionRepository } from '@app/common/modules/device/repositories'; import { DeviceUserPermissionRepository } from '@app/common/modules/device/repositories';
import { PermissionTypeRepository } from '@app/common/modules/permission/repositories'; import { PermissionTypeRepository } from '@app/common/modules/permission/repositories';
import { ProjectUserService } from 'src/project/services/project-user.service'; import { ProjectUserService } from 'src/project/services/project-user.service';
import { RoleTypeRepository } from '@app/common/modules/role-type/repositories';
@Module({ @Module({
imports: [ConfigModule, InviteUserRepositoryModule], imports: [ConfigModule, InviteUserRepositoryModule],
@ -49,6 +50,7 @@ import { ProjectUserService } from 'src/project/services/project-user.service';
DeviceUserPermissionRepository, DeviceUserPermissionRepository,
PermissionTypeRepository, PermissionTypeRepository,
ProjectUserService, ProjectUserService,
RoleTypeRepository,
], ],
exports: [InviteUserService], exports: [InviteUserService],
}) })

View File

@ -24,7 +24,11 @@ import { SpaceEntity, SpaceRepository } from '@app/common/modules/space';
import { ActivateCodeDto } from '../dtos/active-code.dto'; import { ActivateCodeDto } from '../dtos/active-code.dto';
import { UserSpaceService } from 'src/users/services'; import { UserSpaceService } from 'src/users/services';
import { SpaceUserService } from 'src/space/services'; import { SpaceUserService } from 'src/space/services';
import { UpdateUserInvitationDto } from '../dtos/update.invite-user.dto'; import {
DisableUserInvitationDto,
UpdateUserInvitationDto,
} from '../dtos/update.invite-user.dto';
import { RoleTypeRepository } from '@app/common/modules/role-type/repositories';
@Injectable() @Injectable()
export class InviteUserService { export class InviteUserService {
@ -36,6 +40,7 @@ export class InviteUserService {
private readonly userSpaceService: UserSpaceService, private readonly userSpaceService: UserSpaceService,
private readonly spaceUserService: SpaceUserService, private readonly spaceUserService: SpaceUserService,
private readonly spaceRepository: SpaceRepository, private readonly spaceRepository: SpaceRepository,
private readonly roleTypeRepository: RoleTypeRepository,
private readonly dataSource: DataSource, private readonly dataSource: DataSource,
) {} ) {}
@ -111,7 +116,7 @@ export class InviteUserService {
await Promise.all(spacePromises); await Promise.all(spacePromises);
await this.emailService.sendEmailWithInvitationTemplate(email, { await this.emailService.sendEmailWithInvitationTemplate(email, {
name: firstName + ' ' + lastName, name: firstName,
invitationCode, invitationCode,
role: roleType, role: roleType,
spacesList: spaceNamesString, spacesList: spaceNamesString,
@ -269,7 +274,7 @@ export class InviteUserService {
dto: UpdateUserInvitationDto, dto: UpdateUserInvitationDto,
invitedUserUuid: string, invitedUserUuid: string,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
const { projectUuid } = dto; const { projectUuid, spaceUuids } = dto;
const queryRunner = this.dataSource.createQueryRunner(); const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.startTransaction(); await queryRunner.startTransaction();
@ -278,6 +283,7 @@ export class InviteUserService {
// Fetch the user's existing data in the project // Fetch the user's existing data in the project
const userOldData = await this.inviteUserRepository.findOne({ const userOldData = await this.inviteUserRepository.findOne({
where: { uuid: invitedUserUuid, project: { uuid: projectUuid } }, where: { uuid: invitedUserUuid, project: { uuid: projectUuid } },
relations: ['project', 'spaces.space', 'roleType'],
}); });
if (!userOldData) { if (!userOldData) {
@ -285,19 +291,66 @@ export class InviteUserService {
} }
// Perform update actions if status is 'INVITED' // Perform update actions if status is 'INVITED'
if ( if (userOldData.status === UserStatusEnum.INVITED) {
userOldData.status === UserStatusEnum.INVITED || await this.updateWhenUserIsInvite(queryRunner, dto, invitedUserUuid);
userOldData.status === UserStatusEnum.DISABLED
) {
await this.updateWhenUserIsInviteOrDisable(
queryRunner,
dto,
invitedUserUuid,
);
} else if (userOldData.status === UserStatusEnum.ACTIVE) { } else if (userOldData.status === UserStatusEnum.ACTIVE) {
await this.updateWhenUserIsInvite(queryRunner, dto, invitedUserUuid);
await this.updateWhenUserIsActive(queryRunner, dto, invitedUserUuid); await this.updateWhenUserIsActive(queryRunner, dto, invitedUserUuid);
} }
// Extract existing space UUIDs
const oldSpaceUuids = userOldData.spaces.map((space) => space.space.uuid);
// Compare spaces
const addedSpaces = spaceUuids.filter(
(uuid) => !oldSpaceUuids.includes(uuid),
);
const removedSpaces = oldSpaceUuids.filter(
(uuid) => !spaceUuids.includes(uuid),
);
// Fetch the space names for added and removed spaces
const spaceRepo = queryRunner.manager.getRepository(SpaceEntity);
const addedSpacesDetails = await spaceRepo.find({
where: {
uuid: In(addedSpaces),
},
});
const removedSpacesDetails = await spaceRepo.find({
where: {
uuid: In(removedSpaces),
},
});
// Extract the names of the added and removed spaces
const addedSpaceNames = addedSpacesDetails.map(
(space) => space.spaceName,
);
const removedSpaceNames = removedSpacesDetails.map(
(space) => space.spaceName,
);
// Check for role and name change
const oldRole = userOldData.roleType.type;
const newRole = await this.getRoleTypeByUuid(dto.roleUuid);
const oldFullName = `${userOldData.firstName} ${userOldData.lastName}`;
const newFullName = `${dto.firstName} ${dto.lastName}`;
// Generate email body
const emailMessage = this.emailService.generateUserChangesEmailBody(
addedSpaceNames,
removedSpaceNames,
oldRole,
newRole,
oldFullName,
newFullName,
);
await this.emailService.sendEditUserEmailWithTemplate(
userOldData.email,
emailMessage,
);
// Proceed with other updates (e.g., roles, names, etc.)
await queryRunner.commitTransaction(); await queryRunner.commitTransaction();
return new SuccessResponseDto({ return new SuccessResponseDto({
@ -319,8 +372,15 @@ export class InviteUserService {
await queryRunner.release(); await queryRunner.release();
} }
} }
private async getRoleTypeByUuid(roleUuid: string) {
const role = await this.roleTypeRepository.findOne({
where: { uuid: roleUuid },
});
private async updateWhenUserIsInviteOrDisable( return role.type;
}
private async updateWhenUserIsInvite(
queryRunner: QueryRunner, queryRunner: QueryRunner,
dto: UpdateUserInvitationDto, dto: UpdateUserInvitationDto,
invitedUserUuid: string, invitedUserUuid: string,
@ -475,4 +535,209 @@ 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 this.emailService.sendEmailWithTemplate(
userData.email,
userData.firstName,
disable,
false,
);
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);
}
async deleteUserInvitation(
invitedUserUuid: string,
): Promise<BaseResponseDto> {
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.startTransaction();
try {
const userData = await this.inviteUserRepository.findOne({
where: { uuid: invitedUserUuid },
relations: ['roleType', 'spaces.space', 'project'],
});
if (!userData) {
throw new HttpException('User not found', HttpStatus.NOT_FOUND);
}
if (userData.status === UserStatusEnum.INVITED) {
await this.inviteUserRepository.update(
{ uuid: invitedUserUuid },
{ isActive: false },
);
} 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,
);
}
await this.disassociateUserFromSpaces(user, userData.project.uuid);
await this.inviteUserRepository.update(
{ uuid: invitedUserUuid },
{ isActive: false },
);
await this.userRepository.update(
{ uuid: user.uuid },
{ isActive: false },
);
}
await this.emailService.sendEmailWithTemplate(
userData.email,
userData.firstName,
false,
true,
);
await queryRunner.commitTransaction();
return new SuccessResponseDto({
statusCode: HttpStatus.OK,
success: true,
message: 'User invitation deleted successfully',
});
} catch (error) {
await queryRunner.rollbackTransaction();
throw error;
} finally {
await queryRunner.release();
}
}
} }

View File

@ -3,7 +3,6 @@ import { BaseResponseDto } from '@app/common/dto/base.response.dto';
import { SuccessResponseDto } from '@app/common/dto/success.response.dto'; import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
import { InviteUserRepository } from '@app/common/modules/Invite-user/repositiories'; import { InviteUserRepository } from '@app/common/modules/Invite-user/repositiories';
import { ProjectService } from './project.service'; import { ProjectService } from './project.service';
import { UserStatusEnum } from '@app/common/constants/user-status.enum';
import { UserSpaceRepository } from '@app/common/modules/user/repositories'; import { UserSpaceRepository } from '@app/common/modules/user/repositories';
@Injectable() @Injectable()
@ -35,6 +34,7 @@ export class ProjectUserService {
'phoneNumber', 'phoneNumber',
'jobTitle', 'jobTitle',
'invitedBy', 'invitedBy',
'isEnabled',
], ],
relations: ['roleType'], relations: ['roleType'],
}); });
@ -73,7 +73,6 @@ export class ProjectUserService {
invitedUserUuid: string, invitedUserUuid: string,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
try { try {
let userSpaces;
const user = await this.inviteUserRepository.findOne({ const user = await this.inviteUserRepository.findOne({
where: { where: {
project: { uuid: projectUuid }, project: { uuid: projectUuid },
@ -90,6 +89,7 @@ export class ProjectUserService {
'phoneNumber', 'phoneNumber',
'jobTitle', 'jobTitle',
'invitedBy', 'invitedBy',
'isEnabled',
], ],
relations: ['roleType', 'spaces.space'], relations: ['roleType', 'spaces.space'],
}); });
@ -100,15 +100,7 @@ export class ProjectUserService {
HttpStatus.NOT_FOUND, HttpStatus.NOT_FOUND,
); );
} }
if (user.status === UserStatusEnum.ACTIVE) {
const spaces = await this.userSpaceRepository.find({
where: { user: { inviteUser: { uuid: invitedUserUuid } } },
relations: ['space'],
});
userSpaces = spaces.map((space) => space.space);
} else {
userSpaces = user.spaces.map((space) => space.space);
}
const createdAt = new Date(user.createdAt); const createdAt = new Date(user.createdAt);
const createdDate = createdAt.toLocaleDateString(); const createdDate = createdAt.toLocaleDateString();
const createdTime = createdAt.toLocaleTimeString(); const createdTime = createdAt.toLocaleTimeString();
@ -119,7 +111,7 @@ export class ProjectUserService {
roleType: user.roleType.type, roleType: user.roleType.type,
createdDate, createdDate,
createdTime, createdTime,
spaces: userSpaces, spaces: user.spaces.map((space) => space.space),
}, },
statusCode: HttpStatus.OK, statusCode: HttpStatus.OK,
}); });