Add Invite User Module and Update User and Space Entities

This commit introduces a new module for handling user invitations, including DTOs, entities, and repositories. It also updates the User and Space entities to include relationships with the new Invite User entities.
This commit is contained in:
faris Aljohari
2024-12-16 00:17:50 -06:00
parent 852299a273
commit 57397e653a
15 changed files with 341 additions and 50 deletions

View File

@ -721,4 +721,24 @@ export class ControllerRoute {
'This endpoint deletes a users subscription for device messages.';
};
};
static INVITE_USER = class {
public static readonly ROUTE = 'invite-user';
static ACTIONS = class {
public static readonly CREATE_USER_INVITATION_SUMMARY =
'Create user invitation';
public static readonly CREATE_USER_INVITATION_DESCRIPTION =
'This endpoint creates an invitation for a user to assign to role and spaces.';
};
};
static PERMISSION = class {
public static readonly ROUTE = 'permission';
static ACTIONS = class {
public static readonly GET_PERMISSION_BY_ROLE_SUMMARY =
'Get permissions by role';
public static readonly GET_PERMISSION_BY_ROLE_DESCRIPTION =
'This endpoint retrieves the permissions associated with a specific role.';
};
};
}

View File

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

View File

@ -0,0 +1,13 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { InviteUserEntity, InviteUserSpaceEntity } from './entities';
@Module({
providers: [],
exports: [],
controllers: [],
imports: [
TypeOrmModule.forFeature([InviteUserEntity, InviteUserSpaceEntity]),
],
})
export class InviteUserRepositoryModule {}

View File

@ -0,0 +1,42 @@
import { UserStatusEnum } from '@app/common/constants/user-status.enum';
import { IsEnum, IsNotEmpty, IsString } from 'class-validator';
export class InviteUserDto {
@IsString()
@IsNotEmpty()
public uuid: string;
@IsString()
@IsNotEmpty()
public email: string;
@IsString()
@IsNotEmpty()
public jobTitle: string;
@IsEnum(UserStatusEnum)
@IsNotEmpty()
public status: UserStatusEnum;
@IsString()
@IsNotEmpty()
public firstName: string;
@IsString()
@IsNotEmpty()
public lastName: string;
}
export class InviteUserSpaceDto {
@IsString()
@IsNotEmpty()
public uuid: string;
@IsString()
@IsNotEmpty()
public inviteUserUuid: string;
@IsString()
@IsNotEmpty()
public spaceUuid: string;
@IsString()
@IsNotEmpty()
public invitationCode: string;
}

View File

@ -0,0 +1 @@
export * from './Invite-user.dto';

View File

@ -0,0 +1,112 @@
import {
Column,
Entity,
JoinColumn,
ManyToOne,
OneToMany,
OneToOne,
Unique,
} from 'typeorm';
import { InviteUserDto, InviteUserSpaceDto } from '../dtos';
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { RoleTypeEntity } from '../../role-type/entities';
import { UserStatusEnum } from '@app/common/constants/user-status.enum';
import { UserEntity } from '../../user/entities';
import { SpaceEntity } from '../../space/entities';
@Entity({ name: 'invite-user' })
@Unique(['email', 'invitationCode'])
export class InviteUserEntity extends AbstractEntity<InviteUserDto> {
@Column({
type: 'uuid',
default: () => 'gen_random_uuid()',
nullable: false,
})
public uuid: string;
@Column({
nullable: false,
unique: true,
})
email: string;
@Column({
nullable: false,
})
jobTitle: string;
@Column({
nullable: false,
enum: Object.values(UserStatusEnum),
})
status: string;
@Column()
public firstName: string;
@Column({
nullable: false,
})
public lastName: string;
@Column({
nullable: false,
})
public phoneNumber: string;
@Column({
nullable: false,
default: true,
})
public isEnabled: boolean;
@Column({
nullable: false,
default: true,
})
public isActive: boolean;
@Column({
nullable: false,
unique: true,
})
public invitationCode: string;
// Relation with RoleTypeEntity
@ManyToOne(() => RoleTypeEntity, (roleType) => roleType.invitedUsers, {
nullable: false,
onDelete: 'CASCADE',
})
public roleType: RoleTypeEntity;
@OneToOne(() => UserEntity, (user) => user.inviteUser, { nullable: true })
@JoinColumn({ name: 'user_uuid' }) // Foreign key in InviteUserEntity
user: UserEntity;
@OneToMany(
() => InviteUserSpaceEntity,
(inviteUserSpace) => inviteUserSpace.inviteUser,
)
spaces: InviteUserSpaceEntity[];
constructor(partial: Partial<InviteUserEntity>) {
super();
Object.assign(this, partial);
}
}
@Entity({ name: 'invite-user-space' })
@Unique(['inviteUser', 'space'])
export class InviteUserSpaceEntity extends AbstractEntity<InviteUserSpaceDto> {
@Column({
type: 'uuid',
default: () => 'gen_random_uuid()',
nullable: false,
})
public uuid: string;
@ManyToOne(() => InviteUserEntity, (inviteUser) => inviteUser.spaces)
@JoinColumn({ name: 'invite_user_uuid' })
public inviteUser: InviteUserEntity;
@ManyToOne(() => SpaceEntity, (space) => space.invitedUsers)
@JoinColumn({ name: 'space_uuid' })
public space: SpaceEntity;
constructor(partial: Partial<InviteUserSpaceEntity>) {
super();
Object.assign(this, partial);
}
}

