Remove invitationCode from unique constraint and update invite user logic

This commit is contained in:
faris Aljohari
2025-01-11 01:39:52 -06:00
parent 35b6f9f478
commit 78617dde83
5 changed files with 83 additions and 47 deletions

View File

@ -18,7 +18,7 @@ import { InviteUserDto, InviteUserSpaceDto } from '../dtos';
import { ProjectEntity } from '../../project/entities'; import { ProjectEntity } from '../../project/entities';
@Entity({ name: 'invite-user' }) @Entity({ name: 'invite-user' })
@Unique(['email', 'invitationCode', 'project']) @Unique(['email', 'project'])
export class InviteUserEntity extends AbstractEntity<InviteUserDto> { export class InviteUserEntity extends AbstractEntity<InviteUserDto> {
@Column({ @Column({
type: 'uuid', type: 'uuid',

View File

@ -287,13 +287,12 @@ export class InviteUserService {
// Update invited user and associated user data // Update invited user and associated user data
await this.inviteUserRepository.update( await this.inviteUserRepository.update(
{ uuid: invitedUser.uuid }, { uuid: invitedUser.uuid },
{ status: UserStatusEnum.ACTIVE }, { status: UserStatusEnum.ACTIVE, user: { uuid: user.uuid } },
); );
await this.userRepository.update( await this.userRepository.update(
{ uuid: user.uuid }, { uuid: user.uuid },
{ {
project: { uuid: invitedUser.project.uuid }, project: { uuid: invitedUser.project.uuid },
inviteUser: { uuid: invitedUser.uuid },
roleType: { uuid: invitedUser.roleType.uuid }, roleType: { uuid: invitedUser.roleType.uuid },
}, },
); );
@ -460,12 +459,12 @@ export class InviteUserService {
projectUuid, projectUuid,
} = dto; } = dto;
const user = await this.userRepository.findOne({ const userData = await this.inviteUserRepository.findOne({
where: { inviteUser: { uuid: invitedUserUuid } }, where: { uuid: invitedUserUuid },
relations: ['userSpaces.space', 'userSpaces.space.community'], relations: ['user.userSpaces.space', 'user.userSpaces.space.community'],
}); });
if (!user) { if (!userData) {
throw new HttpException( throw new HttpException(
`User with invitedUserUuid ${invitedUserUuid} not found`, `User with invitedUserUuid ${invitedUserUuid} not found`,
HttpStatus.NOT_FOUND, HttpStatus.NOT_FOUND,
@ -486,12 +485,12 @@ export class InviteUserService {
); );
// Disassociate the user from all current spaces // Disassociate the user from all current spaces
const disassociatePromises = user.userSpaces.map((userSpace) => const disassociatePromises = userData.user.userSpaces.map((userSpace) =>
this.spaceUserService this.spaceUserService
.disassociateUserFromSpace({ .disassociateUserFromSpace({
communityUuid: userSpace.space.community.uuid, communityUuid: userSpace.space.community.uuid,
spaceUuid: userSpace.space.uuid, spaceUuid: userSpace.space.uuid,
userUuid: user.uuid, userUuid: userData.user.uuid,
projectUuid, projectUuid,
}) })
.catch((error) => { .catch((error) => {
@ -517,7 +516,7 @@ export class InviteUserService {
// Grant permissions to the user for all devices in the space // Grant permissions to the user for all devices in the space
await this.userSpaceService.addUserPermissionsToDevices( await this.userSpaceService.addUserPermissionsToDevices(
user.uuid, userData.user.uuid,
deviceUUIDs, deviceUUIDs,
); );
@ -525,7 +524,7 @@ export class InviteUserService {
await this.spaceUserService.associateUserToSpace({ await this.spaceUserService.associateUserToSpace({
communityUuid: spaceDetails.communityUuid, communityUuid: spaceDetails.communityUuid,
spaceUuid: spaceUuid, spaceUuid: spaceUuid,
userUuid: user.uuid, userUuid: userData.user.uuid,
projectUuid, projectUuid,
}); });
} catch (error) { } catch (error) {
@ -584,30 +583,36 @@ export class InviteUserService {
} }
if (userData.status === UserStatusEnum.INVITED) { if (userData.status === UserStatusEnum.INVITED) {
await this.updateUserStatus(invitedUserUuid, projectUuid, disable); await this.updateUserStatus(invitedUserUuid, projectUuid, !disable);
} else if (userData.status === UserStatusEnum.ACTIVE) { } else if (userData.status === UserStatusEnum.ACTIVE) {
const user = await this.userRepository.findOne({ const invitedUserData = await this.inviteUserRepository.findOne({
where: { inviteUser: { uuid: invitedUserUuid } }, where: { uuid: invitedUserUuid },
relations: ['userSpaces.space', 'userSpaces.space.community'], relations: [
'user.userSpaces.space',
'user.userSpaces.space.community',
],
}); });
if (!user) { if (!invitedUserData.user) {
throw new HttpException( throw new HttpException(
'User account not found', 'User account not found',
HttpStatus.NOT_FOUND, HttpStatus.NOT_FOUND,
); );
} }
if (!disable) { if (disable) {
await this.disassociateUserFromSpaces(user, projectUuid); await this.disassociateUserFromSpaces(
await this.updateUserStatus(invitedUserUuid, projectUuid, disable); invitedUserData.user,
} else if (disable) { projectUuid,
);
await this.updateUserStatus(invitedUserUuid, projectUuid, !disable);
} else if (!disable) {
await this.associateUserToSpaces( await this.associateUserToSpaces(
user, invitedUserData.user,
userData, userData,
projectUuid, projectUuid,
invitedUserUuid, invitedUserUuid,
disable, !disable,
); );
} }
} else { } else {
@ -640,11 +645,11 @@ export class InviteUserService {
private async updateUserStatus( private async updateUserStatus(
invitedUserUuid: string, invitedUserUuid: string,
projectUuid: string, projectUuid: string,
disable: boolean, isEnabled: boolean,
) { ) {
await this.inviteUserRepository.update( await this.inviteUserRepository.update(
{ uuid: invitedUserUuid, project: { uuid: projectUuid } }, { uuid: invitedUserUuid, project: { uuid: projectUuid } },
{ isEnabled: disable }, { isEnabled },
); );
} }
@ -727,25 +732,31 @@ export class InviteUserService {
{ isActive: false }, { isActive: false },
); );
} else if (userData.status === UserStatusEnum.ACTIVE) { } else if (userData.status === UserStatusEnum.ACTIVE) {
const user = await this.userRepository.findOne({ const invitedUserData = await this.inviteUserRepository.findOne({
where: { inviteUser: { uuid: invitedUserUuid } }, where: { uuid: invitedUserUuid },
relations: ['userSpaces.space', 'userSpaces.space.community'], relations: [
'user.userSpaces.space',
'user.userSpaces.space.community',
],
}); });
if (!user) { if (!invitedUserData.user) {
throw new HttpException( throw new HttpException(
'User account not found', 'User account not found',
HttpStatus.NOT_FOUND, HttpStatus.NOT_FOUND,
); );
} }
await this.disassociateUserFromSpaces(user, userData.project.uuid); await this.disassociateUserFromSpaces(
invitedUserData.user,
userData.project.uuid,
);
await this.inviteUserRepository.update( await this.inviteUserRepository.update(
{ uuid: invitedUserUuid }, { uuid: invitedUserUuid },
{ isActive: false }, { isActive: false },
); );
await this.userRepository.update( await this.userRepository.update(
{ uuid: user.uuid }, { uuid: invitedUserData.user.uuid },
{ isActive: false }, { isActive: false },
); );
} }

View File

@ -66,7 +66,10 @@ import { CqrsModule } from '@nestjs/cqrs';
import { DisableSpaceHandler } from './handlers'; import { DisableSpaceHandler } from './handlers';
import { RegionRepository } from '@app/common/modules/region/repositories'; import { RegionRepository } from '@app/common/modules/region/repositories';
import { TimeZoneRepository } from '@app/common/modules/timezone/repositories'; import { TimeZoneRepository } from '@app/common/modules/timezone/repositories';
import { InviteUserRepository } from '@app/common/modules/Invite-user/repositiories'; import {
InviteUserRepository,
InviteUserSpaceRepository,
} from '@app/common/modules/Invite-user/repositiories';
export const CommandHandlers = [DisableSpaceHandler]; export const CommandHandlers = [DisableSpaceHandler];
@ -124,6 +127,7 @@ export const CommandHandlers = [DisableSpaceHandler];
RegionRepository, RegionRepository,
TimeZoneRepository, TimeZoneRepository,
InviteUserRepository, InviteUserRepository,
InviteUserSpaceRepository,
], ],
exports: [SpaceService], exports: [SpaceService],
}) })

View File

@ -18,7 +18,10 @@ import { PermissionType } from '@app/common/constants/permission-type.enum';
import { InviteSpaceEntity } from '@app/common/modules/space/entities/invite-space.entity'; import { InviteSpaceEntity } from '@app/common/modules/space/entities/invite-space.entity';
import { UserService } from './user.service'; import { UserService } from './user.service';
import { RoleType } from '@app/common/constants/role.type.enum'; import { RoleType } from '@app/common/constants/role.type.enum';
import { InviteUserRepository } from '@app/common/modules/Invite-user/repositiories'; import {
InviteUserRepository,
InviteUserSpaceRepository,
} from '@app/common/modules/Invite-user/repositiories';
import { UserStatusEnum } from '@app/common/constants/user-status.enum'; import { UserStatusEnum } from '@app/common/constants/user-status.enum';
@Injectable() @Injectable()
@ -29,6 +32,7 @@ export class UserSpaceService {
private readonly inviteSpaceRepository: InviteSpaceRepository, private readonly inviteSpaceRepository: InviteSpaceRepository,
private readonly userService: UserService, private readonly userService: UserService,
private readonly inviteUserRepository: InviteUserRepository, private readonly inviteUserRepository: InviteUserRepository,
private readonly inviteUserSpaceRepository: InviteUserSpaceRepository,
private readonly userDevicePermissionService: UserDevicePermissionService, private readonly userDevicePermissionService: UserDevicePermissionService,
) {} ) {}
@ -141,23 +145,36 @@ export class UserSpaceService {
) { ) {
try { try {
const space = await this.getProjectBySpaceUuid(spaceUuid); const space = await this.getProjectBySpaceUuid(spaceUuid);
const invitedUserData = await this.inviteUserRepository.findOne({
const inviteUser = this.inviteUserRepository.create({ where: {
firstName: user.firstName, email: user.email,
lastName: user.lastName, project: { uuid: space.community.project.uuid },
email: user.email, },
jobTitle: null,
phoneNumber: null,
roleType: { uuid: user.role.uuid },
status: UserStatusEnum.ACTIVE,
invitationCode: inviteCode,
invitedBy: RoleType.SPACE_OWNER,
project: { uuid: space.community.project.uuid },
}); });
await this.inviteUserRepository.save(inviteUser); if (!invitedUserData) {
const inviteUser = this.inviteUserRepository.create({
firstName: user.firstName,
lastName: user.lastName,
email: user.email,
jobTitle: null,
phoneNumber: null,
roleType: { uuid: user.role.uuid },
status: UserStatusEnum.ACTIVE,
invitationCode: inviteCode,
invitedBy: RoleType.SPACE_OWNER,
project: { uuid: space.community.project.uuid },
});
const invitedUser = await this.inviteUserRepository.save(inviteUser);
const inviteUserSpace = this.inviteUserSpaceRepository.create({
inviteUser: { uuid: invitedUser.uuid },
space: { uuid: spaceUuid },
});
await this.inviteUserSpaceRepository.save(inviteUserSpace);
}
} catch (err) { } catch (err) {
throw new HttpException( throw new HttpException(
err.message || 'Internal Server Error', err.message || 'Failed to add user as an active invitation.',
HttpStatus.INTERNAL_SERVER_ERROR, HttpStatus.INTERNAL_SERVER_ERROR,
); );
} }

View File

@ -19,7 +19,10 @@ import {
import { UserDevicePermissionService } from 'src/user-device-permission/services'; 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 { InviteUserRepository } from '@app/common/modules/Invite-user/repositiories'; import {
InviteUserRepository,
InviteUserSpaceRepository,
} from '@app/common/modules/Invite-user/repositiories';
@Module({ @Module({
imports: [ConfigModule, CommunityModule], imports: [ConfigModule, CommunityModule],
@ -38,6 +41,7 @@ import { InviteUserRepository } from '@app/common/modules/Invite-user/repositior
UserSpaceService, UserSpaceService,
InviteSpaceRepository, InviteSpaceRepository,
InviteUserRepository, InviteUserRepository,
InviteUserSpaceRepository,
], ],
exports: [UserService], exports: [UserService],
}) })