mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-11-26 17:34:54 +00:00
Merge branch 'feat/device_permissions' into SP-171-be-create-groups-to-control-devices-per-group
This commit is contained in:
@ -7,22 +7,22 @@ import { JwtStrategy } from './strategies/jwt.strategy';
|
|||||||
import { UserSessionRepository } from '../modules/session/repositories/session.repository';
|
import { UserSessionRepository } from '../modules/session/repositories/session.repository';
|
||||||
import { AuthService } from './services/auth.service';
|
import { AuthService } from './services/auth.service';
|
||||||
import { UserRepository } from '../modules/user/repositories';
|
import { UserRepository } from '../modules/user/repositories';
|
||||||
|
import { RefreshTokenStrategy } from './strategies/refresh-token.strategy';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot(),
|
ConfigModule.forRoot(),
|
||||||
PassportModule,
|
PassportModule,
|
||||||
JwtModule.registerAsync({
|
JwtModule.register({}),
|
||||||
imports: [ConfigModule],
|
|
||||||
inject: [ConfigService],
|
|
||||||
useFactory: async (configService: ConfigService) => ({
|
|
||||||
secret: configService.get('JWT_SECRET'),
|
|
||||||
signOptions: { expiresIn: configService.get('JWT_EXPIRE_TIME') },
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
HelperModule,
|
HelperModule,
|
||||||
],
|
],
|
||||||
providers: [JwtStrategy, UserSessionRepository, AuthService, UserRepository],
|
providers: [
|
||||||
|
JwtStrategy,
|
||||||
|
RefreshTokenStrategy,
|
||||||
|
UserSessionRepository,
|
||||||
|
AuthService,
|
||||||
|
UserRepository,
|
||||||
|
],
|
||||||
exports: [AuthService],
|
exports: [AuthService],
|
||||||
})
|
})
|
||||||
export class AuthModule {}
|
export class AuthModule {}
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||||
import { JwtService } from '@nestjs/jwt';
|
import { JwtService } from '@nestjs/jwt';
|
||||||
|
import * as argon2 from 'argon2';
|
||||||
import { HelperHashService } from '../../helper/services';
|
import { HelperHashService } from '../../helper/services';
|
||||||
import { UserRepository } from '../../../../common/src/modules/user/repositories';
|
import { UserRepository } from '../../../../common/src/modules/user/repositories';
|
||||||
import { UserSessionRepository } from '../../../../common/src/modules/session/repositories/session.repository';
|
import { UserSessionRepository } from '../../../../common/src/modules/session/repositories/session.repository';
|
||||||
import { UserSessionEntity } from '../../../../common/src/modules/session/entities';
|
import { UserSessionEntity } from '../../../../common/src/modules/session/entities';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
@ -12,6 +14,7 @@ export class AuthService {
|
|||||||
private readonly userRepository: UserRepository,
|
private readonly userRepository: UserRepository,
|
||||||
private readonly sessionRepository: UserSessionRepository,
|
private readonly sessionRepository: UserSessionRepository,
|
||||||
private readonly helperHashService: HelperHashService,
|
private readonly helperHashService: HelperHashService,
|
||||||
|
private readonly configService: ConfigService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async validateUser(email: string, pass: string): Promise<any> {
|
async validateUser(email: string, pass: string): Promise<any> {
|
||||||
@ -40,6 +43,24 @@ export class AuthService {
|
|||||||
return await this.sessionRepository.save(data);
|
return await this.sessionRepository.save(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getTokens(payload) {
|
||||||
|
const [accessToken, refreshToken] = await Promise.all([
|
||||||
|
this.jwtService.signAsync(payload, {
|
||||||
|
secret: this.configService.get<string>('JWT_SECRET'),
|
||||||
|
expiresIn: '24h',
|
||||||
|
}),
|
||||||
|
this.jwtService.signAsync(payload, {
|
||||||
|
secret: this.configService.get<string>('JWT_SECRET'),
|
||||||
|
expiresIn: '7d',
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
accessToken,
|
||||||
|
refreshToken,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async login(user: any) {
|
async login(user: any) {
|
||||||
const payload = {
|
const payload = {
|
||||||
email: user.email,
|
email: user.email,
|
||||||
@ -48,8 +69,22 @@ export class AuthService {
|
|||||||
type: user.type,
|
type: user.type,
|
||||||
sessionId: user.sessionId,
|
sessionId: user.sessionId,
|
||||||
};
|
};
|
||||||
return {
|
const tokens = await this.getTokens(payload);
|
||||||
access_token: this.jwtService.sign(payload),
|
await this.updateRefreshToken(user.uuid, tokens.refreshToken);
|
||||||
};
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateRefreshToken(userId: string, refreshToken: string) {
|
||||||
|
const hashedRefreshToken = await this.hashData(refreshToken);
|
||||||
|
await this.userRepository.update(
|
||||||
|
{ uuid: userId },
|
||||||
|
{
|
||||||
|
refreshToken: hashedRefreshToken,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
hashData(data: string) {
|
||||||
|
return argon2.hash(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { UserSessionRepository } from '../../../src/modules/session/repositories
|
|||||||
import { AuthInterface } from '../interfaces/auth.interface';
|
import { AuthInterface } from '../interfaces/auth.interface';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class JwtStrategy extends PassportStrategy(Strategy) {
|
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly sessionRepository: UserSessionRepository,
|
private readonly sessionRepository: UserSessionRepository,
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
|
|||||||
42
libs/common/src/auth/strategies/refresh-token.strategy.ts
Normal file
42
libs/common/src/auth/strategies/refresh-token.strategy.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { ExtractJwt, Strategy } from 'passport-jwt';
|
||||||
|
import { PassportStrategy } from '@nestjs/passport';
|
||||||
|
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||||
|
import { UserSessionRepository } from '../../../src/modules/session/repositories/session.repository';
|
||||||
|
import { AuthInterface } from '../interfaces/auth.interface';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class RefreshTokenStrategy extends PassportStrategy(
|
||||||
|
Strategy,
|
||||||
|
'jwt-refresh',
|
||||||
|
) {
|
||||||
|
constructor(
|
||||||
|
private readonly sessionRepository: UserSessionRepository,
|
||||||
|
private readonly configService: ConfigService,
|
||||||
|
) {
|
||||||
|
super({
|
||||||
|
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||||
|
ignoreExpiration: false,
|
||||||
|
secretOrKey: configService.get('JWT_SECRET'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async validate(payload: AuthInterface) {
|
||||||
|
const validateUser = await this.sessionRepository.findOne({
|
||||||
|
where: {
|
||||||
|
uuid: payload.sessionId,
|
||||||
|
isLoggedOut: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (validateUser) {
|
||||||
|
return {
|
||||||
|
email: payload.email,
|
||||||
|
userId: payload.id,
|
||||||
|
uuid: payload.uuid,
|
||||||
|
sessionId: payload.sessionId,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
throw new BadRequestException('Unauthorized');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
4
libs/common/src/constants/permission-type.enum.ts
Normal file
4
libs/common/src/constants/permission-type.enum.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export enum PermissionType {
|
||||||
|
READ = 'READ',
|
||||||
|
CONTROLLABLE = 'CONTROLLABLE',
|
||||||
|
}
|
||||||
@ -7,6 +7,8 @@ import { UserSessionEntity } from '../modules/session/entities/session.entity';
|
|||||||
import { UserOtpEntity } from '../modules/user-otp/entities';
|
import { UserOtpEntity } from '../modules/user-otp/entities';
|
||||||
import { HomeEntity } from '../modules/home/entities';
|
import { HomeEntity } from '../modules/home/entities';
|
||||||
import { ProductEntity } from '../modules/product/entities';
|
import { ProductEntity } from '../modules/product/entities';
|
||||||
|
import { DeviceEntity, DeviceUserPermissionEntity } from '../modules/device/entities';
|
||||||
|
import { PermissionTypeEntity } from '../modules/permission/entities';
|
||||||
import { SpaceEntity } from '../modules/space/entities';
|
import { SpaceEntity } from '../modules/space/entities';
|
||||||
import { SpaceTypeEntity } from '../modules/space-type/entities';
|
import { SpaceTypeEntity } from '../modules/space-type/entities';
|
||||||
import { UserSpaceEntity } from '../modules/user-space/entities';
|
import { UserSpaceEntity } from '../modules/user-space/entities';
|
||||||
@ -31,6 +33,9 @@ import { GroupEntity } from '../modules/group/entities';
|
|||||||
UserOtpEntity,
|
UserOtpEntity,
|
||||||
HomeEntity,
|
HomeEntity,
|
||||||
ProductEntity,
|
ProductEntity,
|
||||||
|
DeviceUserPermissionEntity,
|
||||||
|
DeviceEntity,
|
||||||
|
PermissionTypeEntity,
|
||||||
SpaceEntity,
|
SpaceEntity,
|
||||||
SpaceTypeEntity,
|
SpaceTypeEntity,
|
||||||
UserSpaceEntity,
|
UserSpaceEntity,
|
||||||
|
|||||||
11
libs/common/src/guards/jwt-refresh.auth.guard.ts
Normal file
11
libs/common/src/guards/jwt-refresh.auth.guard.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { UnauthorizedException } from '@nestjs/common';
|
||||||
|
import { AuthGuard } from '@nestjs/passport';
|
||||||
|
|
||||||
|
export class RefreshTokenGuard extends AuthGuard('jwt-refresh') {
|
||||||
|
handleRequest(err, user) {
|
||||||
|
if (err || !user) {
|
||||||
|
throw err || new UnauthorizedException();
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
libs/common/src/modules/device/device.repository.module.ts
Normal file
13
libs/common/src/modules/device/device.repository.module.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
import { DeviceEntity, DeviceUserPermissionEntity } from './entities';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
providers: [],
|
||||||
|
exports: [],
|
||||||
|
controllers: [],
|
||||||
|
imports: [
|
||||||
|
TypeOrmModule.forFeature([DeviceEntity, DeviceUserPermissionEntity]),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class DeviceRepositoryModule {}
|
||||||
19
libs/common/src/modules/device/dtos/device-user-type.dto.ts
Normal file
19
libs/common/src/modules/device/dtos/device-user-type.dto.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { IsNotEmpty, IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class DeviceUserTypeDto {
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
public uuid: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
public userUuid: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
public deviceUuid: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
public permissionTypeUuid: string;
|
||||||
|
}
|
||||||
20
libs/common/src/modules/device/dtos/device.dto.ts
Normal file
20
libs/common/src/modules/device/dtos/device.dto.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { IsNotEmpty, IsString } from "class-validator";
|
||||||
|
|
||||||
|
export class DeviceDto{
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
public uuid: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
spaceUuid:string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
deviceTuyaUuid:string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
productUuid:string;
|
||||||
|
}
|
||||||
2
libs/common/src/modules/device/dtos/index.ts
Normal file
2
libs/common/src/modules/device/dtos/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './device.dto';
|
||||||
|
export * from './device-user-type.dto';
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm';
|
||||||
|
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||||
|
import { DeviceUserTypeDto } from '../dtos/device-user-type.dto';
|
||||||
|
import { DeviceEntity } from './device.entity';
|
||||||
|
import { PermissionTypeEntity } from '../../permission/entities';
|
||||||
|
|
||||||
|
@Entity({ name: 'device-user-permission' })
|
||||||
|
export class DeviceUserPermissionEntity extends AbstractEntity<DeviceUserTypeDto> {
|
||||||
|
@Column({
|
||||||
|
nullable: false,
|
||||||
|
})
|
||||||
|
public userUuid: string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
nullable: false,
|
||||||
|
})
|
||||||
|
deviceUuid: string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
nullable: false,
|
||||||
|
})
|
||||||
|
public permissionTypeUuid: string;
|
||||||
|
|
||||||
|
@ManyToOne(() => DeviceEntity, {
|
||||||
|
onDelete: 'CASCADE',
|
||||||
|
onUpdate: 'CASCADE',
|
||||||
|
})
|
||||||
|
@JoinColumn({ name: 'device_uuid', referencedColumnName: 'uuid' })
|
||||||
|
device: DeviceEntity;
|
||||||
|
|
||||||
|
@ManyToOne(() => PermissionTypeEntity, {
|
||||||
|
onDelete: 'CASCADE',
|
||||||
|
onUpdate: 'CASCADE',
|
||||||
|
})
|
||||||
|
@JoinColumn({ name: 'permission_type_uuid', referencedColumnName: 'uuid' })
|
||||||
|
type: PermissionTypeEntity;
|
||||||
|
|
||||||
|
constructor(partial: Partial<DeviceUserPermissionEntity>) {
|
||||||
|
super();
|
||||||
|
Object.assign(this, partial);
|
||||||
|
}
|
||||||
|
}
|
||||||
44
libs/common/src/modules/device/entities/device.entity.ts
Normal file
44
libs/common/src/modules/device/entities/device.entity.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { Column, Entity, OneToMany } from 'typeorm';
|
||||||
|
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||||
|
import { DeviceDto } from '../dtos/device.dto';
|
||||||
|
import { DeviceUserPermissionEntity } from './device-user-type.entity';
|
||||||
|
|
||||||
|
@Entity({ name: 'device' })
|
||||||
|
export class DeviceEntity extends AbstractEntity<DeviceDto> {
|
||||||
|
@Column({
|
||||||
|
nullable: false,
|
||||||
|
})
|
||||||
|
public spaceUuid: string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
nullable: false,
|
||||||
|
})
|
||||||
|
deviceTuyaUuid: string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
nullable: false,
|
||||||
|
})
|
||||||
|
public productUuid: string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
nullable: true,
|
||||||
|
default: true,
|
||||||
|
})
|
||||||
|
isActive: true;
|
||||||
|
|
||||||
|
@OneToMany(
|
||||||
|
() => DeviceUserPermissionEntity,
|
||||||
|
(permission) => permission.device,
|
||||||
|
{
|
||||||
|
nullable: true,
|
||||||
|
onDelete: 'CASCADE',
|
||||||
|
onUpdate: 'CASCADE',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
permission: DeviceUserPermissionEntity[];
|
||||||
|
|
||||||
|
constructor(partial: Partial<DeviceEntity>) {
|
||||||
|
super();
|
||||||
|
Object.assign(this, partial);
|
||||||
|
}
|
||||||
|
}
|
||||||
2
libs/common/src/modules/device/entities/index.ts
Normal file
2
libs/common/src/modules/device/entities/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './device.entity';
|
||||||
|
export * from './device-user-type.entity';
|
||||||
1
libs/common/src/modules/device/index.ts
Normal file
1
libs/common/src/modules/device/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './device.repository.module';
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { DataSource, Repository } from 'typeorm';
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { DeviceUserPermissionEntity } from '../entities';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DeviceUserTypeRepository extends Repository<DeviceUserPermissionEntity> {
|
||||||
|
constructor(private dataSource: DataSource) {
|
||||||
|
super(DeviceUserPermissionEntity, dataSource.createEntityManager());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { DataSource, Repository } from 'typeorm';
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { DeviceEntity } from '../entities';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DeviceRepository extends Repository<DeviceEntity> {
|
||||||
|
constructor(private dataSource: DataSource) {
|
||||||
|
super(DeviceEntity, dataSource.createEntityManager());
|
||||||
|
}
|
||||||
|
}
|
||||||
2
libs/common/src/modules/device/repositories/index.ts
Normal file
2
libs/common/src/modules/device/repositories/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './device.repository';
|
||||||
|
export * from './device-user-type.repository';
|
||||||
1
libs/common/src/modules/permission/dtos/index.ts
Normal file
1
libs/common/src/modules/permission/dtos/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './permission.dto'
|
||||||
11
libs/common/src/modules/permission/dtos/permission.dto.ts
Normal file
11
libs/common/src/modules/permission/dtos/permission.dto.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { PermissionType } from '@app/common/constants/permission-type.enum';
|
||||||
|
import { IsEnum, IsNotEmpty, IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class PermissionTypeDto {
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
public uuid: string;
|
||||||
|
|
||||||
|
@IsEnum(PermissionType)
|
||||||
|
public type: PermissionType;
|
||||||
|
}
|
||||||
1
libs/common/src/modules/permission/entities/index.ts
Normal file
1
libs/common/src/modules/permission/entities/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './permission.entity'
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
import { Column, Entity } from 'typeorm';
|
||||||
|
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||||
|
import { PermissionType } from '@app/common/constants/permission-type.enum';
|
||||||
|
import { PermissionTypeDto } from '../dtos/permission.dto';
|
||||||
|
|
||||||
|
@Entity({ name: 'permission-type' })
|
||||||
|
export class PermissionTypeEntity extends AbstractEntity<PermissionTypeDto> {
|
||||||
|
@Column({
|
||||||
|
nullable: false,
|
||||||
|
enum: Object.values(PermissionType),
|
||||||
|
})
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
constructor(partial: Partial<PermissionTypeEntity>) {
|
||||||
|
super();
|
||||||
|
Object.assign(this, partial);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
import { PermissionTypeEntity } from './entities/permission.entity';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
providers: [],
|
||||||
|
exports: [],
|
||||||
|
controllers: [],
|
||||||
|
imports: [TypeOrmModule.forFeature([PermissionTypeEntity])],
|
||||||
|
})
|
||||||
|
export class PermissionTypeRepositoryModule {}
|
||||||
1
libs/common/src/modules/permission/repositories/index.ts
Normal file
1
libs/common/src/modules/permission/repositories/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './permission.repository'
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { DataSource, Repository } from 'typeorm';
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { PermissionTypeEntity } from '../entities/permission.entity';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class PermissionTypeRepository extends Repository<PermissionTypeEntity> {
|
||||||
|
constructor(private dataSource: DataSource) {
|
||||||
|
super(PermissionTypeEntity, dataSource.createEntityManager());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -31,12 +31,23 @@ export class UserEntity extends AbstractEntity<UserDto> {
|
|||||||
})
|
})
|
||||||
public lastName: string;
|
public lastName: string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
public refreshToken: string;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: true,
|
nullable: true,
|
||||||
default: false,
|
default: false,
|
||||||
})
|
})
|
||||||
public isUserVerified: boolean;
|
public isUserVerified: boolean;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
nullable: false,
|
||||||
|
default: true,
|
||||||
|
})
|
||||||
|
public isActive: boolean;
|
||||||
|
|
||||||
@OneToMany(() => UserSpaceEntity, (userSpace) => userSpace.user)
|
@OneToMany(() => UserSpaceEntity, (userSpace) => userSpace.user)
|
||||||
userSpaces: UserSpaceEntity[];
|
userSpaces: UserSpaceEntity[];
|
||||||
|
|
||||||
|
|||||||
41
package-lock.json
generated
41
package-lock.json
generated
@ -18,6 +18,7 @@
|
|||||||
"@nestjs/swagger": "^7.3.0",
|
"@nestjs/swagger": "^7.3.0",
|
||||||
"@nestjs/typeorm": "^10.0.2",
|
"@nestjs/typeorm": "^10.0.2",
|
||||||
"@tuya/tuya-connector-nodejs": "^2.1.2",
|
"@tuya/tuya-connector-nodejs": "^2.1.2",
|
||||||
|
"argon2": "^0.40.1",
|
||||||
"axios": "^1.6.7",
|
"axios": "^1.6.7",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
@ -2111,6 +2112,14 @@
|
|||||||
"npm": ">=5.0.0"
|
"npm": ">=5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@phc/format": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@phc/format/-/format-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@pkgjs/parseargs": {
|
"node_modules/@pkgjs/parseargs": {
|
||||||
"version": "0.11.0",
|
"version": "0.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||||
@ -3032,6 +3041,20 @@
|
|||||||
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
||||||
"devOptional": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
|
"node_modules/argon2": {
|
||||||
|
"version": "0.40.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/argon2/-/argon2-0.40.1.tgz",
|
||||||
|
"integrity": "sha512-DjtHDwd7pm12qeWyfihHoM8Bn5vGcgH6sKwgPqwNYroRmxlrzadHEvMyuvQxN/V8YSyRRKD5x6ito09q1e9OyA==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@phc/format": "^1.0.0",
|
||||||
|
"node-addon-api": "^7.1.0",
|
||||||
|
"node-gyp-build": "^4.8.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.17.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/argparse": {
|
"node_modules/argparse": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||||
@ -7168,6 +7191,14 @@
|
|||||||
"integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==",
|
"integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/node-addon-api": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==",
|
||||||
|
"engines": {
|
||||||
|
"node": "^16 || ^18 || >= 20"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/node-emoji": {
|
"node_modules/node-emoji": {
|
||||||
"version": "1.11.0",
|
"version": "1.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz",
|
||||||
@ -7196,6 +7227,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/node-gyp-build": {
|
||||||
|
"version": "4.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz",
|
||||||
|
"integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==",
|
||||||
|
"bin": {
|
||||||
|
"node-gyp-build": "bin.js",
|
||||||
|
"node-gyp-build-optional": "optional.js",
|
||||||
|
"node-gyp-build-test": "build-test.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/node-int64": {
|
"node_modules/node-int64": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
|
||||||
|
|||||||
@ -29,6 +29,7 @@
|
|||||||
"@nestjs/swagger": "^7.3.0",
|
"@nestjs/swagger": "^7.3.0",
|
||||||
"@nestjs/typeorm": "^10.0.2",
|
"@nestjs/typeorm": "^10.0.2",
|
||||||
"@tuya/tuya-connector-nodejs": "^2.1.2",
|
"@tuya/tuya-connector-nodejs": "^2.1.2",
|
||||||
|
"argon2": "^0.40.1",
|
||||||
"axios": "^1.6.7",
|
"axios": "^1.6.7",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { HomeModule } from './home/home.module';
|
|||||||
import { RoomModule } from './room/room.module';
|
import { RoomModule } from './room/room.module';
|
||||||
import { GroupModule } from './group/group.module';
|
import { GroupModule } from './group/group.module';
|
||||||
import { DeviceModule } from './device/device.module';
|
import { DeviceModule } from './device/device.module';
|
||||||
|
import { UserDevicePermissionModule } from './user-device-permission/user-device-permission.module';
|
||||||
import { CommunityModule } from './community/community.module';
|
import { CommunityModule } from './community/community.module';
|
||||||
import { BuildingModule } from './building/building.module';
|
import { BuildingModule } from './building/building.module';
|
||||||
import { FloorModule } from './floor/floor.module';
|
import { FloorModule } from './floor/floor.module';
|
||||||
@ -28,6 +29,7 @@ import { UnitModule } from './unit/unit.module';
|
|||||||
RoomModule,
|
RoomModule,
|
||||||
GroupModule,
|
GroupModule,
|
||||||
DeviceModule,
|
DeviceModule,
|
||||||
|
UserDevicePermissionModule
|
||||||
],
|
],
|
||||||
controllers: [AuthenticationController],
|
controllers: [AuthenticationController],
|
||||||
})
|
})
|
||||||
|
|||||||
@ -2,9 +2,11 @@ import {
|
|||||||
Body,
|
Body,
|
||||||
Controller,
|
Controller,
|
||||||
Delete,
|
Delete,
|
||||||
|
Get,
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
Param,
|
Param,
|
||||||
Post,
|
Post,
|
||||||
|
Req,
|
||||||
UseGuards,
|
UseGuards,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { UserAuthService } from '../services/user-auth.service';
|
import { UserAuthService } from '../services/user-auth.service';
|
||||||
@ -14,6 +16,8 @@ import { ResponseMessage } from '../../../libs/common/src/response/response.deco
|
|||||||
import { UserLoginDto } from '../dtos/user-login.dto';
|
import { UserLoginDto } from '../dtos/user-login.dto';
|
||||||
import { JwtAuthGuard } from '../../../libs/common/src/guards/jwt.auth.guard';
|
import { JwtAuthGuard } from '../../../libs/common/src/guards/jwt.auth.guard';
|
||||||
import { ForgetPasswordDto, UserOtpDto, VerifyOtpDto } from '../dtos';
|
import { ForgetPasswordDto, UserOtpDto, VerifyOtpDto } from '../dtos';
|
||||||
|
import { Request } from 'express';
|
||||||
|
import { RefreshTokenGuard } from '@app/common/guards/jwt-refresh.auth.guard';
|
||||||
|
|
||||||
@Controller({
|
@Controller({
|
||||||
version: '1',
|
version: '1',
|
||||||
@ -93,4 +97,33 @@ export class UserAuthController {
|
|||||||
message: 'Password changed successfully',
|
message: 'Password changed successfully',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
|
@Get('user/list')
|
||||||
|
async userList(@Req() req) {
|
||||||
|
const userList = await this.userAuthService.userList();
|
||||||
|
return {
|
||||||
|
statusCode: HttpStatus.OK,
|
||||||
|
data: userList,
|
||||||
|
message: 'User List Fetched Successfully',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@UseGuards(RefreshTokenGuard)
|
||||||
|
@Get('refresh-token')
|
||||||
|
async refreshToken(@Req() req) {
|
||||||
|
const refreshToken = await this.userAuthService.refreshToken(
|
||||||
|
req.user.uuid,
|
||||||
|
req.headers.authorization,
|
||||||
|
req.user.type,
|
||||||
|
req.user.sessionId,
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
statusCode: HttpStatus.OK,
|
||||||
|
data: refreshToken,
|
||||||
|
message: 'Refresh Token added Successfully',
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { UserRepository } from '../../../libs/common/src/modules/user/repositories';
|
import { UserRepository } from '../../../libs/common/src/modules/user/repositories';
|
||||||
import {
|
import {
|
||||||
BadRequestException,
|
BadRequestException,
|
||||||
|
ForbiddenException,
|
||||||
Injectable,
|
Injectable,
|
||||||
UnauthorizedException,
|
UnauthorizedException,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
@ -14,7 +15,7 @@ import { ForgetPasswordDto, UserOtpDto, VerifyOtpDto } from '../dtos';
|
|||||||
import { EmailService } from '../../../libs/common/src/util/email.service';
|
import { EmailService } from '../../../libs/common/src/util/email.service';
|
||||||
import { OtpType } from '../../../libs/common/src/constants/otp-type.enum';
|
import { OtpType } from '../../../libs/common/src/constants/otp-type.enum';
|
||||||
import { UserEntity } from '../../../libs/common/src/modules/user/entities/user.entity';
|
import { UserEntity } from '../../../libs/common/src/modules/user/entities/user.entity';
|
||||||
import { ILoginResponse } from '../constants/login.response.constant';
|
import * as argon2 from 'argon2';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserAuthService {
|
export class UserAuthService {
|
||||||
@ -64,7 +65,7 @@ export class UserAuthService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async userLogin(data: UserLoginDto): Promise<ILoginResponse> {
|
async userLogin(data: UserLoginDto) {
|
||||||
const user = await this.authService.validateUser(data.email, data.password);
|
const user = await this.authService.validateUser(data.email, data.password);
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new UnauthorizedException('Invalid login credentials.');
|
throw new UnauthorizedException('Invalid login credentials.');
|
||||||
@ -86,7 +87,7 @@ export class UserAuthService {
|
|||||||
|
|
||||||
return await this.authService.login({
|
return await this.authService.login({
|
||||||
email: user.email,
|
email: user.email,
|
||||||
userId: user.id,
|
userId: user.uuid,
|
||||||
uuid: user.uuid,
|
uuid: user.uuid,
|
||||||
sessionId: session[1].uuid,
|
sessionId: session[1].uuid,
|
||||||
});
|
});
|
||||||
@ -97,7 +98,7 @@ export class UserAuthService {
|
|||||||
if (!user) {
|
if (!user) {
|
||||||
throw new BadRequestException('User does not found');
|
throw new BadRequestException('User does not found');
|
||||||
}
|
}
|
||||||
return await this.userRepository.delete({ uuid });
|
return await this.userRepository.update({ uuid }, { isActive: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
async findOneById(id: string): Promise<UserEntity> {
|
async findOneById(id: string): Promise<UserEntity> {
|
||||||
@ -148,4 +149,41 @@ export class UserAuthService {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async userList(): Promise<UserEntity[]> {
|
||||||
|
return await this.userRepository.find({
|
||||||
|
where: { isActive: true },
|
||||||
|
select: {
|
||||||
|
firstName: true,
|
||||||
|
lastName: true,
|
||||||
|
email: true,
|
||||||
|
isActive: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async refreshToken(
|
||||||
|
userId: string,
|
||||||
|
refreshToken: string,
|
||||||
|
type: string,
|
||||||
|
sessionId: string,
|
||||||
|
) {
|
||||||
|
const user = await this.userRepository.findOne({ where: { uuid: userId } });
|
||||||
|
if (!user || !user.refreshToken)
|
||||||
|
throw new ForbiddenException('Access Denied');
|
||||||
|
const refreshTokenMatches = await argon2.verify(
|
||||||
|
user.refreshToken,
|
||||||
|
refreshToken,
|
||||||
|
);
|
||||||
|
if (!refreshTokenMatches) throw new ForbiddenException('Access Denied');
|
||||||
|
const tokens = await this.authService.getTokens({
|
||||||
|
email: user.email,
|
||||||
|
userId: user.uuid,
|
||||||
|
uuid: user.uuid,
|
||||||
|
type,
|
||||||
|
sessionId,
|
||||||
|
});
|
||||||
|
await this.authService.updateRefreshToken(user.uuid, tokens.refreshToken);
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import AuthConfig from './auth.config';
|
import AuthConfig from './auth.config';
|
||||||
import AppConfig from './app.config';
|
import AppConfig from './app.config';
|
||||||
|
import JwtConfig from './jwt.config';
|
||||||
export default [AuthConfig, AppConfig];
|
export default [AuthConfig, AppConfig, JwtConfig];
|
||||||
|
|||||||
0
src/user-device-permission/controllers/index.ts
Normal file
0
src/user-device-permission/controllers/index.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import {
|
||||||
|
Body,
|
||||||
|
Controller,
|
||||||
|
HttpStatus,
|
||||||
|
Param,
|
||||||
|
Post,
|
||||||
|
Put,
|
||||||
|
UseGuards,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
||||||
|
import { UserDevicePermissionService } from '../services/user-device-permission.service';
|
||||||
|
import { UserDevicePermissionAddDto } from '../dtos/user-device-permission.add.dto';
|
||||||
|
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||||
|
import { UserDevicePermissionEditDto } from '../dtos/user-device-permission.edit.dto';
|
||||||
|
|
||||||
|
@ApiTags('Device Permission Module')
|
||||||
|
@Controller({
|
||||||
|
version: '1',
|
||||||
|
path: 'device-permission',
|
||||||
|
})
|
||||||
|
export class UserDevicePermissionController {
|
||||||
|
constructor(
|
||||||
|
private readonly userDevicePermissionService: UserDevicePermissionService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
|
@Post('add')
|
||||||
|
async addDevicePermission(
|
||||||
|
@Body() userDevicePermissionDto: UserDevicePermissionAddDto,
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const addDetails =
|
||||||
|
await this.userDevicePermissionService.addUserPermission(
|
||||||
|
userDevicePermissionDto,
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
statusCode: HttpStatus.CREATED,
|
||||||
|
message: 'User Permission for Devices Added Successfully',
|
||||||
|
data: addDetails,
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
|
@Put('edit/:userId')
|
||||||
|
async editDevicePermission(
|
||||||
|
@Param('userId') userId: string,
|
||||||
|
@Body() userDevicePermissionEditDto: UserDevicePermissionEditDto,
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
await this.userDevicePermissionService.editUserPermission(
|
||||||
|
userId,
|
||||||
|
userDevicePermissionEditDto,
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
statusCode: HttpStatus.OK,
|
||||||
|
message: 'User Permission for Devices Updated Successfully',
|
||||||
|
data: {},
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
0
src/user-device-permission/dtos/index.ts
Normal file
0
src/user-device-permission/dtos/index.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsNotEmpty, IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class UserDevicePermissionAddDto {
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'user id',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
userId: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'permission type id',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
permissionTypeId: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'device id',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
deviceId: string;
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
import { OmitType } from '@nestjs/swagger';
|
||||||
|
import { UserDevicePermissionAddDto } from './user-device-permission.add.dto';
|
||||||
|
|
||||||
|
export class UserDevicePermissionEditDto extends OmitType(
|
||||||
|
UserDevicePermissionAddDto,
|
||||||
|
['userId'],
|
||||||
|
) {}
|
||||||
0
src/user-device-permission/services/index.ts
Normal file
0
src/user-device-permission/services/index.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { DeviceUserTypeRepository } from '@app/common/modules/device/repositories';
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { UserDevicePermissionAddDto } from '../dtos/user-device-permission.add.dto';
|
||||||
|
import { UserDevicePermissionEditDto } from '../dtos/user-device-permission.edit.dto';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UserDevicePermissionService {
|
||||||
|
constructor(
|
||||||
|
private readonly deviceUserTypeRepository: DeviceUserTypeRepository,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async addUserPermission(userDevicePermissionDto: UserDevicePermissionAddDto) {
|
||||||
|
return await this.deviceUserTypeRepository.save({
|
||||||
|
userUuid: userDevicePermissionDto.userId,
|
||||||
|
deviceUuid: userDevicePermissionDto.deviceId,
|
||||||
|
permissionTypeUuid: userDevicePermissionDto.permissionTypeId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async editUserPermission(
|
||||||
|
userId: string,
|
||||||
|
userDevicePermissionEditDto: UserDevicePermissionEditDto,
|
||||||
|
) {
|
||||||
|
return await this.deviceUserTypeRepository.update(
|
||||||
|
{ userUuid: userId },
|
||||||
|
{
|
||||||
|
deviceUuid: userDevicePermissionEditDto.deviceId,
|
||||||
|
permissionTypeUuid: userDevicePermissionEditDto.permissionTypeId,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/user-device-permission/user-device-permission.module.ts
Normal file
21
src/user-device-permission/user-device-permission.module.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { DeviceRepositoryModule } from '@app/common/modules/device';
|
||||||
|
import {
|
||||||
|
DeviceRepository,
|
||||||
|
DeviceUserTypeRepository,
|
||||||
|
} from '@app/common/modules/device/repositories';
|
||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { ConfigModule } from '@nestjs/config';
|
||||||
|
import { UserDevicePermissionService } from './services/user-device-permission.service';
|
||||||
|
import { UserDevicePermissionController } from './controllers/user-device-permission.controller';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [ConfigModule, DeviceRepositoryModule],
|
||||||
|
controllers: [UserDevicePermissionController],
|
||||||
|
providers: [
|
||||||
|
DeviceUserTypeRepository,
|
||||||
|
DeviceRepository,
|
||||||
|
UserDevicePermissionService,
|
||||||
|
],
|
||||||
|
exports: [UserDevicePermissionService],
|
||||||
|
})
|
||||||
|
export class UserDevicePermissionModule {}
|
||||||
Reference in New Issue
Block a user