View File

@ -0,0 +1 @@
export * from './Invite-user.entity';

View File

@ -0,0 +1,16 @@
import { DataSource, Repository } from 'typeorm';
import { Injectable } from '@nestjs/common';
import { InviteUserEntity, InviteUserSpaceEntity } from '../entities/';
@Injectable()
export class InviteUserRepository extends Repository<InviteUserEntity> {
constructor(private dataSource: DataSource) {
super(InviteUserEntity, dataSource.createEntityManager());
}
}
@Injectable()
export class InviteUserSpaceRepository extends Repository<InviteUserSpaceEntity> {
constructor(private dataSource: DataSource) {
super(InviteUserSpaceEntity, dataSource.createEntityManager());
}
}

View File

@ -0,0 +1 @@
export * from './Invite-user.repository';

View File

@ -15,6 +15,7 @@ import { SubspaceEntity } from './subspace.entity';
import { SpaceLinkEntity } from './space-link.entity';
import { SpaceProductEntity } from './space-product.entity';
import { SceneEntity } from '../../scene/entities';
import { InviteUserSpaceEntity } from '../../Invite-user/entities';
@Entity({ name: 'space' })
@Unique(['invitationCode'])
@ -97,7 +98,11 @@ export class SpaceEntity extends AbstractEntity<SpaceDto> {
@OneToMany(() => SceneEntity, (scene) => scene.space)
scenes: SceneEntity[];
@OneToMany(
() => InviteUserSpaceEntity,
(inviteUserSpace) => inviteUserSpace.space,
)
invitedUsers: InviteUserSpaceEntity[];
constructor(partial: Partial<SpaceEntity>) {
super();
Object.assign(this, partial);

View File

@ -58,20 +58,6 @@ export class UserOtpDto {
public expiryTime: string;
}
export class UserRoleDto {
@IsString()
@IsNotEmpty()
public uuid: string;
@IsString()
@IsNotEmpty()
public userUuid: string;
@IsString()
@IsNotEmpty()
public roleTypeUuid: string;
}
export class UserSpaceDto {
@IsString()
@IsNotEmpty()

View File

@ -2,15 +2,16 @@ import {
Column,
DeleteDateColumn,
Entity,
JoinColumn,
ManyToOne,
OneToMany,
OneToOne,
Unique,
} from 'typeorm';
import {
UserDto,
UserNotificationDto,
UserOtpDto,
UserRoleDto,
UserSpaceDto,
} from '../dtos';
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
@ -26,6 +27,8 @@ import { OtpType } from '../../../../src/constants/otp-type.enum';
import { RoleTypeEntity } from '../../role-type/entities';
import { SpaceEntity } from '../../space/entities';
import { VisitorPasswordEntity } from '../../visitor-password/entities';
import { InviteUserEntity } from '../../Invite-user/entities';
import { ProjectEntity } from '../../project/entities';
@Entity({ name: 'user' })
export class UserEntity extends AbstractEntity<UserDto> {
@ -100,10 +103,7 @@ export class UserEntity extends AbstractEntity<UserDto> {
(deviceUserNotification) => deviceUserNotification.user,
)
deviceUserNotification: DeviceNotificationEntity[];
@OneToMany(() => UserRoleEntity, (role) => role.user, {
nullable: true,
})
roles: UserRoleEntity[];
@ManyToOne(() => RegionEntity, (region) => region.users, { nullable: true })
region: RegionEntity;
@ManyToOne(() => TimeZoneEntity, (timezone) => timezone.users, {
@ -116,6 +116,21 @@ export class UserEntity extends AbstractEntity<UserDto> {
)
public visitorPasswords: VisitorPasswordEntity[];
@ManyToOne(() => RoleTypeEntity, (roleType) => roleType.users, {
nullable: true,
})
public roleType: RoleTypeEntity;
@OneToOne(() => InviteUserEntity, (inviteUser) => inviteUser.user, {
nullable: true,
})
@JoinColumn({ name: 'invite_user_uuid' })
inviteUser: InviteUserEntity;
@ManyToOne(() => ProjectEntity, (project) => project.users, {
nullable: true,
})
@JoinColumn({ name: 'project_uuid' })
public project: ProjectEntity;
constructor(partial: Partial<UserEntity>) {
super();
Object.assign(this, partial);
@ -125,7 +140,7 @@ export class UserEntity extends AbstractEntity<UserDto> {
@Entity({ name: 'user-notification' })
@Unique(['user', 'subscriptionUuid'])
export class UserNotificationEntity extends AbstractEntity<UserNotificationDto> {
@ManyToOne(() => UserEntity, (user) => user.roles, {
@ManyToOne(() => UserEntity, (user) => user.roleType, {
nullable: false,
})
user: UserEntity;
@ -178,25 +193,6 @@ export class UserOtpEntity extends AbstractEntity<UserOtpDto> {
}
}
@Entity({ name: 'user-role' })
@Unique(['user', 'roleType'])
export class UserRoleEntity extends AbstractEntity<UserRoleDto> {
@ManyToOne(() => UserEntity, (user) => user.roles, {
nullable: false,
})
user: UserEntity;
@ManyToOne(() => RoleTypeEntity, (roleType) => roleType.roles, {
nullable: false,
})
roleType: RoleTypeEntity;
constructor(partial: Partial<UserRoleEntity>) {
super();
Object.assign(this, partial);
}
}
@Entity({ name: 'user-space' })
@Unique(['user', 'space'])
export class UserSpaceEntity extends AbstractEntity<UserSpaceDto> {

View File

@ -4,7 +4,6 @@ import {
UserEntity,
UserNotificationEntity,
UserOtpEntity,
UserRoleEntity,
UserSpaceEntity,
} from '../entities/';
@ -29,13 +28,6 @@ export class UserOtpRepository extends Repository<UserOtpEntity> {
}
}
@Injectable()
export class UserRoleRepository extends Repository<UserRoleEntity> {
constructor(private dataSource: DataSource) {
super(UserRoleEntity, dataSource.createEntityManager());
}
}
@Injectable()
export class UserSpaceRepository extends Repository<UserSpaceEntity> {
constructor(private dataSource: DataSource) {

View File

@ -10,7 +10,6 @@ import { RoleTypeSeeder } from './services/role.type.seeder';
import { SpaceRepositoryModule } from '../modules/space/space.repository.module';
import { SuperAdminSeeder } from './services/supper.admin.seeder';
import { UserRepository } from '../modules/user/repositories';
import { UserRoleRepository } from '../modules/user/repositories';
import { UserRepositoryModule } from '../modules/user/user.repository.module';
import { RegionSeeder } from './services/regions.seeder';
import { RegionRepository } from '../modules/region/repositories';
@ -28,7 +27,6 @@ import { SceneIconRepository } from '../modules/scene/repositories';
RoleTypeRepository,
SuperAdminSeeder,
UserRepository,
UserRoleRepository,
RegionSeeder,
RegionRepository,
TimeZoneSeeder,