mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-11-27 04:04:55 +00:00
Merge branch 'dev'
This commit is contained in:
@ -90,3 +90,6 @@ FIREBASE_DATABASE_URL=
|
||||
|
||||
OTP_LIMITER=
|
||||
|
||||
GOOGLE_CLIENT_ID=
|
||||
|
||||
GOOGLE_CLIENT_SECRET=
|
||||
@ -1,4 +1,8 @@
|
||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||
import {
|
||||
BadRequestException,
|
||||
Injectable,
|
||||
UnauthorizedException,
|
||||
} from '@nestjs/common';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import * as argon2 from 'argon2';
|
||||
import { HelperHashService } from '../../helper/services';
|
||||
@ -6,16 +10,20 @@ import { UserRepository } from '../../../../common/src/modules/user/repositories
|
||||
import { UserSessionRepository } from '../../../../common/src/modules/session/repositories/session.repository';
|
||||
import { UserSessionEntity } from '../../../../common/src/modules/session/entities';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { OAuth2Client } from 'google-auth-library';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
private client: OAuth2Client;
|
||||
constructor(
|
||||
private jwtService: JwtService,
|
||||
private readonly userRepository: UserRepository,
|
||||
private readonly sessionRepository: UserSessionRepository,
|
||||
private readonly helperHashService: HelperHashService,
|
||||
private readonly configService: ConfigService,
|
||||
) {}
|
||||
) {
|
||||
this.client = new OAuth2Client(this.configService.get('GOOGLE_CLIENT_ID'));
|
||||
}
|
||||
|
||||
async validateUser(
|
||||
email: string,
|
||||
@ -80,8 +88,17 @@ export class AuthService {
|
||||
type: user.type,
|
||||
sessionId: user.sessionId,
|
||||
roles: user?.roles,
|
||||
googleCode: user.googleCode,
|
||||
};
|
||||
|
||||
if (payload.googleCode) {
|
||||
const profile = await this.getProfile(payload.googleCode);
|
||||
user = await this.userRepository.findOne({
|
||||
where: { email: profile.email },
|
||||
});
|
||||
if (!user) {
|
||||
return { profile };
|
||||
}
|
||||
}
|
||||
const tokens = await this.getTokens(payload);
|
||||
await this.updateRefreshToken(user.uuid, tokens.refreshToken);
|
||||
return tokens;
|
||||
@ -100,4 +117,19 @@ export class AuthService {
|
||||
hashData(data: string) {
|
||||
return argon2.hash(data);
|
||||
}
|
||||
|
||||
async getProfile(googleCode: string) {
|
||||
try {
|
||||
const ticket = await this.client.verifyIdToken({
|
||||
idToken: googleCode,
|
||||
audience: this.configService.get('GOOGLE_CLIENT_ID'),
|
||||
});
|
||||
const payload = ticket.getPayload();
|
||||
return {
|
||||
...payload,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new UnauthorizedException('Google login failed');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,10 +6,16 @@ import { AuthModule } from './auth/auth.module';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import config from './config';
|
||||
import { EmailService } from './util/email.service';
|
||||
|
||||
import { ErrorMessageService } from 'src/error-message/error-message.service';
|
||||
@Module({
|
||||
providers: [CommonService, EmailService],
|
||||
exports: [CommonService, HelperModule, AuthModule, EmailService],
|
||||
providers: [CommonService, EmailService, ErrorMessageService],
|
||||
exports: [
|
||||
CommonService,
|
||||
HelperModule,
|
||||
AuthModule,
|
||||
EmailService,
|
||||
ErrorMessageService,
|
||||
],
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
load: config,
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
import { BooleanValues } from '../constants/boolean-values.enum';
|
||||
|
||||
export default registerAs(
|
||||
'email-config',
|
||||
(): Record<string, any> => ({
|
||||
SMTP_HOST: process.env.SMTP_HOST,
|
||||
SMTP_PORT: parseInt(process.env.SMTP_PORT),
|
||||
SMTP_SECURE: process.env.SMTP_SECURE === 'true',
|
||||
SMTP_SECURE: process.env.SMTP_SECURE === BooleanValues.TRUE,
|
||||
SMTP_USER: process.env.SMTP_USER,
|
||||
SMTP_SENDER: process.env.SMTP_SENDER,
|
||||
SMTP_PASSWORD: process.env.SMTP_PASSWORD,
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
import { BooleanValues } from '../constants/boolean-values.enum';
|
||||
|
||||
export default registerAs(
|
||||
'tuya-config',
|
||||
@ -7,6 +8,6 @@ export default registerAs(
|
||||
TUYA_ACCESS_KEY: process.env.TUYA_ACCESS_KEY,
|
||||
TUYA_EU_URL: process.env.TUYA_EU_URL,
|
||||
TRUN_ON_TUYA_SOCKET:
|
||||
process.env.TRUN_ON_TUYA_SOCKET === 'true' ? true : false,
|
||||
process.env.TRUN_ON_TUYA_SOCKET === BooleanValues.TRUE ? true : false,
|
||||
}),
|
||||
);
|
||||
|
||||
9
libs/common/src/constants/automation.enum.ts
Normal file
9
libs/common/src/constants/automation.enum.ts
Normal file
@ -0,0 +1,9 @@
|
||||
// automation.enum.ts
|
||||
export enum ActionExecutorEnum {
|
||||
DEVICE_ISSUE = 'device_issue',
|
||||
DELAY = 'delay',
|
||||
}
|
||||
|
||||
export enum EntityTypeEnum {
|
||||
DEVICE_REPORT = 'device_report',
|
||||
}
|
||||
4
libs/common/src/constants/battery-status.enum.ts
Normal file
4
libs/common/src/constants/battery-status.enum.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export enum BatteryStatus {
|
||||
RESIDUAL_ELECTRICITY = 'residual_electricity',
|
||||
BATTERY_PERCENTAGE = 'battery_percentage',
|
||||
}
|
||||
4
libs/common/src/constants/boolean-values.enum.ts
Normal file
4
libs/common/src/constants/boolean-values.enum.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export enum BooleanValues {
|
||||
TRUE = 'true',
|
||||
FALSE = 'false',
|
||||
}
|
||||
11
libs/common/src/constants/controller-route.ts
Normal file
11
libs/common/src/constants/controller-route.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export class ControllerRoute {
|
||||
static REGION = class {
|
||||
public static readonly ROUTE = 'region';
|
||||
static ACTIONS = class {
|
||||
public static readonly GET_REGIONS_SUMMARY = 'Get list of all regions';
|
||||
|
||||
public static readonly GET_REGIONS_DESCRIPTION =
|
||||
'Retrieve the list of all regions registered in Syncrow.';
|
||||
};
|
||||
};
|
||||
}
|
||||
14
libs/common/src/constants/days.enum.ts
Normal file
14
libs/common/src/constants/days.enum.ts
Normal file
@ -0,0 +1,14 @@
|
||||
export enum DaysEnum {
|
||||
SUN = 'Sun',
|
||||
MON = 'Mon',
|
||||
TUE = 'Tue',
|
||||
WED = 'Wed',
|
||||
THU = 'Thu',
|
||||
FRI = 'Fri',
|
||||
SAT = 'Sat',
|
||||
}
|
||||
|
||||
export enum EnableDisableStatusEnum {
|
||||
DISABLED = '0',
|
||||
ENABLED = '1',
|
||||
}
|
||||
4
libs/common/src/constants/device-status.enum.ts
Normal file
4
libs/common/src/constants/device-status.enum.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export enum DeviceStatuses {
|
||||
REJECTED = 'rejected',
|
||||
FULLFILLED = 'fulfilled',
|
||||
}
|
||||
3
libs/common/src/constants/error-codes.enum.ts
Normal file
3
libs/common/src/constants/error-codes.enum.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export enum CommonErrorCodes {
|
||||
DUPLICATE_ENTITY = '23505',
|
||||
}
|
||||
99
libs/common/src/constants/hours-minutes.enum.ts
Normal file
99
libs/common/src/constants/hours-minutes.enum.ts
Normal file
@ -0,0 +1,99 @@
|
||||
export enum CommonHours {
|
||||
ONE = '01:00',
|
||||
ONE_THIRTY = '01:30',
|
||||
TWO = '02:00',
|
||||
TWO_THIRTY = '02:30',
|
||||
THREE = '03:00',
|
||||
THREE_THIRTY = '03:30',
|
||||
FOUR = '04:00',
|
||||
FOUR_THIRTY = '04:30',
|
||||
FIVE = '05:00',
|
||||
FIVE_THIRTY = '05:30',
|
||||
SIX = '06:00',
|
||||
SIX_THIRTY = '06:30',
|
||||
SEVEN = '07:00',
|
||||
SEVEN_THIRTY = '07:30',
|
||||
EIGHT = '08:00',
|
||||
EIGHT_THIRTY = '08:30',
|
||||
NINE = '09:00',
|
||||
NINE_THIRTY = '09:30',
|
||||
TEN = '10:00',
|
||||
TEN_THIRTY = '10:30',
|
||||
ELEVEN = '11:00',
|
||||
ELEVEN_THIRTY = '11:30',
|
||||
TWELVE = '12:00',
|
||||
TWELVE_THIRTY = '12:30',
|
||||
THIRTEEN = '13:00',
|
||||
THIRTEEN_THIRTY = '13:30',
|
||||
FOURTEEN = '14:00',
|
||||
FOURTEEN_THIRTY = '14:30',
|
||||
FIFTEEN = '15:00',
|
||||
FIFTEEN_THIRTY = '15:30',
|
||||
SIXTEEN = '16:00',
|
||||
SIXTEEN_THIRTY = '16:30',
|
||||
SEVENTEEN = '17:00',
|
||||
SEVENTEEN_THIRTY = '17:30',
|
||||
EIGHTEEN = '18:00',
|
||||
EIGHTEEN_THIRTY = '18:30',
|
||||
NINETEEN = '19:00',
|
||||
NINETEEN_THIRTY = '19:30',
|
||||
TWENTY = '20:00',
|
||||
TWENTY_THIRTY = '20:30',
|
||||
TWENTY_ONE = '21:00',
|
||||
TWENTY_ONE_THIRTY = '21:30',
|
||||
TWENTY_TWO = '22:00',
|
||||
TWENTY_TWO_THIRTY = '22:30',
|
||||
TWENTY_THREE = '23:00',
|
||||
TWENTY_THREE_THIRTY = '23:30',
|
||||
TWENTY_FOUR = '24:00',
|
||||
}
|
||||
|
||||
export enum CommonHourMinutes {
|
||||
ONE = 60,
|
||||
ONE_THIRTY = 90,
|
||||
TWO = 120,
|
||||
TWO_THIRTY = 150,
|
||||
THREE = 180,
|
||||
THREE_THIRTY = 210,
|
||||
FOUR = 240,
|
||||
FOUR_THIRTY = 270,
|
||||
FIVE = 300,
|
||||
FIVE_THIRTY = 330,
|
||||
SIX = 360,
|
||||
SIX_THIRTY = 390,
|
||||
SEVEN = 420,
|
||||
SEVEN_THIRTY = 450,
|
||||
EIGHT = 480,
|
||||
EIGHT_THIRTY = 510,
|
||||
NINE = 540,
|
||||
NINE_THIRTY = 570,
|
||||
TEN = 600,
|
||||
TEN_THIRTY = 630,
|
||||
ELEVEN = 660,
|
||||
ELEVEN_THIRTY = 690,
|
||||
TWELVE = 720,
|
||||
TWELVE_THIRTY = 750,
|
||||
THIRTEEN = 780,
|
||||
THIRTEEN_THIRTY = 810,
|
||||
FOURTEEN = 840,
|
||||
FOURTEEN_THIRTY = 870,
|
||||
FIFTEEN = 900,
|
||||
FIFTEEN_THIRTY = 930,
|
||||
SIXTEEN = 960,
|
||||
SIXTEEN_THIRTY = 990,
|
||||
SEVENTEEN = 1020,
|
||||
SEVENTEEN_THIRTY = 1050,
|
||||
EIGHTEEN = 1080,
|
||||
EIGHTEEN_THIRTY = 1110,
|
||||
NINETEEN = 1140,
|
||||
NINETEEN_THIRTY = 1170,
|
||||
TWENTY = 1200,
|
||||
TWENTY_THIRTY = 1230,
|
||||
TWENTY_ONE = 1260,
|
||||
TWENTY_ONE_THIRTY = 1290,
|
||||
TWENTY_TWO = 1320,
|
||||
TWENTY_TWO_THIRTY = 1350,
|
||||
TWENTY_THREE = 1380,
|
||||
TWENTY_THREE_THIRTY = 1410,
|
||||
TWENTY_FOUR = 1440,
|
||||
}
|
||||
4
libs/common/src/constants/password-type.enum.ts
Normal file
4
libs/common/src/constants/password-type.enum.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export enum PasswordType {
|
||||
SINGLE = 'single',
|
||||
MULTIPLE = 'multiple',
|
||||
}
|
||||
@ -4,5 +4,15 @@ export enum ProductType {
|
||||
CPS = 'CPS',
|
||||
DL = 'DL',
|
||||
WPS = 'WPS',
|
||||
TH_G = '3G',
|
||||
THREE_G = '3G',
|
||||
TWO_G = '2G',
|
||||
ONE_G = '1G',
|
||||
WH = 'WH',
|
||||
DS = 'DS',
|
||||
THREE_3TG = '3GT',
|
||||
TWO_2TG = '2GT',
|
||||
ONE_1TG = '1GT',
|
||||
WL = 'WL',
|
||||
GD = 'GD',
|
||||
CUR = 'CUR',
|
||||
}
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
import { DaysEnum } from './days.enum';
|
||||
|
||||
export enum WorkingDays {
|
||||
Sun = 'Sun',
|
||||
Mon = 'Mon',
|
||||
Tue = 'Tue',
|
||||
Wed = 'Wed',
|
||||
Thu = 'Thu',
|
||||
Fri = 'Fri',
|
||||
Sat = 'Sat',
|
||||
Sun = DaysEnum.SUN,
|
||||
Mon = DaysEnum.MON,
|
||||
Tue = DaysEnum.TUE,
|
||||
Wed = DaysEnum.WED,
|
||||
Thu = DaysEnum.THU,
|
||||
Fri = DaysEnum.FRI,
|
||||
Sat = DaysEnum.SAT,
|
||||
}
|
||||
|
||||
@ -2,10 +2,11 @@ import { Controller, Post, Param } from '@nestjs/common';
|
||||
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
||||
import { AddDeviceStatusDto } from '../dtos/add.devices-status.dto';
|
||||
import { DeviceStatusFirebaseService } from '../services/devices-status.service';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
|
||||
@ApiTags('Device Status Firebase Module')
|
||||
@Controller({
|
||||
version: '1',
|
||||
version: EnableDisableStatusEnum.ENABLED,
|
||||
path: 'device-status-firebase',
|
||||
})
|
||||
export class DeviceStatusFirebaseController {
|
||||
|
||||
@ -85,6 +85,7 @@ export class DeviceStatusFirebaseService {
|
||||
return await this.deviceRepository.findOne({
|
||||
where: {
|
||||
deviceTuyaUuid,
|
||||
isActive: true,
|
||||
},
|
||||
relations: ['productDevice'],
|
||||
});
|
||||
@ -139,6 +140,7 @@ export class DeviceStatusFirebaseService {
|
||||
return await this.deviceRepository.findOne({
|
||||
where: {
|
||||
uuid: deviceUuid,
|
||||
isActive: true,
|
||||
},
|
||||
...(withProductDevice && { relations: ['productDevice'] }),
|
||||
});
|
||||
|
||||
37
libs/common/src/helper/convertTimestampToDubaiTime.ts
Normal file
37
libs/common/src/helper/convertTimestampToDubaiTime.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { EnableDisableStatusEnum } from '../constants/days.enum';
|
||||
|
||||
export function convertTimestampToDubaiTime(timestamp) {
|
||||
// Convert timestamp to milliseconds
|
||||
const date = new Date(timestamp * 1000);
|
||||
|
||||
// Convert to Dubai time (UTC+3)
|
||||
const dubaiTimeOffset = 3 * 60; // 3 hours in minutes
|
||||
const dubaiTime = new Date(date.getTime() + dubaiTimeOffset * 60 * 1000);
|
||||
|
||||
// Format the date as YYYYMMDD
|
||||
const year = dubaiTime.getUTCFullYear();
|
||||
const month = String(dubaiTime.getUTCMonth() + 1).padStart(
|
||||
2,
|
||||
EnableDisableStatusEnum.DISABLED,
|
||||
); // Months are zero-based
|
||||
const day = String(dubaiTime.getUTCDate()).padStart(
|
||||
2,
|
||||
EnableDisableStatusEnum.DISABLED,
|
||||
);
|
||||
|
||||
// Format the time as HH:MM (24-hour format)
|
||||
const hours = String(dubaiTime.getUTCHours()).padStart(
|
||||
2,
|
||||
EnableDisableStatusEnum.DISABLED,
|
||||
);
|
||||
const minutes = String(dubaiTime.getUTCMinutes()).padStart(
|
||||
2,
|
||||
EnableDisableStatusEnum.DISABLED,
|
||||
);
|
||||
|
||||
// Return formatted date and time
|
||||
return {
|
||||
date: `${year}${month}${day}`,
|
||||
time: `${hours}:${minutes}`,
|
||||
};
|
||||
}
|
||||
45
libs/common/src/helper/getScheduleStatus.ts
Normal file
45
libs/common/src/helper/getScheduleStatus.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { DaysEnum, EnableDisableStatusEnum } from '../constants/days.enum';
|
||||
|
||||
export function getScheduleStatus(daysEnabled: string[]): string {
|
||||
const daysMap: string[] = [
|
||||
DaysEnum.SUN,
|
||||
DaysEnum.MON,
|
||||
DaysEnum.TUE,
|
||||
DaysEnum.WED,
|
||||
DaysEnum.THU,
|
||||
DaysEnum.FRI,
|
||||
DaysEnum.SAT,
|
||||
];
|
||||
|
||||
const schedule: string[] = Array(7).fill(EnableDisableStatusEnum.DISABLED);
|
||||
|
||||
daysEnabled.forEach((day) => {
|
||||
const index: number = daysMap.indexOf(day);
|
||||
if (index !== -1) {
|
||||
schedule[index] = EnableDisableStatusEnum.ENABLED;
|
||||
}
|
||||
});
|
||||
|
||||
return schedule.join('');
|
||||
}
|
||||
export function getEnabledDays(schedule: string): string[] {
|
||||
const daysMap: string[] = [
|
||||
DaysEnum.SUN,
|
||||
DaysEnum.MON,
|
||||
DaysEnum.TUE,
|
||||
DaysEnum.WED,
|
||||
DaysEnum.THU,
|
||||
DaysEnum.FRI,
|
||||
DaysEnum.SAT,
|
||||
];
|
||||
const enabledDays: string[] = [];
|
||||
|
||||
// Iterate through the schedule string
|
||||
for (let i = 0; i < schedule.length; i++) {
|
||||
if (schedule[i] === EnableDisableStatusEnum.ENABLED) {
|
||||
enabledDays.push(daysMap[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return enabledDays;
|
||||
}
|
||||
@ -18,8 +18,9 @@ export class DeviceEntity extends AbstractEntity<DeviceDto> {
|
||||
@Column({
|
||||
nullable: true,
|
||||
default: true,
|
||||
type: 'boolean',
|
||||
})
|
||||
isActive: true;
|
||||
isActive: boolean;
|
||||
|
||||
@ManyToOne(() => UserEntity, (user) => user.userSpaces, { nullable: false })
|
||||
user: UserEntity;
|
||||
|
||||
346
package-lock.json
generated
346
package-lock.json
generated
@ -20,13 +20,14 @@
|
||||
"@nestjs/websockets": "^10.3.8",
|
||||
"@tuya/tuya-connector-nodejs": "^2.1.2",
|
||||
"argon2": "^0.40.1",
|
||||
"axios": "^1.6.7",
|
||||
"axios": "^1.7.7",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"express-rate-limit": "^7.1.5",
|
||||
"firebase": "^10.12.5",
|
||||
"google-auth-library": "^9.14.1",
|
||||
"helmet": "^7.1.0",
|
||||
"ioredis": "^5.3.2",
|
||||
"morgan": "^1.10.0",
|
||||
@ -2258,6 +2259,8 @@
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.8.tgz",
|
||||
"integrity": "sha512-qKwC/M/nNNaKUBMQ0nuzm47b7ZYWQHN3pcXq4IIcoSBc2hOIrflAxJduIvvqmhoz3gR2TacTAs8vlsCVPkiEdQ==",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"sparse-bitfield": "^3.0.3"
|
||||
}
|
||||
@ -2490,17 +2493,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@nestjs/mongoose": {
|
||||
"version": "10.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/mongoose/-/mongoose-10.0.10.tgz",
|
||||
"integrity": "sha512-3Ff60ock8nwlAJC823TG91Qy+Qc6av+ddIb6n6wlFsTK0akDF/aTcagX8cF8uI8mWxCWjEwEsgv99vo6p0yJ+w==",
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0",
|
||||
"@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0",
|
||||
"mongoose": "^6.0.2 || ^7.0.0 || ^8.0.0",
|
||||
"rxjs": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nestjs/passport": {
|
||||
"version": "10.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-10.0.3.tgz",
|
||||
@ -3138,7 +3130,9 @@
|
||||
"node_modules/@types/webidl-conversions": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
|
||||
"integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA=="
|
||||
"integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==",
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@types/whatwg-url": {
|
||||
"version": "8.2.2",
|
||||
@ -3571,6 +3565,18 @@
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
|
||||
"integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/ajv": {
|
||||
"version": "8.12.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
||||
@ -3791,11 +3797,12 @@
|
||||
"integrity": "sha512-3AungXC4I8kKsS9PuS4JH2nc+0bVY/mjgrephHTIi8fpEeGsTHBUJeosp0Wc1myYMElmD0B3Oc4XL/HVJ4PV2g=="
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.6.7",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz",
|
||||
"integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==",
|
||||
"version": "1.7.7",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
|
||||
"integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.4",
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
@ -3969,6 +3976,15 @@
|
||||
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
|
||||
"integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ=="
|
||||
},
|
||||
"node_modules/bignumber.js": {
|
||||
"version": "9.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz",
|
||||
"integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
@ -4131,14 +4147,6 @@
|
||||
"node-int64": "^0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bson": {
|
||||
"version": "6.8.0",
|
||||
"resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz",
|
||||
"integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==",
|
||||
"engines": {
|
||||
"node": ">=16.20.1"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
@ -5902,15 +5910,16 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.5",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
|
||||
"integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
|
||||
"version": "1.15.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
@ -6071,6 +6080,35 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/gaxios": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz",
|
||||
"integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"extend": "^3.0.2",
|
||||
"https-proxy-agent": "^7.0.1",
|
||||
"is-stream": "^2.0.0",
|
||||
"node-fetch": "^2.6.9",
|
||||
"uuid": "^9.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/gcp-metadata": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz",
|
||||
"integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"gaxios": "^6.0.0",
|
||||
"json-bigint": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/gensync": {
|
||||
"version": "1.0.0-beta.2",
|
||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||
@ -6209,6 +6247,44 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/google-auth-library": {
|
||||
"version": "9.14.1",
|
||||
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.14.1.tgz",
|
||||
"integrity": "sha512-Rj+PMjoNFGFTmtItH7gHfbHpGVSb3vmnGK3nwNBqxQF9NoBpttSZI/rc0WiM63ma2uGDQtYEkMHkK9U6937NiA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.0",
|
||||
"ecdsa-sig-formatter": "^1.0.11",
|
||||
"gaxios": "^6.1.1",
|
||||
"gcp-metadata": "^6.1.0",
|
||||
"gtoken": "^7.0.0",
|
||||
"jws": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/google-auth-library/node_modules/jwa": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
|
||||
"integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-equal-constant-time": "1.0.1",
|
||||
"ecdsa-sig-formatter": "1.0.11",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/google-auth-library/node_modules/jws": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
|
||||
"integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jwa": "^2.0.0",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
||||
@ -6232,6 +6308,40 @@
|
||||
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/gtoken": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz",
|
||||
"integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"gaxios": "^6.0.0",
|
||||
"jws": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/gtoken/node_modules/jwa": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
|
||||
"integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-equal-constant-time": "1.0.1",
|
||||
"ecdsa-sig-formatter": "1.0.11",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/gtoken/node_modules/jws": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
|
||||
"integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jwa": "^2.0.0",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/har-schema": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
||||
@ -6399,6 +6509,19 @@
|
||||
"npm": ">=1.3.7"
|
||||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "7.0.5",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz",
|
||||
"integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "^7.0.2",
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/human-signals": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
|
||||
@ -6704,7 +6827,6 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
|
||||
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
@ -7548,6 +7670,15 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/json-bigint": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
|
||||
"integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bignumber.js": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/json-buffer": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
||||
@ -7666,14 +7797,6 @@
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/kareem": {
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz",
|
||||
"integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/keyv": {
|
||||
"version": "4.5.4",
|
||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||
@ -7911,7 +8034,9 @@
|
||||
"node_modules/memory-pager": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
|
||||
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg=="
|
||||
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/merge-descriptors": {
|
||||
"version": "1.0.1",
|
||||
@ -8146,125 +8271,6 @@
|
||||
"node": ">=14.20.1"
|
||||
}
|
||||
},
|
||||
"node_modules/mongoose": {
|
||||
"version": "8.5.1",
|
||||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.5.1.tgz",
|
||||
"integrity": "sha512-OhVcwVl91A1G6+XpjDcpkGP7l7ikZkxa0DylX7NT/lcEqAjggzSdqDxb48A+xsDxqNAr0ntSJ1yiE3+KJTOd5Q==",
|
||||
"dependencies": {
|
||||
"bson": "^6.7.0",
|
||||
"kareem": "2.6.3",
|
||||
"mongodb": "6.7.0",
|
||||
"mpath": "0.9.0",
|
||||
"mquery": "5.0.0",
|
||||
"ms": "2.1.3",
|
||||
"sift": "17.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.20.1"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/mongoose"
|
||||
}
|
||||
},
|
||||
"node_modules/mongoose/node_modules/@types/whatwg-url": {
|
||||
"version": "11.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz",
|
||||
"integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==",
|
||||
"dependencies": {
|
||||
"@types/webidl-conversions": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/mongoose/node_modules/mongodb": {
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.7.0.tgz",
|
||||
"integrity": "sha512-TMKyHdtMcO0fYBNORiYdmM25ijsHs+Njs963r4Tro4OQZzqYigAzYQouwWRg4OIaiLRUEGUh/1UAcH5lxdSLIA==",
|
||||
"dependencies": {
|
||||
"@mongodb-js/saslprep": "^1.1.5",
|
||||
"bson": "^6.7.0",
|
||||
"mongodb-connection-string-url": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.20.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@aws-sdk/credential-providers": "^3.188.0",
|
||||
"@mongodb-js/zstd": "^1.1.0",
|
||||
"gcp-metadata": "^5.2.0",
|
||||
"kerberos": "^2.0.1",
|
||||
"mongodb-client-encryption": ">=6.0.0 <7",
|
||||
"snappy": "^7.2.2",
|
||||
"socks": "^2.7.1"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@aws-sdk/credential-providers": {
|
||||
"optional": true
|
||||
},
|
||||
"@mongodb-js/zstd": {
|
||||
"optional": true
|
||||
},
|
||||
"gcp-metadata": {
|
||||
"optional": true
|
||||
},
|
||||
"kerberos": {
|
||||
"optional": true
|
||||
},
|
||||
"mongodb-client-encryption": {
|
||||
"optional": true
|
||||
},
|
||||
"snappy": {
|
||||
"optional": true
|
||||
},
|
||||
"socks": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/mongoose/node_modules/mongodb-connection-string-url": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz",
|
||||
"integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==",
|
||||
"dependencies": {
|
||||
"@types/whatwg-url": "^11.0.2",
|
||||
"whatwg-url": "^13.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mongoose/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
},
|
||||
"node_modules/mongoose/node_modules/tr46": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz",
|
||||
"integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==",
|
||||
"dependencies": {
|
||||
"punycode": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/mongoose/node_modules/webidl-conversions": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
||||
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/mongoose/node_modules/whatwg-url": {
|
||||
"version": "13.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz",
|
||||
"integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==",
|
||||
"dependencies": {
|
||||
"tr46": "^4.1.1",
|
||||
"webidl-conversions": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/morgan": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz",
|
||||
@ -8304,25 +8310,6 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/mpath": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
|
||||
"integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==",
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mquery": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz",
|
||||
"integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==",
|
||||
"dependencies": {
|
||||
"debug": "4.x"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
@ -9956,11 +9943,6 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/sift": {
|
||||
"version": "17.1.3",
|
||||
"resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz",
|
||||
"integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ=="
|
||||
},
|
||||
"node_modules/signal-exit": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
||||
@ -10045,6 +10027,8 @@
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
|
||||
"integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"memory-pager": "^1.0.2"
|
||||
}
|
||||
|
||||
@ -31,13 +31,14 @@
|
||||
"@nestjs/websockets": "^10.3.8",
|
||||
"@tuya/tuya-connector-nodejs": "^2.1.2",
|
||||
"argon2": "^0.40.1",
|
||||
"axios": "^1.6.7",
|
||||
"axios": "^1.7.7",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"express-rate-limit": "^7.1.5",
|
||||
"firebase": "^10.12.5",
|
||||
"google-auth-library": "^9.14.1",
|
||||
"helmet": "^7.1.0",
|
||||
"ioredis": "^5.3.2",
|
||||
"morgan": "^1.10.0",
|
||||
|
||||
@ -2,7 +2,6 @@ import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import config from './config';
|
||||
import { AuthenticationModule } from './auth/auth.module';
|
||||
import { AuthenticationController } from './auth/controllers/authentication.controller';
|
||||
import { UserModule } from './users/user.module';
|
||||
import { RoomModule } from './room/room.module';
|
||||
import { GroupModule } from './group/group.module';
|
||||
@ -24,6 +23,7 @@ import { AutomationModule } from './automation/automation.module';
|
||||
import { RegionModule } from './region/region.module';
|
||||
import { TimeZoneModule } from './timezone/timezone.module';
|
||||
import { VisitorPasswordModule } from './vistor-password/visitor-password.module';
|
||||
import { ScheduleModule } from './schedule/schedule.module';
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
@ -50,8 +50,8 @@ import { VisitorPasswordModule } from './vistor-password/visitor-password.module
|
||||
RegionModule,
|
||||
TimeZoneModule,
|
||||
VisitorPasswordModule,
|
||||
ScheduleModule,
|
||||
],
|
||||
controllers: [AuthenticationController],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AuthenticationController } from './controllers/authentication.controller';
|
||||
import { AuthenticationService } from './services/authentication.service';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { UserRepositoryModule } from '@app/common/modules/user/user.repository.module';
|
||||
import { CommonModule } from '../../libs/common/src';
|
||||
@ -16,9 +14,8 @@ import { RoleTypeRepository } from '@app/common/modules/role-type/repositories';
|
||||
|
||||
@Module({
|
||||
imports: [ConfigModule, UserRepositoryModule, CommonModule],
|
||||
controllers: [AuthenticationController, UserAuthController],
|
||||
controllers: [UserAuthController],
|
||||
providers: [
|
||||
AuthenticationService,
|
||||
UserAuthService,
|
||||
UserRepository,
|
||||
UserSessionRepository,
|
||||
@ -26,6 +23,6 @@ import { RoleTypeRepository } from '@app/common/modules/role-type/repositories';
|
||||
UserRoleRepository,
|
||||
RoleTypeRepository,
|
||||
],
|
||||
exports: [AuthenticationService, UserAuthService],
|
||||
exports: [UserAuthService],
|
||||
})
|
||||
export class AuthenticationModule {}
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
import { Controller, Post } from '@nestjs/common';
|
||||
import { AuthenticationService } from '../services/authentication.service';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
|
||||
@Controller({
|
||||
version: '1',
|
||||
path: 'authentication',
|
||||
})
|
||||
@ApiTags('Tuya Auth')
|
||||
export class AuthenticationController {
|
||||
constructor(private readonly authenticationService: AuthenticationService) {}
|
||||
@Post('auth2')
|
||||
async Authentication() {
|
||||
return await this.authenticationService.main();
|
||||
}
|
||||
}
|
||||
@ -1,2 +1 @@
|
||||
export * from './authentication.controller';
|
||||
export * from './user-auth.controller';
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Post,
|
||||
Req,
|
||||
UseGuards,
|
||||
@ -17,9 +15,10 @@ import { UserLoginDto } from '../dtos/user-login.dto';
|
||||
import { ForgetPasswordDto, UserOtpDto, VerifyOtpDto } from '../dtos';
|
||||
import { RefreshTokenGuard } from '@app/common/guards/jwt-refresh.auth.guard';
|
||||
import { SuperAdminRoleGuard } from 'src/guards/super.admin.role.guard';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
|
||||
@Controller({
|
||||
version: '1',
|
||||
version: EnableDisableStatusEnum.ENABLED,
|
||||
path: 'authentication',
|
||||
})
|
||||
@ApiTags('Auth')
|
||||
@ -51,20 +50,6 @@ export class UserAuthController {
|
||||
};
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(SuperAdminRoleGuard)
|
||||
@Delete('user/delete/:id')
|
||||
async userDelete(@Param('id') id: string) {
|
||||
await this.userAuthService.deleteUser(id);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
data: {
|
||||
id,
|
||||
},
|
||||
message: 'User Deleted Successfully',
|
||||
};
|
||||
}
|
||||
|
||||
@Post('user/send-otp')
|
||||
async sendOtp(@Body() otpDto: UserOtpDto) {
|
||||
const otpCode = await this.userAuthService.generateOTP(otpDto);
|
||||
@ -99,7 +84,7 @@ export class UserAuthController {
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(SuperAdminRoleGuard)
|
||||
@Get('user/list')
|
||||
@Get('user')
|
||||
async userList() {
|
||||
const userList = await this.userAuthService.userList();
|
||||
return {
|
||||
|
||||
@ -41,5 +41,5 @@ export class UserSignUpDto {
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
public regionUuid: string;
|
||||
public regionUuid?: string;
|
||||
}
|
||||
|
||||
@ -1,19 +1,23 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||
import { IsEmail, IsOptional, IsString } from 'class-validator';
|
||||
|
||||
export class UserLoginDto {
|
||||
@ApiProperty()
|
||||
@IsEmail()
|
||||
@IsNotEmpty()
|
||||
email: string;
|
||||
@IsOptional()
|
||||
email?: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
password: string;
|
||||
password?: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
regionUuid?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
googleCode?: string;
|
||||
}
|
||||
|
||||
@ -1,120 +0,0 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import * as qs from 'qs';
|
||||
import * as crypto from 'crypto';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import axios from 'axios';
|
||||
@Injectable()
|
||||
export class AuthenticationService {
|
||||
private token: string;
|
||||
private deviceId: string;
|
||||
private accessKey: string;
|
||||
private secretKey: string;
|
||||
|
||||
constructor(private readonly configService: ConfigService) {
|
||||
(this.deviceId = this.configService.get<string>('auth-config.DEVICE_ID')),
|
||||
(this.accessKey = this.configService.get<string>(
|
||||
'auth-config.ACCESS_KEY',
|
||||
)),
|
||||
(this.secretKey = this.configService.get<string>(
|
||||
'auth-config.SECRET_KEY',
|
||||
));
|
||||
}
|
||||
|
||||
async main() {
|
||||
await this.getToken();
|
||||
const data = await this.getDeviceInfo(this.deviceId);
|
||||
console.log('fetch success: ', JSON.stringify(data));
|
||||
return JSON.stringify(data);
|
||||
}
|
||||
|
||||
async getToken() {
|
||||
const method = 'GET';
|
||||
const timestamp = Date.now().toString();
|
||||
const signUrl = 'https://openapi.tuyaeu.com/v1.0/token?grant_type=1';
|
||||
const contentHash = crypto.createHash('sha256').update('').digest('hex');
|
||||
const stringToSign = [method, contentHash, '', signUrl].join('\n');
|
||||
const signStr = this.accessKey + timestamp + stringToSign;
|
||||
|
||||
const headers = {
|
||||
t: timestamp,
|
||||
sign_method: 'HMAC-SHA256',
|
||||
client_id: this.accessKey,
|
||||
sign: await this.encryptStr(signStr, this.secretKey),
|
||||
};
|
||||
|
||||
const { data: login } = await axios.get(
|
||||
'https://openapi.tuyaeu.com/v1.0/token',
|
||||
{
|
||||
params: {
|
||||
grant_type: 1,
|
||||
},
|
||||
headers,
|
||||
},
|
||||
);
|
||||
|
||||
if (!login || !login.success) {
|
||||
throw new Error(`fetch failed: ${login.msg}`);
|
||||
}
|
||||
this.token = login.result.access_token;
|
||||
}
|
||||
|
||||
async getDeviceInfo(deviceId: string) {
|
||||
const query = {};
|
||||
const method = 'POST';
|
||||
const url = `https://openapi.tuyaeu.com/v1.0/devices/${deviceId}/commands`;
|
||||
const reqHeaders: { [k: string]: string } = await this.getRequestSign(
|
||||
url,
|
||||
method,
|
||||
{},
|
||||
query,
|
||||
);
|
||||
|
||||
const { data } = await axios.post(url, {}, reqHeaders);
|
||||
|
||||
if (!data || !data.success) {
|
||||
throw new Error(`request api failed: ${data.msg}`);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async encryptStr(str: string, secret: string): Promise<string> {
|
||||
return crypto
|
||||
.createHmac('sha256', secret)
|
||||
.update(str, 'utf8')
|
||||
.digest('hex')
|
||||
.toUpperCase();
|
||||
}
|
||||
|
||||
async getRequestSign(
|
||||
path: string,
|
||||
method: string,
|
||||
query: { [k: string]: any } = {},
|
||||
body: { [k: string]: any } = {},
|
||||
) {
|
||||
const t = Date.now().toString();
|
||||
const [uri, pathQuery] = path.split('?');
|
||||
const queryMerged = Object.assign(query, qs.parse(pathQuery));
|
||||
const sortedQuery: { [k: string]: string } = {};
|
||||
Object.keys(queryMerged)
|
||||
.sort()
|
||||
.forEach((i) => (sortedQuery[i] = query[i]));
|
||||
|
||||
const querystring = decodeURIComponent(qs.stringify(sortedQuery));
|
||||
const url = querystring ? `${uri}?${querystring}` : uri;
|
||||
const contentHash = crypto
|
||||
.createHash('sha256')
|
||||
.update(JSON.stringify(body))
|
||||
.digest('hex');
|
||||
const stringToSign = [method, contentHash, '', url].join('\n');
|
||||
const signStr = this.accessKey + this.token + t + stringToSign;
|
||||
return {
|
||||
t,
|
||||
path: url,
|
||||
client_id: 'this.accessKey',
|
||||
sign: await this.encryptStr(signStr, this.secretKey),
|
||||
sign_method: 'HMAC-SHA256',
|
||||
access_token: this.token,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1,2 +1 @@
|
||||
export * from './authentication.service';
|
||||
export * from './user-auth.service';
|
||||
|
||||
@ -1,11 +1,8 @@
|
||||
import { RoleTypeRepository } from './../../../libs/common/src/modules/role-type/repositories/role.type.repository';
|
||||
import { UserRoleRepository } from './../../../libs/common/src/modules/user/repositories/user.repository';
|
||||
import { UserRepository } from '../../../libs/common/src/modules/user/repositories';
|
||||
import {
|
||||
BadRequestException,
|
||||
ForbiddenException,
|
||||
Injectable,
|
||||
UnauthorizedException,
|
||||
} from '@nestjs/common';
|
||||
import { UserSignUpDto } from '../dtos/user-auth.dto';
|
||||
import { HelperHashService } from '../../../libs/common/src/helper/services';
|
||||
@ -21,6 +18,7 @@ import * as argon2 from 'argon2';
|
||||
import { differenceInSeconds } from '@app/common/helper/differenceInSeconds';
|
||||
import { LessThan, MoreThan } from 'typeorm';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { UUID } from 'typeorm/driver/mongodb/bson.typings';
|
||||
|
||||
@Injectable()
|
||||
export class UserAuthService {
|
||||
@ -31,8 +29,6 @@ export class UserAuthService {
|
||||
private readonly helperHashService: HelperHashService,
|
||||
private readonly authService: AuthService,
|
||||
private readonly emailService: EmailService,
|
||||
private readonly userRoleRepository: UserRoleRepository,
|
||||
private readonly roleTypeRepository: RoleTypeRepository,
|
||||
private readonly configService: ConfigService,
|
||||
) {}
|
||||
|
||||
@ -93,13 +89,38 @@ export class UserAuthService {
|
||||
|
||||
async userLogin(data: UserLoginDto) {
|
||||
try {
|
||||
const user = await this.authService.validateUser(
|
||||
data.email,
|
||||
data.password,
|
||||
data.regionUuid,
|
||||
);
|
||||
if (!user) {
|
||||
throw new UnauthorizedException('Invalid login credentials.');
|
||||
let user;
|
||||
if (data.googleCode) {
|
||||
const googleUserData = await this.authService.login({
|
||||
googleCode: data.googleCode,
|
||||
});
|
||||
const userExists = await this.userRepository.exists({
|
||||
where: {
|
||||
email: googleUserData['email'],
|
||||
},
|
||||
});
|
||||
user = await this.userRepository.findOne({
|
||||
where: {
|
||||
email: googleUserData['email'],
|
||||
},
|
||||
});
|
||||
if (!userExists) {
|
||||
await this.signUp({
|
||||
email: googleUserData['email'],
|
||||
firstName: googleUserData['given_name'],
|
||||
lastName: googleUserData['family_name'],
|
||||
password: googleUserData['email'],
|
||||
});
|
||||
}
|
||||
data.email = googleUserData['email'];
|
||||
data.password = googleUserData['password'];
|
||||
}
|
||||
if (!data.googleCode) {
|
||||
user = await this.authService.validateUser(
|
||||
data.email,
|
||||
data.password,
|
||||
data.regionUuid,
|
||||
);
|
||||
}
|
||||
const session = await Promise.all([
|
||||
await this.sessionRepository.update(
|
||||
@ -114,7 +135,7 @@ export class UserAuthService {
|
||||
isLoggedOut: false,
|
||||
}),
|
||||
]);
|
||||
return await this.authService.login({
|
||||
const res = await this.authService.login({
|
||||
email: user.email,
|
||||
userId: user.uuid,
|
||||
uuid: user.uuid,
|
||||
@ -123,19 +144,12 @@ export class UserAuthService {
|
||||
}),
|
||||
sessionId: session[1].uuid,
|
||||
});
|
||||
return res;
|
||||
} catch (error) {
|
||||
throw new BadRequestException('Invalid credentials');
|
||||
}
|
||||
}
|
||||
|
||||
async deleteUser(uuid: string) {
|
||||
const user = await this.findOneById(uuid);
|
||||
if (!user) {
|
||||
throw new BadRequestException('User not found');
|
||||
}
|
||||
return await this.userRepository.update({ uuid }, { isActive: false });
|
||||
}
|
||||
|
||||
async findOneById(id: string): Promise<UserEntity> {
|
||||
return await this.userRepository.findOne({ where: { uuid: id } });
|
||||
}
|
||||
@ -225,7 +239,15 @@ export class UserAuthService {
|
||||
});
|
||||
|
||||
if (!otp) {
|
||||
throw new BadRequestException('this email is not registered');
|
||||
const user = await this.userRepository.findOne({
|
||||
where: {
|
||||
email: data.email,
|
||||
},
|
||||
});
|
||||
if (!user) {
|
||||
throw new BadRequestException('this email is not registered');
|
||||
}
|
||||
throw new BadRequestException('You entered wrong otp');
|
||||
}
|
||||
|
||||
if (otp.otpCode !== data.otpCode) {
|
||||
|
||||
@ -4,7 +4,6 @@ import {
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Post,
|
||||
@ -18,10 +17,11 @@ import {
|
||||
UpdateAutomationStatusDto,
|
||||
} from '../dtos/automation.dto';
|
||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
|
||||
@ApiTags('Automation Module')
|
||||
@Controller({
|
||||
version: '1',
|
||||
version: EnableDisableStatusEnum.ENABLED,
|
||||
path: 'automation',
|
||||
})
|
||||
export class AutomationController {
|
||||
@ -31,52 +31,30 @@ export class AutomationController {
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post()
|
||||
async addAutomation(@Body() addAutomationDto: AddAutomationDto) {
|
||||
try {
|
||||
const automation =
|
||||
await this.automationService.addAutomation(addAutomationDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Automation added successfully',
|
||||
data: automation,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const automation =
|
||||
await this.automationService.addAutomation(addAutomationDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Automation added successfully',
|
||||
data: automation,
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get(':unitUuid')
|
||||
async getAutomationByUnit(@Param('unitUuid') unitUuid: string) {
|
||||
try {
|
||||
const automation =
|
||||
await this.automationService.getAutomationByUnit(unitUuid);
|
||||
return automation;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const automation =
|
||||
await this.automationService.getAutomationByUnit(unitUuid);
|
||||
return automation;
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('details/:automationId')
|
||||
async getAutomationDetails(@Param('automationId') automationId: string) {
|
||||
try {
|
||||
const automation =
|
||||
await this.automationService.getAutomationDetails(automationId);
|
||||
return automation;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
``;
|
||||
}
|
||||
const automation =
|
||||
await this.automationService.getAutomationDetails(automationId);
|
||||
return automation;
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ -85,18 +63,11 @@ export class AutomationController {
|
||||
@Param('unitUuid') unitUuid: string,
|
||||
@Param('automationId') automationId: string,
|
||||
) {
|
||||
try {
|
||||
await this.automationService.deleteAutomation(unitUuid, automationId);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'Automation Deleted Successfully',
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
await this.automationService.deleteAutomation(unitUuid, automationId);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'Automation Deleted Successfully',
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ -105,23 +76,16 @@ export class AutomationController {
|
||||
@Body() updateAutomationDto: UpdateAutomationDto,
|
||||
@Param('automationId') automationId: string,
|
||||
) {
|
||||
try {
|
||||
const automation = await this.automationService.updateAutomation(
|
||||
updateAutomationDto,
|
||||
automationId,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Automation updated successfully',
|
||||
data: automation,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const automation = await this.automationService.updateAutomation(
|
||||
updateAutomationDto,
|
||||
automationId,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Automation updated successfully',
|
||||
data: automation,
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ -130,21 +94,14 @@ export class AutomationController {
|
||||
@Body() updateAutomationStatusDto: UpdateAutomationStatusDto,
|
||||
@Param('automationId') automationId: string,
|
||||
) {
|
||||
try {
|
||||
await this.automationService.updateAutomationStatus(
|
||||
updateAutomationStatusDto,
|
||||
automationId,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Automation status updated successfully',
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
await this.automationService.updateAutomationStatus(
|
||||
updateAutomationStatusDto,
|
||||
automationId,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Automation status updated successfully',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,6 +23,11 @@ import {
|
||||
GetAutomationByUnitInterface,
|
||||
} from '../interface/automation.interface';
|
||||
import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter';
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
import {
|
||||
ActionExecutorEnum,
|
||||
EntityTypeEnum,
|
||||
} from '@app/common/constants/automation.enum';
|
||||
|
||||
@Injectable()
|
||||
export class AutomationService {
|
||||
@ -64,7 +69,7 @@ export class AutomationService {
|
||||
);
|
||||
|
||||
for (const action of actions) {
|
||||
if (action.action_executor === 'device_issue') {
|
||||
if (action.action_executor === ActionExecutorEnum.DEVICE_ISSUE) {
|
||||
const device = await this.deviceService.getDeviceByDeviceUuid(
|
||||
action.entity_id,
|
||||
false,
|
||||
@ -76,7 +81,7 @@ export class AutomationService {
|
||||
}
|
||||
|
||||
for (const condition of conditions) {
|
||||
if (condition.entity_type === 'device_report') {
|
||||
if (condition.entity_type === EntityTypeEnum.DEVICE_REPORT) {
|
||||
const device = await this.deviceService.getDeviceByDeviceUuid(
|
||||
condition.entity_id,
|
||||
false,
|
||||
@ -127,12 +132,12 @@ export class AutomationService {
|
||||
where: {
|
||||
uuid: unitUuid,
|
||||
spaceType: {
|
||||
type: 'unit',
|
||||
type: SpaceType.UNIT,
|
||||
},
|
||||
},
|
||||
relations: ['spaceType'],
|
||||
});
|
||||
if (!unit || !unit.spaceType || unit.spaceType.type !== 'unit') {
|
||||
if (!unit || !unit.spaceType || unit.spaceType.type !== SpaceType.UNIT) {
|
||||
throw new BadRequestException('Invalid unit UUID');
|
||||
}
|
||||
return {
|
||||
@ -240,7 +245,7 @@ export class AutomationService {
|
||||
}));
|
||||
|
||||
for (const action of actions) {
|
||||
if (action.actionExecutor === 'device_issue') {
|
||||
if (action.actionExecutor === ActionExecutorEnum.DEVICE_ISSUE) {
|
||||
const device = await this.deviceService.getDeviceByDeviceTuyaUuid(
|
||||
action.entityId,
|
||||
);
|
||||
@ -249,8 +254,8 @@ export class AutomationService {
|
||||
action.entityId = device.uuid;
|
||||
}
|
||||
} else if (
|
||||
action.actionExecutor !== 'device_issue' &&
|
||||
action.actionExecutor !== 'delay'
|
||||
action.actionExecutor !== ActionExecutorEnum.DEVICE_ISSUE &&
|
||||
action.actionExecutor !== ActionExecutorEnum.DELAY
|
||||
) {
|
||||
const sceneDetails = await this.getTapToRunSceneDetailsTuya(
|
||||
action.entityId,
|
||||
@ -268,7 +273,7 @@ export class AutomationService {
|
||||
}));
|
||||
|
||||
for (const condition of conditions) {
|
||||
if (condition.entityType === 'device_report') {
|
||||
if (condition.entityType === EntityTypeEnum.DEVICE_REPORT) {
|
||||
const device = await this.deviceService.getDeviceByDeviceTuyaUuid(
|
||||
condition.entityId,
|
||||
);
|
||||
|
||||
@ -3,7 +3,6 @@ import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Post,
|
||||
@ -20,11 +19,13 @@ import { CheckUserBuildingGuard } from 'src/guards/user.building.guard';
|
||||
import { AdminRoleGuard } from 'src/guards/admin.role.guard';
|
||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||
import { BuildingPermissionGuard } from 'src/guards/building.permission.guard';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
|
||||
@ApiTags('Building Module')
|
||||
@Controller({
|
||||
version: '1',
|
||||
path: 'building',
|
||||
version: EnableDisableStatusEnum.ENABLED,
|
||||
path: SpaceType.BUILDING,
|
||||
})
|
||||
export class BuildingController {
|
||||
constructor(private readonly buildingService: BuildingService) {}
|
||||
@ -33,36 +34,21 @@ export class BuildingController {
|
||||
@UseGuards(JwtAuthGuard, CheckCommunityTypeGuard)
|
||||
@Post()
|
||||
async addBuilding(@Body() addBuildingDto: AddBuildingDto) {
|
||||
try {
|
||||
const building = await this.buildingService.addBuilding(addBuildingDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Building added successfully',
|
||||
data: building,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const building = await this.buildingService.addBuilding(addBuildingDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Building added successfully',
|
||||
data: building,
|
||||
};
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, BuildingPermissionGuard)
|
||||
@Get(':buildingUuid')
|
||||
async getBuildingByUuid(@Param('buildingUuid') buildingUuid: string) {
|
||||
try {
|
||||
const building =
|
||||
await this.buildingService.getBuildingByUuid(buildingUuid);
|
||||
return building;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const building = await this.buildingService.getBuildingByUuid(buildingUuid);
|
||||
return building;
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@ -72,84 +58,49 @@ export class BuildingController {
|
||||
@Param('buildingUuid') buildingUuid: string,
|
||||
@Query() query: GetBuildingChildDto,
|
||||
) {
|
||||
try {
|
||||
const building = await this.buildingService.getBuildingChildByUuid(
|
||||
buildingUuid,
|
||||
query,
|
||||
);
|
||||
return building;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const building = await this.buildingService.getBuildingChildByUuid(
|
||||
buildingUuid,
|
||||
query,
|
||||
);
|
||||
return building;
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, BuildingPermissionGuard)
|
||||
@Get('parent/:buildingUuid')
|
||||
async getBuildingParentByUuid(@Param('buildingUuid') buildingUuid: string) {
|
||||
try {
|
||||
const building =
|
||||
await this.buildingService.getBuildingParentByUuid(buildingUuid);
|
||||
return building;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const building =
|
||||
await this.buildingService.getBuildingParentByUuid(buildingUuid);
|
||||
return building;
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(AdminRoleGuard, CheckUserBuildingGuard)
|
||||
@Post('user')
|
||||
async addUserBuilding(@Body() addUserBuildingDto: AddUserBuildingDto) {
|
||||
try {
|
||||
await this.buildingService.addUserBuilding(addUserBuildingDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'user building added successfully',
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
await this.buildingService.addUserBuilding(addUserBuildingDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'user building added successfully',
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('user/:userUuid')
|
||||
async getBuildingsByUserId(@Param('userUuid') userUuid: string) {
|
||||
try {
|
||||
return await this.buildingService.getBuildingsByUserId(userUuid);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.buildingService.getBuildingsByUserId(userUuid);
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, BuildingPermissionGuard)
|
||||
@Put('rename/:buildingUuid')
|
||||
@Put(':buildingUuid')
|
||||
async renameBuildingByUuid(
|
||||
@Param('buildingUuid') buildingUuid: string,
|
||||
@Body() updateBuildingDto: UpdateBuildingNameDto,
|
||||
) {
|
||||
try {
|
||||
const building = await this.buildingService.renameBuildingByUuid(
|
||||
buildingUuid,
|
||||
updateBuildingDto,
|
||||
);
|
||||
return building;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const building = await this.buildingService.renameBuildingByUuid(
|
||||
buildingUuid,
|
||||
updateBuildingDto,
|
||||
);
|
||||
return building;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { BooleanValues } from '@app/common/constants/boolean-values.enum';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Transform } from 'class-transformer';
|
||||
import {
|
||||
@ -45,7 +46,7 @@ export class GetBuildingChildDto {
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@Transform((value) => {
|
||||
return value.obj.includeSubSpaces === 'true';
|
||||
return value.obj.includeSubSpaces === BooleanValues.TRUE;
|
||||
})
|
||||
public includeSubSpaces: boolean = false;
|
||||
}
|
||||
|
||||
@ -18,6 +18,8 @@ import {
|
||||
import { SpaceEntity } from '@app/common/modules/space/entities';
|
||||
import { UpdateBuildingNameDto } from '../dtos/update.building.dto';
|
||||
import { UserSpaceRepository } from '@app/common/modules/user/repositories';
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
import { CommonErrorCodes } from '@app/common/constants/error-codes.enum';
|
||||
|
||||
@Injectable()
|
||||
export class BuildingService {
|
||||
@ -31,7 +33,7 @@ export class BuildingService {
|
||||
try {
|
||||
const spaceType = await this.spaceTypeRepository.findOne({
|
||||
where: {
|
||||
type: 'building',
|
||||
type: SpaceType.BUILDING,
|
||||
},
|
||||
});
|
||||
|
||||
@ -61,7 +63,7 @@ export class BuildingService {
|
||||
where: {
|
||||
uuid: buildingUuid,
|
||||
spaceType: {
|
||||
type: 'building',
|
||||
type: SpaceType.BUILDING,
|
||||
},
|
||||
},
|
||||
relations: ['spaceType'],
|
||||
@ -69,7 +71,7 @@ export class BuildingService {
|
||||
if (
|
||||
!building ||
|
||||
!building.spaceType ||
|
||||
building.spaceType.type !== 'building'
|
||||
building.spaceType.type !== SpaceType.BUILDING
|
||||
) {
|
||||
throw new BadRequestException('Invalid building UUID');
|
||||
}
|
||||
@ -99,7 +101,11 @@ export class BuildingService {
|
||||
where: { uuid: buildingUuid },
|
||||
relations: ['children', 'spaceType'],
|
||||
});
|
||||
if (!space || !space.spaceType || space.spaceType.type !== 'building') {
|
||||
if (
|
||||
!space ||
|
||||
!space.spaceType ||
|
||||
space.spaceType.type !== SpaceType.BUILDING
|
||||
) {
|
||||
throw new BadRequestException('Invalid building UUID');
|
||||
}
|
||||
|
||||
@ -147,8 +153,8 @@ export class BuildingService {
|
||||
return children
|
||||
.filter(
|
||||
(child) =>
|
||||
child.spaceType.type !== 'building' &&
|
||||
child.spaceType.type !== 'community',
|
||||
child.spaceType.type !== SpaceType.BUILDING &&
|
||||
child.spaceType.type !== SpaceType.COMMUNITY,
|
||||
) // Filter remaining building and community types
|
||||
.map((child) => ({
|
||||
uuid: child.uuid,
|
||||
@ -161,8 +167,8 @@ export class BuildingService {
|
||||
children
|
||||
.filter(
|
||||
(child) =>
|
||||
child.spaceType.type !== 'building' &&
|
||||
child.spaceType.type !== 'community',
|
||||
child.spaceType.type !== SpaceType.BUILDING &&
|
||||
child.spaceType.type !== SpaceType.COMMUNITY,
|
||||
) // Filter remaining building and community types
|
||||
.map(async (child) => ({
|
||||
uuid: child.uuid,
|
||||
@ -183,7 +189,7 @@ export class BuildingService {
|
||||
where: {
|
||||
uuid: buildingUuid,
|
||||
spaceType: {
|
||||
type: 'building',
|
||||
type: SpaceType.BUILDING,
|
||||
},
|
||||
},
|
||||
relations: ['spaceType', 'parent', 'parent.spaceType'],
|
||||
@ -191,7 +197,7 @@ export class BuildingService {
|
||||
if (
|
||||
!building ||
|
||||
!building.spaceType ||
|
||||
building.spaceType.type !== 'building'
|
||||
building.spaceType.type !== SpaceType.BUILDING
|
||||
) {
|
||||
throw new BadRequestException('Invalid building UUID');
|
||||
}
|
||||
@ -222,7 +228,7 @@ export class BuildingService {
|
||||
relations: ['space', 'space.spaceType'],
|
||||
where: {
|
||||
user: { uuid: userUuid },
|
||||
space: { spaceType: { type: 'building' } },
|
||||
space: { spaceType: { type: SpaceType.BUILDING } },
|
||||
},
|
||||
});
|
||||
|
||||
@ -254,7 +260,7 @@ export class BuildingService {
|
||||
space: { uuid: addUserBuildingDto.buildingUuid },
|
||||
});
|
||||
} catch (err) {
|
||||
if (err.code === '23505') {
|
||||
if (err.code === CommonErrorCodes.DUPLICATE_ENTITY) {
|
||||
throw new HttpException(
|
||||
'User already belongs to this building',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
@ -279,7 +285,7 @@ export class BuildingService {
|
||||
if (
|
||||
!building ||
|
||||
!building.spaceType ||
|
||||
building.spaceType.type !== 'building'
|
||||
building.spaceType.type !== SpaceType.BUILDING
|
||||
) {
|
||||
throw new BadRequestException('Invalid building UUID');
|
||||
}
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
import { HttpExceptionFilter } from './http-exception.filter';
|
||||
|
||||
describe('HttpExceptionFilter', () => {
|
||||
it('should be defined', () => {
|
||||
expect(new HttpExceptionFilter()).toBeDefined();
|
||||
});
|
||||
});
|
||||
38
src/common/filters/http-exception/http-exception.filter.ts
Normal file
38
src/common/filters/http-exception/http-exception.filter.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import {
|
||||
ExceptionFilter,
|
||||
Catch,
|
||||
ArgumentsHost,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
} from '@nestjs/common';
|
||||
import { Response } from 'express';
|
||||
|
||||
@Catch()
|
||||
export class HttpExceptionFilter implements ExceptionFilter {
|
||||
catch(exception: unknown, host: ArgumentsHost) {
|
||||
const ctx = host.switchToHttp();
|
||||
const response = ctx.getResponse<Response>();
|
||||
const request = ctx.getRequest<Request>();
|
||||
const status =
|
||||
exception instanceof HttpException
|
||||
? exception.getStatus()
|
||||
: HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
|
||||
const message =
|
||||
exception instanceof HttpException
|
||||
? exception.getResponse()
|
||||
: 'Internal server error';
|
||||
|
||||
const errorResponse = {
|
||||
statusCode: status,
|
||||
timestamp: new Date().toISOString(),
|
||||
path: request.url,
|
||||
error: message,
|
||||
};
|
||||
|
||||
// Optionally log the exception
|
||||
console.error(`Error occurred:`, exception);
|
||||
|
||||
response.status(status).json(errorResponse);
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,6 @@ import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Post,
|
||||
@ -18,15 +17,16 @@ import {
|
||||
} from '../dtos/add.community.dto';
|
||||
import { GetCommunityChildDto } from '../dtos/get.community.dto';
|
||||
import { UpdateCommunityNameDto } from '../dtos/update.community.dto';
|
||||
// import { CheckUserCommunityGuard } from 'src/guards/user.community.guard';
|
||||
import { AdminRoleGuard } from 'src/guards/admin.role.guard';
|
||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
// import { CommunityPermissionGuard } from 'src/guards/community.permission.guard';
|
||||
|
||||
@ApiTags('Community Module')
|
||||
@Controller({
|
||||
version: '1',
|
||||
path: 'community',
|
||||
version: EnableDisableStatusEnum.ENABLED,
|
||||
path: SpaceType.COMMUNITY,
|
||||
})
|
||||
export class CommunityController {
|
||||
constructor(private readonly communityService: CommunityService) {}
|
||||
@ -35,51 +35,29 @@ export class CommunityController {
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post()
|
||||
async addCommunity(@Body() addCommunityDto: AddCommunityDto) {
|
||||
try {
|
||||
const community =
|
||||
await this.communityService.addCommunity(addCommunityDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Community added successfully',
|
||||
data: community,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const community = await this.communityService.addCommunity(addCommunityDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Community added successfully',
|
||||
data: community,
|
||||
};
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get(':communityUuid')
|
||||
async getCommunityByUuid(@Param('communityUuid') communityUuid: string) {
|
||||
try {
|
||||
const community =
|
||||
await this.communityService.getCommunityByUuid(communityUuid);
|
||||
return community;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const community =
|
||||
await this.communityService.getCommunityByUuid(communityUuid);
|
||||
return community;
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get()
|
||||
async getCommunities() {
|
||||
try {
|
||||
const communities = await this.communityService.getCommunities();
|
||||
return communities;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const communities = await this.communityService.getCommunities();
|
||||
return communities;
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ -88,69 +66,41 @@ export class CommunityController {
|
||||
@Param('communityUuid') communityUuid: string,
|
||||
@Query() query: GetCommunityChildDto,
|
||||
) {
|
||||
try {
|
||||
const community = await this.communityService.getCommunityChildByUuid(
|
||||
communityUuid,
|
||||
query,
|
||||
);
|
||||
return community;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const community = await this.communityService.getCommunityChildByUuid(
|
||||
communityUuid,
|
||||
query,
|
||||
);
|
||||
return community;
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('user/:userUuid')
|
||||
async getCommunitiesByUserId(@Param('userUuid') userUuid: string) {
|
||||
try {
|
||||
return await this.communityService.getCommunitiesByUserId(userUuid);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.communityService.getCommunitiesByUserId(userUuid);
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(AdminRoleGuard)
|
||||
@Post('user')
|
||||
async addUserCommunity(@Body() addUserCommunityDto: AddUserCommunityDto) {
|
||||
try {
|
||||
await this.communityService.addUserCommunity(addUserCommunityDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'user community added successfully',
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
await this.communityService.addUserCommunity(addUserCommunityDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'user community added successfully',
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Put('rename/:communityUuid')
|
||||
@Put(':communityUuid')
|
||||
async renameCommunityByUuid(
|
||||
@Param('communityUuid') communityUuid: string,
|
||||
@Body() updateCommunityDto: UpdateCommunityNameDto,
|
||||
) {
|
||||
try {
|
||||
const community = await this.communityService.renameCommunityByUuid(
|
||||
communityUuid,
|
||||
updateCommunityDto,
|
||||
);
|
||||
return community;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const community = await this.communityService.renameCommunityByUuid(
|
||||
communityUuid,
|
||||
updateCommunityDto,
|
||||
);
|
||||
return community;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { BooleanValues } from '@app/common/constants/boolean-values.enum';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Transform } from 'class-transformer';
|
||||
import {
|
||||
@ -45,7 +46,7 @@ export class GetCommunityChildDto {
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@Transform((value) => {
|
||||
return value.obj.includeSubSpaces === 'true';
|
||||
return value.obj.includeSubSpaces === BooleanValues.TRUE;
|
||||
})
|
||||
public includeSubSpaces: boolean = false;
|
||||
}
|
||||
|
||||
@ -18,6 +18,8 @@ import {
|
||||
import { SpaceEntity } from '@app/common/modules/space/entities';
|
||||
import { UpdateCommunityNameDto } from '../dtos/update.community.dto';
|
||||
import { UserSpaceRepository } from '@app/common/modules/user/repositories';
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
import { CommonErrorCodes } from '@app/common/constants/error-codes.enum';
|
||||
|
||||
@Injectable()
|
||||
export class CommunityService {
|
||||
@ -31,7 +33,7 @@ export class CommunityService {
|
||||
try {
|
||||
const spaceType = await this.spaceTypeRepository.findOne({
|
||||
where: {
|
||||
type: 'community',
|
||||
type: SpaceType.COMMUNITY,
|
||||
},
|
||||
});
|
||||
|
||||
@ -53,7 +55,7 @@ export class CommunityService {
|
||||
where: {
|
||||
uuid: communityUuid,
|
||||
spaceType: {
|
||||
type: 'community',
|
||||
type: SpaceType.COMMUNITY,
|
||||
},
|
||||
},
|
||||
relations: ['spaceType'],
|
||||
@ -61,7 +63,7 @@ export class CommunityService {
|
||||
if (
|
||||
!community ||
|
||||
!community.spaceType ||
|
||||
community.spaceType.type !== 'community'
|
||||
community.spaceType.type !== SpaceType.COMMUNITY
|
||||
) {
|
||||
throw new BadRequestException('Invalid community UUID');
|
||||
}
|
||||
@ -83,7 +85,7 @@ export class CommunityService {
|
||||
async getCommunities(): Promise<GetCommunitiesInterface> {
|
||||
try {
|
||||
const community = await this.spaceRepository.find({
|
||||
where: { spaceType: { type: 'community' } },
|
||||
where: { spaceType: { type: SpaceType.COMMUNITY } },
|
||||
relations: ['spaceType'],
|
||||
});
|
||||
return community.map((community) => ({
|
||||
@ -109,7 +111,11 @@ export class CommunityService {
|
||||
relations: ['children', 'spaceType'],
|
||||
});
|
||||
|
||||
if (!space || !space.spaceType || space.spaceType.type !== 'community') {
|
||||
if (
|
||||
!space ||
|
||||
!space.spaceType ||
|
||||
space.spaceType.type !== SpaceType.COMMUNITY
|
||||
) {
|
||||
throw new BadRequestException('Invalid community UUID');
|
||||
}
|
||||
const totalCount = await this.spaceRepository.count({
|
||||
@ -152,7 +158,7 @@ export class CommunityService {
|
||||
|
||||
if (!children || children.length === 0 || !includeSubSpaces) {
|
||||
return children
|
||||
.filter((child) => child.spaceType.type !== 'community') // Filter remaining community type
|
||||
.filter((child) => child.spaceType.type !== SpaceType.COMMUNITY) // Filter remaining community type
|
||||
.map((child) => ({
|
||||
uuid: child.uuid,
|
||||
name: child.spaceName,
|
||||
@ -162,7 +168,7 @@ export class CommunityService {
|
||||
|
||||
const childHierarchies = await Promise.all(
|
||||
children
|
||||
.filter((child) => child.spaceType.type !== 'community') // Filter remaining community type
|
||||
.filter((child) => child.spaceType.type !== SpaceType.COMMUNITY) // Filter remaining community type
|
||||
.map(async (child) => ({
|
||||
uuid: child.uuid,
|
||||
name: child.spaceName,
|
||||
@ -182,7 +188,7 @@ export class CommunityService {
|
||||
relations: ['space', 'space.spaceType'],
|
||||
where: {
|
||||
user: { uuid: userUuid },
|
||||
space: { spaceType: { type: 'community' } },
|
||||
space: { spaceType: { type: SpaceType.COMMUNITY } },
|
||||
},
|
||||
});
|
||||
|
||||
@ -215,7 +221,7 @@ export class CommunityService {
|
||||
space: { uuid: addUserCommunityDto.communityUuid },
|
||||
});
|
||||
} catch (err) {
|
||||
if (err.code === '23505') {
|
||||
if (err.code === CommonErrorCodes.DUPLICATE_ENTITY) {
|
||||
throw new HttpException(
|
||||
'User already belongs to this community',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
@ -240,7 +246,7 @@ export class CommunityService {
|
||||
if (
|
||||
!community ||
|
||||
!community.spaceType ||
|
||||
community.spaceType.type !== 'community'
|
||||
community.spaceType.type !== SpaceType.COMMUNITY
|
||||
) {
|
||||
throw new BadRequestException('Invalid community UUID');
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@ import {
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Post,
|
||||
@ -14,10 +13,11 @@ import { DeviceMessagesSubscriptionService } from '../services/device-messages.s
|
||||
import { DeviceMessagesAddDto } from '../dtos/device-messages.dto';
|
||||
|
||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
|
||||
@ApiTags('Device Messages Status Module')
|
||||
@Controller({
|
||||
version: '1',
|
||||
version: EnableDisableStatusEnum.ENABLED,
|
||||
path: 'device-messages/subscription',
|
||||
})
|
||||
export class DeviceMessagesSubscriptionController {
|
||||
@ -31,22 +31,15 @@ export class DeviceMessagesSubscriptionController {
|
||||
async addDeviceMessagesSubscription(
|
||||
@Body() deviceMessagesAddDto: DeviceMessagesAddDto,
|
||||
) {
|
||||
try {
|
||||
const addDetails =
|
||||
await this.deviceMessagesSubscriptionService.addDeviceMessagesSubscription(
|
||||
deviceMessagesAddDto,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
message: 'Device Messages Subscription Added Successfully',
|
||||
data: addDetails,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
const addDetails =
|
||||
await this.deviceMessagesSubscriptionService.addDeviceMessagesSubscription(
|
||||
deviceMessagesAddDto,
|
||||
);
|
||||
}
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
message: 'Device Messages Subscription Added Successfully',
|
||||
data: addDetails,
|
||||
};
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@ -56,23 +49,16 @@ export class DeviceMessagesSubscriptionController {
|
||||
@Param('deviceUuid') deviceUuid: string,
|
||||
@Param('userUuid') userUuid: string,
|
||||
) {
|
||||
try {
|
||||
const deviceDetails =
|
||||
await this.deviceMessagesSubscriptionService.getDeviceMessagesSubscription(
|
||||
userUuid,
|
||||
deviceUuid,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'User Device Subscription fetched Successfully',
|
||||
data: deviceDetails,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
const deviceDetails =
|
||||
await this.deviceMessagesSubscriptionService.getDeviceMessagesSubscription(
|
||||
userUuid,
|
||||
deviceUuid,
|
||||
);
|
||||
}
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'User Device Subscription fetched Successfully',
|
||||
data: deviceDetails,
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ -80,19 +66,12 @@ export class DeviceMessagesSubscriptionController {
|
||||
async deleteDeviceMessagesSubscription(
|
||||
@Body() deviceMessagesAddDto: DeviceMessagesAddDto,
|
||||
) {
|
||||
try {
|
||||
await this.deviceMessagesSubscriptionService.deleteDeviceMessagesSubscription(
|
||||
deviceMessagesAddDto,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'User subscription deleted Successfully',
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
await this.deviceMessagesSubscriptionService.deleteDeviceMessagesSubscription(
|
||||
deviceMessagesAddDto,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'User subscription deleted Successfully',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { DeviceMessagesAddDto } from '../dtos/device-messages.dto';
|
||||
import { DeviceNotificationRepository } from '@app/common/modules/device/repositories';
|
||||
import { CommonErrorCodes } from '@app/common/constants/error-codes.enum';
|
||||
|
||||
@Injectable()
|
||||
export class DeviceMessagesSubscriptionService {
|
||||
@ -21,7 +22,7 @@ export class DeviceMessagesSubscriptionService {
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
if (error.code === '23505') {
|
||||
if (error.code === CommonErrorCodes.DUPLICATE_ENTITY) {
|
||||
throw new HttpException(
|
||||
'This User already belongs to this device',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
|
||||
@ -6,7 +6,6 @@ import {
|
||||
Post,
|
||||
Query,
|
||||
Param,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
UseGuards,
|
||||
Req,
|
||||
@ -18,17 +17,24 @@ import {
|
||||
GetDeviceByRoomUuidDto,
|
||||
GetDeviceLogsDto,
|
||||
} from '../dtos/get.device.dto';
|
||||
import { ControlDeviceDto } from '../dtos/control.device.dto';
|
||||
import {
|
||||
ControlDeviceDto,
|
||||
BatchControlDevicesDto,
|
||||
BatchStatusDevicesDto,
|
||||
BatchFactoryResetDevicesDto,
|
||||
} from '../dtos/control.device.dto';
|
||||
import { CheckRoomGuard } from 'src/guards/room.guard';
|
||||
import { CheckUserHavePermission } from 'src/guards/user.device.permission.guard';
|
||||
import { CheckUserHaveControllablePermission } from 'src/guards/user.device.controllable.permission.guard';
|
||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||
import { CheckDeviceGuard } from 'src/guards/device.guard';
|
||||
import { SuperAdminRoleGuard } from 'src/guards/super.admin.role.guard';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
|
||||
@ApiTags('Device Module')
|
||||
@Controller({
|
||||
version: '1',
|
||||
version: EnableDisableStatusEnum.ENABLED,
|
||||
path: 'device',
|
||||
})
|
||||
export class DeviceController {
|
||||
@ -37,67 +43,39 @@ export class DeviceController {
|
||||
@UseGuards(SuperAdminRoleGuard, CheckDeviceGuard)
|
||||
@Post()
|
||||
async addDeviceUser(@Body() addDeviceDto: AddDeviceDto) {
|
||||
try {
|
||||
const device = await this.deviceService.addDeviceUser(addDeviceDto);
|
||||
const device = await this.deviceService.addDeviceUser(addDeviceDto);
|
||||
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'device added successfully',
|
||||
data: device,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'device added successfully',
|
||||
data: device,
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('user/:userUuid')
|
||||
async getDevicesByUser(@Param('userUuid') userUuid: string) {
|
||||
try {
|
||||
return await this.deviceService.getDevicesByUser(userUuid);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.deviceService.getDevicesByUser(userUuid);
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, CheckRoomGuard)
|
||||
@Get('room')
|
||||
@Get(SpaceType.ROOM)
|
||||
async getDevicesByRoomId(
|
||||
@Query() getDeviceByRoomUuidDto: GetDeviceByRoomUuidDto,
|
||||
@Req() req: any,
|
||||
) {
|
||||
try {
|
||||
const userUuid = req.user.uuid;
|
||||
return await this.deviceService.getDevicesByRoomId(
|
||||
getDeviceByRoomUuidDto,
|
||||
userUuid,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const userUuid = req.user.uuid;
|
||||
return await this.deviceService.getDevicesByRoomId(
|
||||
getDeviceByRoomUuidDto,
|
||||
userUuid,
|
||||
);
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('unit/:unitUuid')
|
||||
async getDevicesByUnitId(@Param('unitUuid') unitUuid: string) {
|
||||
try {
|
||||
return await this.deviceService.getDevicesByUnitId(unitUuid);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.deviceService.getDevicesByUnitId(unitUuid);
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, CheckRoomGuard)
|
||||
@ -105,23 +83,16 @@ export class DeviceController {
|
||||
async updateDeviceInRoom(
|
||||
@Body() updateDeviceInRoomDto: UpdateDeviceInRoomDto,
|
||||
) {
|
||||
try {
|
||||
const device = await this.deviceService.updateDeviceInRoom(
|
||||
updateDeviceInRoomDto,
|
||||
);
|
||||
const device = await this.deviceService.updateDeviceInRoom(
|
||||
updateDeviceInRoomDto,
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'device updated in room successfully',
|
||||
data: device,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'device updated in room successfully',
|
||||
data: device,
|
||||
};
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@ -131,18 +102,11 @@ export class DeviceController {
|
||||
@Param('deviceUuid') deviceUuid: string,
|
||||
@Req() req: any,
|
||||
) {
|
||||
try {
|
||||
const userUuid = req.user.uuid;
|
||||
return await this.deviceService.getDeviceDetailsByDeviceId(
|
||||
deviceUuid,
|
||||
userUuid,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const userUuid = req.user.uuid;
|
||||
return await this.deviceService.getDeviceDetailsByDeviceId(
|
||||
deviceUuid,
|
||||
userUuid,
|
||||
);
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, CheckUserHavePermission)
|
||||
@ -150,29 +114,13 @@ export class DeviceController {
|
||||
async getDeviceInstructionByDeviceId(
|
||||
@Param('deviceUuid') deviceUuid: string,
|
||||
) {
|
||||
try {
|
||||
return await this.deviceService.getDeviceInstructionByDeviceId(
|
||||
deviceUuid,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.deviceService.getDeviceInstructionByDeviceId(deviceUuid);
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, CheckUserHavePermission)
|
||||
@Get(':deviceUuid/functions/status')
|
||||
async getDevicesInstructionStatus(@Param('deviceUuid') deviceUuid: string) {
|
||||
try {
|
||||
return await this.deviceService.getDevicesInstructionStatus(deviceUuid);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.deviceService.getDevicesInstructionStatus(deviceUuid);
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@ -182,17 +130,7 @@ export class DeviceController {
|
||||
@Body() controlDeviceDto: ControlDeviceDto,
|
||||
@Param('deviceUuid') deviceUuid: string,
|
||||
) {
|
||||
try {
|
||||
return await this.deviceService.controlDevice(
|
||||
controlDeviceDto,
|
||||
deviceUuid,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.deviceService.controlDevice(controlDeviceDto, deviceUuid);
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ -201,43 +139,22 @@ export class DeviceController {
|
||||
@Param('deviceUuid') deviceUuid: string,
|
||||
@Param('firmwareVersion') firmwareVersion: number,
|
||||
) {
|
||||
try {
|
||||
return await this.deviceService.updateDeviceFirmware(
|
||||
deviceUuid,
|
||||
firmwareVersion,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.deviceService.updateDeviceFirmware(
|
||||
deviceUuid,
|
||||
firmwareVersion,
|
||||
);
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('gateway/:gatewayUuid/devices')
|
||||
async getDevicesInGateway(@Param('gatewayUuid') gatewayUuid: string) {
|
||||
try {
|
||||
return await this.deviceService.getDevicesInGateway(gatewayUuid);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.deviceService.getDevicesInGateway(gatewayUuid);
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get()
|
||||
async getAllDevices() {
|
||||
try {
|
||||
return await this.deviceService.getAllDevices();
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.deviceService.getAllDevices();
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ -246,13 +163,32 @@ export class DeviceController {
|
||||
@Param('deviceUuid') deviceUuid: string,
|
||||
@Query() query: GetDeviceLogsDto,
|
||||
) {
|
||||
try {
|
||||
return await this.deviceService.getDeviceLogs(deviceUuid, query);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.deviceService.getDeviceLogs(deviceUuid, query);
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('control/batch')
|
||||
async batchControlDevices(
|
||||
@Body() batchControlDevicesDto: BatchControlDevicesDto,
|
||||
) {
|
||||
return await this.deviceService.batchControlDevices(batchControlDevicesDto);
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('status/batch')
|
||||
async batchStatusDevices(
|
||||
@Query() batchStatusDevicesDto: BatchStatusDevicesDto,
|
||||
) {
|
||||
return await this.deviceService.batchStatusDevices(batchStatusDevicesDto);
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('factory/reset/:deviceUuid')
|
||||
async batchFactoryResetDevices(
|
||||
@Body() batchFactoryResetDevicesDto: BatchFactoryResetDevicesDto,
|
||||
) {
|
||||
return await this.deviceService.batchFactoryResetDevices(
|
||||
batchFactoryResetDevicesDto,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNotEmpty, IsString } from 'class-validator';
|
||||
import { IsArray, IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class ControlDeviceDto {
|
||||
@ApiProperty({
|
||||
@ -16,3 +16,41 @@ export class ControlDeviceDto {
|
||||
@IsNotEmpty()
|
||||
public value: any;
|
||||
}
|
||||
export class BatchControlDevicesDto {
|
||||
@ApiProperty({
|
||||
description: 'devicesUuid',
|
||||
required: true,
|
||||
})
|
||||
@IsArray()
|
||||
@IsNotEmpty()
|
||||
public devicesUuid: [string];
|
||||
@ApiProperty({
|
||||
description: 'code',
|
||||
required: true,
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public code: string;
|
||||
@ApiProperty({
|
||||
description: 'value',
|
||||
required: true,
|
||||
})
|
||||
@IsNotEmpty()
|
||||
public value: any;
|
||||
}
|
||||
export class BatchStatusDevicesDto {
|
||||
@ApiProperty({
|
||||
example: 'uuid1,uuid2,uuid3',
|
||||
description: 'Comma-separated list of device UUIDs',
|
||||
})
|
||||
devicesUuid: string;
|
||||
}
|
||||
export class BatchFactoryResetDevicesDto {
|
||||
@ApiProperty({
|
||||
description: 'devicesUuid',
|
||||
required: true,
|
||||
})
|
||||
@IsArray()
|
||||
@IsNotEmpty()
|
||||
public devicesUuid: [string];
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNotEmpty, IsString } from 'class-validator';
|
||||
import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||
|
||||
export class GetDeviceByRoomUuidDto {
|
||||
@ApiProperty({
|
||||
@ -18,4 +18,18 @@ export class GetDeviceLogsDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public code: string;
|
||||
@ApiProperty({
|
||||
description: 'startTime',
|
||||
required: false,
|
||||
})
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
public startTime: string;
|
||||
@ApiProperty({
|
||||
description: 'endTime',
|
||||
required: false,
|
||||
})
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
public endTime: string;
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ export interface updateDeviceFirmwareInterface {
|
||||
}
|
||||
export interface getDeviceLogsInterface {
|
||||
data: [];
|
||||
startTime: number;
|
||||
endTime: number;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
deviceUuid?: string;
|
||||
}
|
||||
|
||||
@ -22,7 +22,12 @@ import {
|
||||
GetDeviceByRoomUuidDto,
|
||||
GetDeviceLogsDto,
|
||||
} from '../dtos/get.device.dto';
|
||||
import { ControlDeviceDto } from '../dtos/control.device.dto';
|
||||
import {
|
||||
BatchControlDevicesDto,
|
||||
BatchFactoryResetDevicesDto,
|
||||
BatchStatusDevicesDto,
|
||||
ControlDeviceDto,
|
||||
} from '../dtos/control.device.dto';
|
||||
import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter';
|
||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||
import { PermissionType } from '@app/common/constants/permission-type.enum';
|
||||
@ -30,6 +35,9 @@ import { In } from 'typeorm';
|
||||
import { ProductType } from '@app/common/constants/product-type.enum';
|
||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service';
|
||||
import { DeviceStatuses } from '@app/common/constants/device-status.enum';
|
||||
import { CommonErrorCodes } from '@app/common/constants/error-codes.enum';
|
||||
import { BatteryStatus } from '@app/common/constants/battery-status.enum';
|
||||
|
||||
@Injectable()
|
||||
export class DeviceService {
|
||||
@ -101,7 +109,7 @@ export class DeviceService {
|
||||
}
|
||||
return deviceSaved;
|
||||
} catch (error) {
|
||||
if (error.code === '23505') {
|
||||
if (error.code === CommonErrorCodes.DUPLICATE_ENTITY) {
|
||||
throw new HttpException(
|
||||
'Device already exists',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
@ -121,6 +129,7 @@ export class DeviceService {
|
||||
const devices = await this.deviceRepository.find({
|
||||
where: {
|
||||
user: { uuid: userUuid },
|
||||
isActive: true,
|
||||
permission: {
|
||||
userUuid,
|
||||
permissionType: {
|
||||
@ -167,6 +176,7 @@ export class DeviceService {
|
||||
const devices = await this.deviceRepository.find({
|
||||
where: {
|
||||
spaceDevice: { uuid: getDeviceByRoomUuidDto.roomUuid },
|
||||
isActive: true,
|
||||
permission: {
|
||||
userUuid,
|
||||
permissionType: {
|
||||
@ -284,6 +294,24 @@ export class DeviceService {
|
||||
);
|
||||
}
|
||||
}
|
||||
async factoryResetDeviceTuya(
|
||||
deviceUuid: string,
|
||||
): Promise<controlDeviceInterface> {
|
||||
try {
|
||||
const path = `/v2.0/cloud/thing/${deviceUuid}/reset`;
|
||||
const response = await this.tuya.request({
|
||||
method: 'POST',
|
||||
path,
|
||||
});
|
||||
|
||||
return response as controlDeviceInterface;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
'Error factory resetting device from Tuya',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
async controlDeviceTuya(
|
||||
deviceUuid: string,
|
||||
controlDeviceDto: ControlDeviceDto,
|
||||
@ -308,7 +336,164 @@ export class DeviceService {
|
||||
);
|
||||
}
|
||||
}
|
||||
async batchControlDevices(batchControlDevicesDto: BatchControlDevicesDto) {
|
||||
const { devicesUuid } = batchControlDevicesDto;
|
||||
|
||||
try {
|
||||
// Check if all devices have the same product UUID
|
||||
await this.checkAllDevicesHaveSameProductUuid(devicesUuid);
|
||||
|
||||
// Perform all operations concurrently
|
||||
const results = await Promise.allSettled(
|
||||
devicesUuid.map(async (deviceUuid) => {
|
||||
const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid);
|
||||
const result = await this.controlDeviceTuya(
|
||||
deviceDetails.deviceTuyaUuid,
|
||||
batchControlDevicesDto,
|
||||
);
|
||||
return { deviceUuid, result };
|
||||
}),
|
||||
);
|
||||
|
||||
// Separate successful and failed operations
|
||||
const successResults = [];
|
||||
const failedResults = [];
|
||||
|
||||
for (const result of results) {
|
||||
if (result.status === DeviceStatuses.FULLFILLED) {
|
||||
const { deviceUuid, result: operationResult } = result.value;
|
||||
|
||||
if (operationResult.success) {
|
||||
// Add to success results if operationResult.success is true
|
||||
successResults.push({ deviceUuid, result: operationResult });
|
||||
} else {
|
||||
// Add to failed results if operationResult.success is false
|
||||
failedResults.push({ deviceUuid, error: operationResult.msg });
|
||||
}
|
||||
} else {
|
||||
// Add to failed results if promise is rejected
|
||||
failedResults.push({
|
||||
deviceUuid: devicesUuid[results.indexOf(result)],
|
||||
error: result.reason.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { successResults, failedResults };
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Device Not Found',
|
||||
error.status || HttpStatus.NOT_FOUND,
|
||||
);
|
||||
}
|
||||
}
|
||||
async batchStatusDevices(batchStatusDevicesDto: BatchStatusDevicesDto) {
|
||||
const { devicesUuid } = batchStatusDevicesDto;
|
||||
const devicesUuidArray = devicesUuid.split(',');
|
||||
|
||||
try {
|
||||
await this.checkAllDevicesHaveSameProductUuid(devicesUuidArray);
|
||||
const statuses = await Promise.all(
|
||||
devicesUuidArray.map(async (deviceUuid) => {
|
||||
const result = await this.getDevicesInstructionStatus(deviceUuid);
|
||||
return { deviceUuid, result };
|
||||
}),
|
||||
);
|
||||
return {
|
||||
status: statuses[0].result,
|
||||
devices: statuses,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Device Not Found',
|
||||
error.status || HttpStatus.NOT_FOUND,
|
||||
);
|
||||
}
|
||||
}
|
||||
async checkAllDevicesHaveSameProductUuid(deviceUuids: string[]) {
|
||||
const firstDevice = await this.deviceRepository.findOne({
|
||||
where: { uuid: deviceUuids[0], isActive: true },
|
||||
relations: ['productDevice'],
|
||||
});
|
||||
|
||||
if (!firstDevice) {
|
||||
throw new BadRequestException('First device not found');
|
||||
}
|
||||
|
||||
const firstProductType = firstDevice.productDevice.prodType;
|
||||
|
||||
for (let i = 1; i < deviceUuids.length; i++) {
|
||||
const device = await this.deviceRepository.findOne({
|
||||
where: { uuid: deviceUuids[i], isActive: true },
|
||||
relations: ['productDevice'],
|
||||
});
|
||||
|
||||
if (!device) {
|
||||
throw new BadRequestException(`Device ${deviceUuids[i]} not found`);
|
||||
}
|
||||
|
||||
if (device.productDevice.prodType !== firstProductType) {
|
||||
throw new BadRequestException(`Devices have different product types`);
|
||||
}
|
||||
}
|
||||
}
|
||||
async batchFactoryResetDevices(
|
||||
batchFactoryResetDevicesDto: BatchFactoryResetDevicesDto,
|
||||
) {
|
||||
const { devicesUuid } = batchFactoryResetDevicesDto;
|
||||
|
||||
try {
|
||||
// Check if all devices have the same product UUID
|
||||
await this.checkAllDevicesHaveSameProductUuid(devicesUuid);
|
||||
|
||||
// Perform all operations concurrently
|
||||
const results = await Promise.allSettled(
|
||||
devicesUuid.map(async (deviceUuid) => {
|
||||
const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid);
|
||||
const result = await this.factoryResetDeviceTuya(
|
||||
deviceDetails.deviceTuyaUuid,
|
||||
);
|
||||
return { deviceUuid, result };
|
||||
}),
|
||||
);
|
||||
|
||||
// Separate successful and failed operations
|
||||
const successResults = [];
|
||||
const failedResults = [];
|
||||
|
||||
for (const result of results) {
|
||||
if (result.status === DeviceStatuses.FULLFILLED) {
|
||||
const { deviceUuid, result: operationResult } = result.value;
|
||||
|
||||
if (operationResult.success) {
|
||||
// Add to success results if operationResult.success is true
|
||||
successResults.push({ deviceUuid, result: operationResult });
|
||||
// Update isActive to false in the repository for the successfully reset device
|
||||
await this.deviceRepository.update(
|
||||
{ uuid: deviceUuid },
|
||||
{ isActive: false },
|
||||
);
|
||||
} else {
|
||||
// Add to failed results if operationResult.success is false
|
||||
failedResults.push({ deviceUuid, error: operationResult.msg });
|
||||
}
|
||||
} else {
|
||||
// Add to failed results if promise is rejected
|
||||
failedResults.push({
|
||||
deviceUuid: devicesUuid[results.indexOf(result)],
|
||||
error: result.reason.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { successResults, failedResults };
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Device Not Found',
|
||||
error.status || HttpStatus.NOT_FOUND,
|
||||
);
|
||||
}
|
||||
}
|
||||
async getDeviceDetailsByDeviceId(deviceUuid: string, userUuid: string) {
|
||||
try {
|
||||
const userDevicePermission = await this.getUserDevicePermission(
|
||||
@ -359,7 +544,7 @@ export class DeviceService {
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { productName, productId, id, ...rest } = camelCaseResponse.result;
|
||||
const { productId, id, ...rest } = camelCaseResponse.result;
|
||||
|
||||
return {
|
||||
...rest,
|
||||
@ -492,19 +677,25 @@ export class DeviceService {
|
||||
|
||||
const devices = await Promise.all(
|
||||
response.map(async (device: any) => {
|
||||
const deviceDetails = await this.getDeviceByDeviceTuyaUuid(device.id);
|
||||
if (deviceDetails.deviceTuyaUuid) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { id, ...rest } = device;
|
||||
return {
|
||||
...rest,
|
||||
tuyaUuid: deviceDetails.deviceTuyaUuid,
|
||||
uuid: deviceDetails.uuid,
|
||||
productUuid: deviceDetails.productDevice.uuid,
|
||||
productType: deviceDetails.productDevice.prodType,
|
||||
};
|
||||
try {
|
||||
const deviceDetails = await this.getDeviceByDeviceTuyaUuid(
|
||||
device.id,
|
||||
);
|
||||
if (deviceDetails.deviceTuyaUuid) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { id, ...rest } = device;
|
||||
return {
|
||||
...rest,
|
||||
tuyaUuid: deviceDetails.deviceTuyaUuid,
|
||||
uuid: deviceDetails.uuid,
|
||||
productUuid: deviceDetails.productDevice.uuid,
|
||||
productType: deviceDetails.productDevice.prodType,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
);
|
||||
|
||||
@ -593,6 +784,9 @@ export class DeviceService {
|
||||
parent: {
|
||||
uuid: unitUuid,
|
||||
},
|
||||
devicesSpaceEntity: {
|
||||
isActive: true,
|
||||
},
|
||||
},
|
||||
relations: ['devicesSpaceEntity', 'devicesSpaceEntity.productDevice'],
|
||||
});
|
||||
@ -627,6 +821,7 @@ export class DeviceService {
|
||||
async getAllDevices(): Promise<GetDeviceDetailsInterface[]> {
|
||||
try {
|
||||
const devices = await this.deviceRepository.find({
|
||||
where: { isActive: true },
|
||||
relations: [
|
||||
'spaceDevice.parent',
|
||||
'productDevice',
|
||||
@ -644,14 +839,40 @@ export class DeviceService {
|
||||
await this.getDevicesInstructionStatus(device.uuid);
|
||||
|
||||
const batteryStatus: any = doorLockInstructionsStatus.status.find(
|
||||
(status: any) => status.code === 'residual_electricity',
|
||||
(status: any) =>
|
||||
status.code === BatteryStatus.RESIDUAL_ELECTRICITY,
|
||||
);
|
||||
|
||||
if (batteryStatus) {
|
||||
battery = batteryStatus.value;
|
||||
}
|
||||
}
|
||||
// Check if the device is a door sensor (DS)
|
||||
if (device.productDevice.prodType === ProductType.DS) {
|
||||
const doorSensorInstructionsStatus =
|
||||
await this.getDevicesInstructionStatus(device.uuid);
|
||||
|
||||
const batteryStatus: any = doorSensorInstructionsStatus.status.find(
|
||||
(status: any) => status.code === BatteryStatus.BATTERY_PERCENTAGE,
|
||||
);
|
||||
|
||||
if (batteryStatus) {
|
||||
battery = batteryStatus.value;
|
||||
}
|
||||
}
|
||||
// Check if the device is a water leak sensor (WL)
|
||||
if (device.productDevice.prodType === ProductType.WL) {
|
||||
const doorSensorInstructionsStatus =
|
||||
await this.getDevicesInstructionStatus(device.uuid);
|
||||
|
||||
const batteryStatus: any = doorSensorInstructionsStatus.status.find(
|
||||
(status: any) => status.code === BatteryStatus.BATTERY_PERCENTAGE,
|
||||
);
|
||||
|
||||
if (batteryStatus) {
|
||||
battery = batteryStatus.value;
|
||||
}
|
||||
}
|
||||
const spaceDevice = device?.spaceDevice;
|
||||
const parentDevice = spaceDevice?.parent;
|
||||
return {
|
||||
@ -677,7 +898,7 @@ export class DeviceService {
|
||||
|
||||
// Filter out rejected promises and extract the fulfilled values
|
||||
const fulfilledDevices = devicesData
|
||||
.filter((result) => result.status === 'fulfilled')
|
||||
.filter((result) => result.status === DeviceStatuses.FULLFILLED)
|
||||
.map(
|
||||
(result) =>
|
||||
(result as PromiseFulfilledResult<GetDeviceDetailsInterface>).value,
|
||||
@ -702,6 +923,8 @@ export class DeviceService {
|
||||
const response = await this.getDeviceLogsTuya(
|
||||
deviceDetails.deviceTuyaUuid,
|
||||
query.code,
|
||||
query.startTime,
|
||||
query.endTime,
|
||||
);
|
||||
|
||||
return {
|
||||
@ -718,11 +941,11 @@ export class DeviceService {
|
||||
async getDeviceLogsTuya(
|
||||
deviceId: string,
|
||||
code: string,
|
||||
startTime: string = (Date.now() - 1 * 60 * 60 * 1000).toString(),
|
||||
endTime: string = Date.now().toString(),
|
||||
): Promise<getDeviceLogsInterface> {
|
||||
try {
|
||||
const now = Date.now();
|
||||
const oneHourAgo = now - 1 * 60 * 60 * 1000;
|
||||
const path = `/v2.0/cloud/thing/${deviceId}/report-logs?start_time=${oneHourAgo}&end_time=${now}&codes=${code}&size=50`;
|
||||
const path = `/v2.0/cloud/thing/${deviceId}/report-logs?start_time=${startTime}&end_time=${endTime}&codes=${code}&size=50`;
|
||||
const response = await this.tuya.request({
|
||||
method: 'GET',
|
||||
path,
|
||||
@ -731,8 +954,8 @@ export class DeviceService {
|
||||
const camelCaseResponse = convertKeysToCamelCase(response);
|
||||
const logs = camelCaseResponse.result.logs ?? [];
|
||||
return {
|
||||
startTime: oneHourAgo,
|
||||
endTime: now,
|
||||
startTime,
|
||||
endTime,
|
||||
data: logs,
|
||||
} as getDeviceLogsInterface;
|
||||
} catch (error) {
|
||||
|
||||
@ -4,7 +4,6 @@ import {
|
||||
Controller,
|
||||
Post,
|
||||
Param,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Get,
|
||||
Delete,
|
||||
@ -16,10 +15,11 @@ import { AddDoorLockOnlineDto } from '../dtos/add.online-temp.dto';
|
||||
import { AddDoorLockOfflineTempMultipleTimeDto } from '../dtos/add.offline-temp.dto';
|
||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||
import { UpdateDoorLockOfflineTempDto } from '../dtos/update.offline-temp.dto';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
|
||||
@ApiTags('Door Lock Module')
|
||||
@Controller({
|
||||
version: '1',
|
||||
version: EnableDisableStatusEnum.ENABLED,
|
||||
path: 'door-lock',
|
||||
})
|
||||
export class DoorLockController {
|
||||
@ -31,27 +31,20 @@ export class DoorLockController {
|
||||
@Body() addDoorLockDto: AddDoorLockOnlineDto,
|
||||
@Param('doorLockUuid') doorLockUuid: string,
|
||||
) {
|
||||
try {
|
||||
const temporaryPassword =
|
||||
await this.doorLockService.addOnlineTemporaryPassword(
|
||||
addDoorLockDto,
|
||||
doorLockUuid,
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'online temporary password added successfully',
|
||||
data: {
|
||||
id: temporaryPassword.id,
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
const temporaryPassword =
|
||||
await this.doorLockService.addOnlineTemporaryPassword(
|
||||
addDoorLockDto,
|
||||
doorLockUuid,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'online temporary password added successfully',
|
||||
data: {
|
||||
id: temporaryPassword.id,
|
||||
},
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ -59,24 +52,17 @@ export class DoorLockController {
|
||||
async addOfflineOneTimeTemporaryPassword(
|
||||
@Param('doorLockUuid') doorLockUuid: string,
|
||||
) {
|
||||
try {
|
||||
const temporaryPassword =
|
||||
await this.doorLockService.addOfflineOneTimeTemporaryPassword(
|
||||
doorLockUuid,
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'offline temporary password added successfully',
|
||||
data: temporaryPassword,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
const temporaryPassword =
|
||||
await this.doorLockService.addOfflineOneTimeTemporaryPassword(
|
||||
doorLockUuid,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'offline temporary password added successfully',
|
||||
data: temporaryPassword,
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ -86,25 +72,18 @@ export class DoorLockController {
|
||||
addDoorLockOfflineTempMultipleTimeDto: AddDoorLockOfflineTempMultipleTimeDto,
|
||||
@Param('doorLockUuid') doorLockUuid: string,
|
||||
) {
|
||||
try {
|
||||
const temporaryPassword =
|
||||
await this.doorLockService.addOfflineMultipleTimeTemporaryPassword(
|
||||
addDoorLockOfflineTempMultipleTimeDto,
|
||||
doorLockUuid,
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'offline temporary password added successfully',
|
||||
data: temporaryPassword,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
const temporaryPassword =
|
||||
await this.doorLockService.addOfflineMultipleTimeTemporaryPassword(
|
||||
addDoorLockOfflineTempMultipleTimeDto,
|
||||
doorLockUuid,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'offline temporary password added successfully',
|
||||
data: temporaryPassword,
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ -112,16 +91,9 @@ export class DoorLockController {
|
||||
async getOnlineTemporaryPasswords(
|
||||
@Param('doorLockUuid') doorLockUuid: string,
|
||||
) {
|
||||
try {
|
||||
return await this.doorLockService.getOnlineTemporaryPasswordsMultiple(
|
||||
doorLockUuid,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.doorLockService.getOnlineTemporaryPasswordsMultiple(
|
||||
doorLockUuid,
|
||||
);
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ -130,21 +102,11 @@ export class DoorLockController {
|
||||
@Param('doorLockUuid') doorLockUuid: string,
|
||||
@Param('passwordId') passwordId: string,
|
||||
) {
|
||||
try {
|
||||
await this.doorLockService.deleteDoorLockPassword(
|
||||
doorLockUuid,
|
||||
passwordId,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'Temporary Password deleted Successfully',
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
await this.doorLockService.deleteDoorLockPassword(doorLockUuid, passwordId);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'Temporary Password deleted Successfully',
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ -152,16 +114,9 @@ export class DoorLockController {
|
||||
async getOfflineOneTimeTemporaryPasswords(
|
||||
@Param('doorLockUuid') doorLockUuid: string,
|
||||
) {
|
||||
try {
|
||||
return await this.doorLockService.getOfflineOneTimeTemporaryPasswords(
|
||||
doorLockUuid,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.doorLockService.getOfflineOneTimeTemporaryPasswords(
|
||||
doorLockUuid,
|
||||
);
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ -169,16 +124,9 @@ export class DoorLockController {
|
||||
async getOfflineMultipleTimeTemporaryPasswords(
|
||||
@Param('doorLockUuid') doorLockUuid: string,
|
||||
) {
|
||||
try {
|
||||
return await this.doorLockService.getOfflineMultipleTimeTemporaryPasswords(
|
||||
doorLockUuid,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.doorLockService.getOfflineMultipleTimeTemporaryPasswords(
|
||||
doorLockUuid,
|
||||
);
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@ -190,44 +138,30 @@ export class DoorLockController {
|
||||
@Param('doorLockUuid') doorLockUuid: string,
|
||||
@Param('passwordId') passwordId: string,
|
||||
) {
|
||||
try {
|
||||
const temporaryPassword =
|
||||
await this.doorLockService.updateOfflineTemporaryPassword(
|
||||
updateDoorLockOfflineTempDto,
|
||||
doorLockUuid,
|
||||
passwordId,
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'offline temporary password updated successfully',
|
||||
data: temporaryPassword,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
const temporaryPassword =
|
||||
await this.doorLockService.updateOfflineTemporaryPassword(
|
||||
updateDoorLockOfflineTempDto,
|
||||
doorLockUuid,
|
||||
passwordId,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'offline temporary password updated successfully',
|
||||
data: temporaryPassword,
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('open/:doorLockUuid')
|
||||
async openDoorLock(@Param('doorLockUuid') doorLockUuid: string) {
|
||||
try {
|
||||
await this.doorLockService.openDoorLock(doorLockUuid);
|
||||
await this.doorLockService.openDoorLock(doorLockUuid);
|
||||
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'door lock opened successfully',
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'door lock opened successfully',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,6 +24,15 @@ import { UpdateDoorLockOfflineTempDto } from '../dtos/update.offline-temp.dto';
|
||||
import { defaultDoorLockPass } from '@app/common/constants/default.door-lock-pass';
|
||||
import { VisitorPasswordRepository } from '@app/common/modules/visitor-password/repositories';
|
||||
import { DeviceService } from 'src/device/services';
|
||||
import {
|
||||
DaysEnum,
|
||||
EnableDisableStatusEnum,
|
||||
} from '@app/common/constants/days.enum';
|
||||
import { PasswordType } from '@app/common/constants/password-type.enum';
|
||||
import {
|
||||
CommonHourMinutes,
|
||||
CommonHours,
|
||||
} from '@app/common/constants/hours-minutes.enum';
|
||||
|
||||
@Injectable()
|
||||
export class DoorLockService {
|
||||
@ -115,7 +124,7 @@ export class DoorLockService {
|
||||
);
|
||||
const passwords = await this.getTemporaryOfflinePasswordsTuya(
|
||||
deviceDetails.deviceTuyaUuid,
|
||||
'multiple',
|
||||
PasswordType.MULTIPLE,
|
||||
isExpired,
|
||||
);
|
||||
if (!passwords.result.records.length && fromVisitor) {
|
||||
@ -502,7 +511,7 @@ export class DoorLockService {
|
||||
}
|
||||
const createOnceOfflinePass = await this.addOfflineTemporaryPasswordTuya(
|
||||
deviceDetails.deviceTuyaUuid,
|
||||
'multiple',
|
||||
PasswordType.MULTIPLE,
|
||||
addDoorLockOfflineTempMultipleTimeDto,
|
||||
);
|
||||
if (!createOnceOfflinePass.success) {
|
||||
@ -566,7 +575,7 @@ export class DoorLockService {
|
||||
method: 'POST',
|
||||
path,
|
||||
body: {
|
||||
...(type === 'multiple' && {
|
||||
...(type === PasswordType.MULTIPLE && {
|
||||
effective_time: addDoorLockOfflineTempMultipleTimeDto.effectiveTime,
|
||||
invalid_time: addDoorLockOfflineTempMultipleTimeDto.invalidTime,
|
||||
}),
|
||||
@ -711,7 +720,7 @@ export class DoorLockService {
|
||||
schedule_list: scheduleList,
|
||||
}),
|
||||
|
||||
type: '0',
|
||||
type: EnableDisableStatusEnum.DISABLED,
|
||||
},
|
||||
});
|
||||
|
||||
@ -725,7 +734,15 @@ export class DoorLockService {
|
||||
}
|
||||
getWorkingDayValue(days) {
|
||||
// Array representing the days of the week
|
||||
const weekDays = ['Sat', 'Fri', 'Thu', 'Wed', 'Tue', 'Mon', 'Sun'];
|
||||
const weekDays = [
|
||||
DaysEnum.SAT,
|
||||
DaysEnum.FRI,
|
||||
DaysEnum.THU,
|
||||
DaysEnum.WED,
|
||||
DaysEnum.TUE,
|
||||
DaysEnum.MON,
|
||||
DaysEnum.SUN,
|
||||
];
|
||||
|
||||
// Initialize a binary string with 7 bits
|
||||
let binaryString = '0000000';
|
||||
@ -734,10 +751,10 @@ export class DoorLockService {
|
||||
days.forEach((day) => {
|
||||
const index = weekDays.indexOf(day);
|
||||
if (index !== -1) {
|
||||
// Set the corresponding bit to '1'
|
||||
// Set the corresponding bit to EnableDisableStatusEnum.ENABLED
|
||||
binaryString =
|
||||
binaryString.substring(0, index) +
|
||||
'1' +
|
||||
EnableDisableStatusEnum.ENABLED +
|
||||
binaryString.substring(index + 1);
|
||||
}
|
||||
});
|
||||
@ -749,17 +766,27 @@ export class DoorLockService {
|
||||
}
|
||||
getDaysFromWorkingDayValue(workingDayValue) {
|
||||
// Array representing the days of the week
|
||||
const weekDays = ['Sat', 'Fri', 'Thu', 'Wed', 'Tue', 'Mon', 'Sun'];
|
||||
const weekDays = [
|
||||
DaysEnum.SAT,
|
||||
DaysEnum.FRI,
|
||||
DaysEnum.THU,
|
||||
DaysEnum.WED,
|
||||
DaysEnum.TUE,
|
||||
DaysEnum.MON,
|
||||
DaysEnum.SUN,
|
||||
];
|
||||
|
||||
// Convert the integer to a binary string and pad with leading zeros to ensure 7 bits
|
||||
const binaryString = workingDayValue.toString(2).padStart(7, '0');
|
||||
const binaryString = workingDayValue
|
||||
.toString(2)
|
||||
.padStart(7, EnableDisableStatusEnum.DISABLED);
|
||||
|
||||
// Initialize an array to hold the days of the week
|
||||
const days = [];
|
||||
|
||||
// Iterate through the binary string and weekDays array
|
||||
for (let i = 0; i < binaryString.length; i++) {
|
||||
if (binaryString[i] === '1') {
|
||||
if (binaryString[i] === EnableDisableStatusEnum.ENABLED) {
|
||||
days.push(weekDays[i]);
|
||||
}
|
||||
}
|
||||
@ -769,8 +796,8 @@ export class DoorLockService {
|
||||
timeToMinutes(timeStr) {
|
||||
try {
|
||||
// Special case for "24:00"
|
||||
if (timeStr === '24:00') {
|
||||
return 1440;
|
||||
if (timeStr === CommonHours.TWENTY_FOUR) {
|
||||
return CommonHourMinutes.TWENTY_FOUR;
|
||||
}
|
||||
|
||||
// Regular expression to validate the 24-hour time format (HH:MM)
|
||||
@ -798,20 +825,26 @@ export class DoorLockService {
|
||||
if (
|
||||
typeof totalMinutes !== 'number' ||
|
||||
totalMinutes < 0 ||
|
||||
totalMinutes > 1440
|
||||
totalMinutes > CommonHourMinutes.TWENTY_FOUR
|
||||
) {
|
||||
throw new Error('Invalid minutes value');
|
||||
}
|
||||
|
||||
if (totalMinutes === 1440) {
|
||||
return '24:00';
|
||||
if (totalMinutes === CommonHourMinutes.TWENTY_FOUR) {
|
||||
return CommonHours.TWENTY_FOUR;
|
||||
}
|
||||
|
||||
const hours = Math.floor(totalMinutes / 60);
|
||||
const minutes = totalMinutes % 60;
|
||||
|
||||
const formattedHours = String(hours).padStart(2, '0');
|
||||
const formattedMinutes = String(minutes).padStart(2, '0');
|
||||
const formattedHours = String(hours).padStart(
|
||||
2,
|
||||
EnableDisableStatusEnum.DISABLED,
|
||||
);
|
||||
const formattedMinutes = String(minutes).padStart(
|
||||
2,
|
||||
EnableDisableStatusEnum.DISABLED,
|
||||
);
|
||||
|
||||
return `${formattedHours}:${formattedMinutes}`;
|
||||
} catch (error) {
|
||||
@ -826,6 +859,7 @@ export class DoorLockService {
|
||||
return await this.deviceRepository.findOne({
|
||||
where: {
|
||||
uuid: deviceUuid,
|
||||
isActive: true,
|
||||
},
|
||||
...(withProductDevice && { relations: ['productDevice'] }),
|
||||
});
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import * as CryptoJS from 'crypto-js';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
|
||||
@Injectable()
|
||||
export class PasswordEncryptionService {
|
||||
@ -43,7 +44,9 @@ export class PasswordEncryptionService {
|
||||
'auth-config.SECRET_KEY',
|
||||
);
|
||||
// The accessSecret must be 32 bytes, ensure it is properly padded or truncated
|
||||
const paddedAccessSecret = accessSecret.padEnd(32, '0').slice(0, 32);
|
||||
const paddedAccessSecret = accessSecret
|
||||
.padEnd(32, EnableDisableStatusEnum.DISABLED)
|
||||
.slice(0, 32);
|
||||
const plainTextTicketKey = this.decrypt(ticketKey, paddedAccessSecret);
|
||||
|
||||
return this.encrypt(plainTextPassword, plainTextTicketKey);
|
||||
|
||||
18
src/error-message/error-message.service.spec.ts
Normal file
18
src/error-message/error-message.service.spec.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { ErrorMessageService } from './error-message.service';
|
||||
|
||||
describe('ErrorMessageService', () => {
|
||||
let service: ErrorMessageService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [ErrorMessageService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<ErrorMessageService>(ErrorMessageService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
||||
40
src/error-message/error-message.service.ts
Normal file
40
src/error-message/error-message.service.ts
Normal file
@ -0,0 +1,40 @@
|
||||
// src/common/services/error-message.service.ts
|
||||
import { Injectable } from '@nestjs/common';
|
||||
type ErrorMessageKey = keyof typeof ErrorMessageService.prototype.messages;
|
||||
|
||||
@Injectable()
|
||||
export class ErrorMessageService {
|
||||
public readonly messages = {
|
||||
NOT_FOUND: '{entity} not found', // Single key for "not found" errors
|
||||
INVALID_MINUTES: 'Invalid minutes value',
|
||||
INVALID_TIME_FORMAT: 'Invalid time format',
|
||||
USER_NOT_FOUND: '{entity} not found', // Can reuse NOT_FOUND if desired
|
||||
INTERNAL_SERVER_ERROR: 'Internal server error',
|
||||
ERROR_ADDING_TEMP_PASSWORD:
|
||||
'Error adding {type} temporary password from Tuya',
|
||||
INVALID_UUID: 'Invalid {entity} UUID',
|
||||
USER_ALREADY_BELONGS: 'This user already belongs to this {entity}',
|
||||
USER_HAS_NO_ENTITIES: 'This user has no {entity}',
|
||||
DEVICE_OPERATION_FAILED: 'All device operations failed',
|
||||
REQUEST_FAILED: 'Error processing {operation} request',
|
||||
COOLDOWN_ERROR:
|
||||
'Please wait {time} more seconds before requesting a new OTP.',
|
||||
};
|
||||
|
||||
getMessage(
|
||||
key: ErrorMessageKey,
|
||||
params?: Record<string, string | number>,
|
||||
): string {
|
||||
let message = this.messages[key] || 'Unknown error';
|
||||
|
||||
// Replace placeholders with provided params
|
||||
if (params) {
|
||||
Object.keys(params).forEach((param) => {
|
||||
const regex = new RegExp(`{${param}}`, 'g');
|
||||
message = message.replace(regex, params[param].toString());
|
||||
});
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,6 @@ import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Post,
|
||||
@ -20,11 +19,13 @@ import { CheckUserFloorGuard } from 'src/guards/user.floor.guard';
|
||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||
import { AdminRoleGuard } from 'src/guards/admin.role.guard';
|
||||
import { FloorPermissionGuard } from 'src/guards/floor.permission.guard';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
|
||||
@ApiTags('Floor Module')
|
||||
@Controller({
|
||||
version: '1',
|
||||
path: 'floor',
|
||||
version: EnableDisableStatusEnum.ENABLED,
|
||||
path: SpaceType.FLOOR,
|
||||
})
|
||||
export class FloorController {
|
||||
constructor(private readonly floorService: FloorService) {}
|
||||
@ -33,35 +34,21 @@ export class FloorController {
|
||||
@UseGuards(JwtAuthGuard, CheckBuildingTypeGuard)
|
||||
@Post()
|
||||
async addFloor(@Body() addFloorDto: AddFloorDto) {
|
||||
try {
|
||||
const floor = await this.floorService.addFloor(addFloorDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Floor added successfully',
|
||||
data: floor,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const floor = await this.floorService.addFloor(addFloorDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Floor added successfully',
|
||||
data: floor,
|
||||
};
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, FloorPermissionGuard)
|
||||
@Get(':floorUuid')
|
||||
async getFloorByUuid(@Param('floorUuid') floorUuid: string) {
|
||||
try {
|
||||
const floor = await this.floorService.getFloorByUuid(floorUuid);
|
||||
return floor;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const floor = await this.floorService.getFloorByUuid(floorUuid);
|
||||
return floor;
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@ -71,85 +58,47 @@ export class FloorController {
|
||||
@Param('floorUuid') floorUuid: string,
|
||||
@Query() query: GetFloorChildDto,
|
||||
) {
|
||||
try {
|
||||
const floor = await this.floorService.getFloorChildByUuid(
|
||||
floorUuid,
|
||||
query,
|
||||
);
|
||||
return floor;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const floor = await this.floorService.getFloorChildByUuid(floorUuid, query);
|
||||
return floor;
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, FloorPermissionGuard)
|
||||
@Get('parent/:floorUuid')
|
||||
async getFloorParentByUuid(@Param('floorUuid') floorUuid: string) {
|
||||
try {
|
||||
const floor = await this.floorService.getFloorParentByUuid(floorUuid);
|
||||
return floor;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const floor = await this.floorService.getFloorParentByUuid(floorUuid);
|
||||
return floor;
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(AdminRoleGuard, CheckUserFloorGuard)
|
||||
@Post('user')
|
||||
async addUserFloor(@Body() addUserFloorDto: AddUserFloorDto) {
|
||||
try {
|
||||
await this.floorService.addUserFloor(addUserFloorDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'user floor added successfully',
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
await this.floorService.addUserFloor(addUserFloorDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'user floor added successfully',
|
||||
};
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('user/:userUuid')
|
||||
async getFloorsByUserId(@Param('userUuid') userUuid: string) {
|
||||
try {
|
||||
return await this.floorService.getFloorsByUserId(userUuid);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.floorService.getFloorsByUserId(userUuid);
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, FloorPermissionGuard)
|
||||
@Put('rename/:floorUuid')
|
||||
@Put(':floorUuid')
|
||||
async renameFloorByUuid(
|
||||
@Param('floorUuid') floorUuid: string,
|
||||
@Body() updateFloorNameDto: UpdateFloorNameDto,
|
||||
) {
|
||||
try {
|
||||
const floor = await this.floorService.renameFloorByUuid(
|
||||
floorUuid,
|
||||
updateFloorNameDto,
|
||||
);
|
||||
return floor;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const floor = await this.floorService.renameFloorByUuid(
|
||||
floorUuid,
|
||||
updateFloorNameDto,
|
||||
);
|
||||
return floor;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { BooleanValues } from '@app/common/constants/boolean-values.enum';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Transform } from 'class-transformer';
|
||||
import {
|
||||
@ -45,7 +46,7 @@ export class GetFloorChildDto {
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@Transform((value) => {
|
||||
return value.obj.includeSubSpaces === 'true';
|
||||
return value.obj.includeSubSpaces === BooleanValues.TRUE;
|
||||
})
|
||||
public includeSubSpaces: boolean = false;
|
||||
}
|
||||
|
||||
@ -18,6 +18,8 @@ import {
|
||||
import { SpaceEntity } from '@app/common/modules/space/entities';
|
||||
import { UpdateFloorNameDto } from '../dtos/update.floor.dto';
|
||||
import { UserSpaceRepository } from '@app/common/modules/user/repositories';
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
import { CommonErrorCodes } from '@app/common/constants/error-codes.enum';
|
||||
|
||||
@Injectable()
|
||||
export class FloorService {
|
||||
@ -31,7 +33,7 @@ export class FloorService {
|
||||
try {
|
||||
const spaceType = await this.spaceTypeRepository.findOne({
|
||||
where: {
|
||||
type: 'floor',
|
||||
type: SpaceType.FLOOR,
|
||||
},
|
||||
});
|
||||
|
||||
@ -52,12 +54,16 @@ export class FloorService {
|
||||
where: {
|
||||
uuid: floorUuid,
|
||||
spaceType: {
|
||||
type: 'floor',
|
||||
type: SpaceType.FLOOR,
|
||||
},
|
||||
},
|
||||
relations: ['spaceType'],
|
||||
});
|
||||
if (!floor || !floor.spaceType || floor.spaceType.type !== 'floor') {
|
||||
if (
|
||||
!floor ||
|
||||
!floor.spaceType ||
|
||||
floor.spaceType.type !== SpaceType.FLOOR
|
||||
) {
|
||||
throw new BadRequestException('Invalid floor UUID');
|
||||
}
|
||||
|
||||
@ -88,7 +94,11 @@ export class FloorService {
|
||||
relations: ['children', 'spaceType'],
|
||||
});
|
||||
|
||||
if (!space || !space.spaceType || space.spaceType.type !== 'floor') {
|
||||
if (
|
||||
!space ||
|
||||
!space.spaceType ||
|
||||
space.spaceType.type !== SpaceType.FLOOR
|
||||
) {
|
||||
throw new BadRequestException('Invalid floor UUID');
|
||||
}
|
||||
const totalCount = await this.spaceRepository.count({
|
||||
@ -135,9 +145,9 @@ export class FloorService {
|
||||
return children
|
||||
.filter(
|
||||
(child) =>
|
||||
child.spaceType.type !== 'floor' &&
|
||||
child.spaceType.type !== 'building' &&
|
||||
child.spaceType.type !== 'community',
|
||||
child.spaceType.type !== SpaceType.FLOOR &&
|
||||
child.spaceType.type !== SpaceType.BUILDING &&
|
||||
child.spaceType.type !== SpaceType.COMMUNITY,
|
||||
) // Filter remaining floor and building and community types
|
||||
.map((child) => ({
|
||||
uuid: child.uuid,
|
||||
@ -150,9 +160,9 @@ export class FloorService {
|
||||
children
|
||||
.filter(
|
||||
(child) =>
|
||||
child.spaceType.type !== 'floor' &&
|
||||
child.spaceType.type !== 'building' &&
|
||||
child.spaceType.type !== 'community',
|
||||
child.spaceType.type !== SpaceType.FLOOR &&
|
||||
child.spaceType.type !== SpaceType.BUILDING &&
|
||||
child.spaceType.type !== SpaceType.COMMUNITY,
|
||||
) // Filter remaining floor and building and community types
|
||||
.map(async (child) => ({
|
||||
uuid: child.uuid,
|
||||
@ -171,12 +181,16 @@ export class FloorService {
|
||||
where: {
|
||||
uuid: floorUuid,
|
||||
spaceType: {
|
||||
type: 'floor',
|
||||
type: SpaceType.FLOOR,
|
||||
},
|
||||
},
|
||||
relations: ['spaceType', 'parent', 'parent.spaceType'],
|
||||
});
|
||||
if (!floor || !floor.spaceType || floor.spaceType.type !== 'floor') {
|
||||
if (
|
||||
!floor ||
|
||||
!floor.spaceType ||
|
||||
floor.spaceType.type !== SpaceType.FLOOR
|
||||
) {
|
||||
throw new BadRequestException('Invalid floor UUID');
|
||||
}
|
||||
|
||||
@ -207,7 +221,7 @@ export class FloorService {
|
||||
relations: ['space', 'space.spaceType'],
|
||||
where: {
|
||||
user: { uuid: userUuid },
|
||||
space: { spaceType: { type: 'floor' } },
|
||||
space: { spaceType: { type: SpaceType.FLOOR } },
|
||||
},
|
||||
});
|
||||
|
||||
@ -239,7 +253,7 @@ export class FloorService {
|
||||
space: { uuid: addUserFloorDto.floorUuid },
|
||||
});
|
||||
} catch (err) {
|
||||
if (err.code === '23505') {
|
||||
if (err.code === CommonErrorCodes.DUPLICATE_ENTITY) {
|
||||
throw new HttpException(
|
||||
'User already belongs to this floor',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
@ -261,7 +275,11 @@ export class FloorService {
|
||||
relations: ['spaceType'],
|
||||
});
|
||||
|
||||
if (!floor || !floor.spaceType || floor.spaceType.type !== 'floor') {
|
||||
if (
|
||||
!floor ||
|
||||
!floor.spaceType ||
|
||||
floor.spaceType.type !== SpaceType.FLOOR
|
||||
) {
|
||||
throw new BadRequestException('Invalid floor UUID');
|
||||
}
|
||||
|
||||
|
||||
@ -1,20 +1,13 @@
|
||||
import { GroupService } from '../services/group.service';
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
UseGuards,
|
||||
Param,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Req,
|
||||
} from '@nestjs/common';
|
||||
import { Controller, Get, UseGuards, Param, Req } from '@nestjs/common';
|
||||
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||
import { UnitPermissionGuard } from 'src/guards/unit.permission.guard';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
|
||||
@ApiTags('Group Module')
|
||||
@Controller({
|
||||
version: '1',
|
||||
version: EnableDisableStatusEnum.ENABLED,
|
||||
path: 'group',
|
||||
})
|
||||
export class GroupController {
|
||||
@ -24,14 +17,7 @@ export class GroupController {
|
||||
@UseGuards(JwtAuthGuard, UnitPermissionGuard)
|
||||
@Get(':unitUuid')
|
||||
async getGroupsBySpaceUuid(@Param('unitUuid') unitUuid: string) {
|
||||
try {
|
||||
return await this.groupService.getGroupsByUnitUuid(unitUuid);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.groupService.getGroupsByUnitUuid(unitUuid);
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, UnitPermissionGuard)
|
||||
@ -41,19 +27,12 @@ export class GroupController {
|
||||
@Param('groupName') groupName: string,
|
||||
@Req() req: any,
|
||||
) {
|
||||
try {
|
||||
const userUuid = req.user.uuid;
|
||||
const userUuid = req.user.uuid;
|
||||
|
||||
return await this.groupService.getUnitDevicesByGroupName(
|
||||
unitUuid,
|
||||
groupName,
|
||||
userUuid,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.groupService.getUnitDevicesByGroupName(
|
||||
unitUuid,
|
||||
groupName,
|
||||
userUuid,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter';
|
||||
import { ProductRepository } from '@app/common/modules/product/repositories';
|
||||
import { PermissionType } from '@app/common/constants/permission-type.enum';
|
||||
import { In } from 'typeorm';
|
||||
import { ProductType } from '@app/common/constants/product-type.enum';
|
||||
|
||||
@Injectable()
|
||||
export class GroupService {
|
||||
@ -44,8 +45,24 @@ export class GroupService {
|
||||
});
|
||||
|
||||
const uniqueGroupNames = [...new Set(groupNames)];
|
||||
|
||||
return uniqueGroupNames.map((groupName) => ({ groupName }));
|
||||
const groups = uniqueGroupNames.map((groupName) => ({
|
||||
groupName: groupName as ProductType,
|
||||
}));
|
||||
const allowedProductTypes = [
|
||||
ProductType.ONE_1TG,
|
||||
ProductType.TWO_2TG,
|
||||
ProductType.THREE_3TG,
|
||||
ProductType.THREE_G,
|
||||
ProductType.TWO_G,
|
||||
ProductType.ONE_G,
|
||||
ProductType.GD,
|
||||
ProductType.WH,
|
||||
ProductType.AC,
|
||||
ProductType.CUR,
|
||||
];
|
||||
return groups.filter((group) =>
|
||||
allowedProductTypes.includes(group.groupName),
|
||||
);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
'This unit does not have any groups',
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
import { SpacePermissionService } from '@app/common/helper/services/space.permission.service';
|
||||
import {
|
||||
BadRequestException,
|
||||
@ -24,7 +25,7 @@ export class BuildingPermissionGuard implements CanActivate {
|
||||
await this.permissionService.checkUserPermission(
|
||||
buildingUuid,
|
||||
user.uuid,
|
||||
'building',
|
||||
SpaceType.BUILDING,
|
||||
);
|
||||
|
||||
return true;
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||
import {
|
||||
Injectable,
|
||||
@ -42,7 +43,7 @@ export class CheckBuildingTypeGuard implements CanActivate {
|
||||
if (
|
||||
!buildingData ||
|
||||
!buildingData.spaceType ||
|
||||
buildingData.spaceType.type !== 'building'
|
||||
buildingData.spaceType.type !== SpaceType.BUILDING
|
||||
) {
|
||||
throw new BadRequestException('Invalid building UUID');
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
import { SpacePermissionService } from '@app/common/helper/services/space.permission.service';
|
||||
import {
|
||||
BadRequestException,
|
||||
@ -24,7 +25,7 @@ export class CommunityPermissionGuard implements CanActivate {
|
||||
await this.permissionService.checkUserPermission(
|
||||
communityUuid,
|
||||
user.uuid,
|
||||
'community',
|
||||
SpaceType.COMMUNITY,
|
||||
);
|
||||
|
||||
return true;
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
} from '@nestjs/common';
|
||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
|
||||
@Injectable()
|
||||
export class CheckCommunityTypeGuard implements CanActivate {
|
||||
@ -43,7 +44,7 @@ export class CheckCommunityTypeGuard implements CanActivate {
|
||||
if (
|
||||
!communityData ||
|
||||
!communityData.spaceType ||
|
||||
communityData.spaceType.type !== 'community'
|
||||
communityData.spaceType.type !== SpaceType.COMMUNITY
|
||||
) {
|
||||
throw new BadRequestException('Invalid community UUID');
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ export class CheckProductUuidForAllDevicesGuard implements CanActivate {
|
||||
|
||||
async checkAllDevicesHaveSameProductUuid(deviceUuids: string[]) {
|
||||
const firstDevice = await this.deviceRepository.findOne({
|
||||
where: { uuid: deviceUuids[0] },
|
||||
where: { uuid: deviceUuids[0], isActive: true },
|
||||
relations: ['productDevice'],
|
||||
});
|
||||
|
||||
@ -40,7 +40,7 @@ export class CheckProductUuidForAllDevicesGuard implements CanActivate {
|
||||
|
||||
for (let i = 1; i < deviceUuids.length; i++) {
|
||||
const device = await this.deviceRepository.findOne({
|
||||
where: { uuid: deviceUuids[i] },
|
||||
where: { uuid: deviceUuids[i], isActive: true },
|
||||
relations: ['productDevice'],
|
||||
});
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
import { SpacePermissionService } from '@app/common/helper/services/space.permission.service';
|
||||
import {
|
||||
BadRequestException,
|
||||
@ -24,7 +25,7 @@ export class FloorPermissionGuard implements CanActivate {
|
||||
await this.permissionService.checkUserPermission(
|
||||
floorUuid,
|
||||
user.uuid,
|
||||
'floor',
|
||||
SpaceType.FLOOR,
|
||||
);
|
||||
|
||||
return true;
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||
import {
|
||||
Injectable,
|
||||
@ -42,7 +43,7 @@ export class CheckFloorTypeGuard implements CanActivate {
|
||||
if (
|
||||
!floorData ||
|
||||
!floorData.spaceType ||
|
||||
floorData.spaceType.type !== 'floor'
|
||||
floorData.spaceType.type !== SpaceType.FLOOR
|
||||
) {
|
||||
throw new BadRequestException('Invalid floor UUID');
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import {
|
||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
|
||||
@Injectable()
|
||||
export class CheckRoomGuard implements CanActivate {
|
||||
@ -43,7 +44,7 @@ export class CheckRoomGuard implements CanActivate {
|
||||
where: {
|
||||
uuid: roomUuid,
|
||||
spaceType: {
|
||||
type: 'room',
|
||||
type: SpaceType.ROOM,
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -55,6 +56,7 @@ export class CheckRoomGuard implements CanActivate {
|
||||
const response = await this.deviceRepository.findOne({
|
||||
where: {
|
||||
uuid: deviceUuid,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
import { SpacePermissionService } from '@app/common/helper/services/space.permission.service';
|
||||
import {
|
||||
BadRequestException,
|
||||
@ -24,7 +25,7 @@ export class RoomPermissionGuard implements CanActivate {
|
||||
await this.permissionService.checkUserPermission(
|
||||
roomUuid,
|
||||
user.uuid,
|
||||
'room',
|
||||
SpaceType.ROOM,
|
||||
);
|
||||
|
||||
return true;
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
import { SpacePermissionService } from '@app/common/helper/services/space.permission.service';
|
||||
import {
|
||||
BadRequestException,
|
||||
@ -24,7 +25,7 @@ export class UnitPermissionGuard implements CanActivate {
|
||||
await this.permissionService.checkUserPermission(
|
||||
unitUuid,
|
||||
user.uuid,
|
||||
'unit',
|
||||
SpaceType.UNIT,
|
||||
);
|
||||
|
||||
return true;
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||
import {
|
||||
Injectable,
|
||||
@ -42,7 +43,7 @@ export class CheckUnitTypeGuard implements CanActivate {
|
||||
if (
|
||||
!unitData ||
|
||||
!unitData.spaceType ||
|
||||
unitData.spaceType.type !== 'unit'
|
||||
unitData.spaceType.type !== SpaceType.UNIT
|
||||
) {
|
||||
throw new BadRequestException('Invalid unit UUID');
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import {
|
||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||
import { UserRepository } from '@app/common/modules/user/repositories';
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
|
||||
@Injectable()
|
||||
export class CheckUserBuildingGuard implements CanActivate {
|
||||
@ -43,7 +44,7 @@ export class CheckUserBuildingGuard implements CanActivate {
|
||||
|
||||
private async checkBuildingIsFound(spaceUuid: string) {
|
||||
const spaceData = await this.spaceRepository.findOne({
|
||||
where: { uuid: spaceUuid, spaceType: { type: 'building' } },
|
||||
where: { uuid: spaceUuid, spaceType: { type: SpaceType.BUILDING } },
|
||||
relations: ['spaceType'],
|
||||
});
|
||||
if (!spaceData) {
|
||||
|
||||
@ -7,6 +7,7 @@ import {
|
||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||
import { UserRepository } from '@app/common/modules/user/repositories';
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
|
||||
@Injectable()
|
||||
export class CheckUserCommunityGuard implements CanActivate {
|
||||
@ -43,7 +44,7 @@ export class CheckUserCommunityGuard implements CanActivate {
|
||||
|
||||
private async checkCommunityIsFound(spaceUuid: string) {
|
||||
const spaceData = await this.spaceRepository.findOne({
|
||||
where: { uuid: spaceUuid, spaceType: { type: 'community' } },
|
||||
where: { uuid: spaceUuid, spaceType: { type: SpaceType.COMMUNITY } },
|
||||
relations: ['spaceType'],
|
||||
});
|
||||
if (!spaceData) {
|
||||
|
||||
@ -58,7 +58,11 @@ export class CheckUserHaveControllablePermission implements CanActivate {
|
||||
deviceUuid: string,
|
||||
): Promise<string> {
|
||||
const device = await this.deviceRepository.findOne({
|
||||
where: { uuid: deviceUuid, permission: { userUuid: userUuid } },
|
||||
where: {
|
||||
uuid: deviceUuid,
|
||||
isActive: true,
|
||||
permission: { userUuid: userUuid },
|
||||
},
|
||||
relations: ['permission', 'permission.permissionType'],
|
||||
});
|
||||
|
||||
|
||||
@ -59,7 +59,11 @@ export class CheckUserHavePermission implements CanActivate {
|
||||
deviceUuid: string,
|
||||
): Promise<string> {
|
||||
const device = await this.deviceRepository.findOne({
|
||||
where: { uuid: deviceUuid, permission: { userUuid: userUuid } },
|
||||
where: {
|
||||
uuid: deviceUuid,
|
||||
permission: { userUuid: userUuid },
|
||||
isActive: true,
|
||||
},
|
||||
relations: ['permission', 'permission.permissionType'],
|
||||
});
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ import {
|
||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||
import { UserRepository } from '@app/common/modules/user/repositories';
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
|
||||
@Injectable()
|
||||
export class CheckUserFloorGuard implements CanActivate {
|
||||
@ -43,7 +44,7 @@ export class CheckUserFloorGuard implements CanActivate {
|
||||
|
||||
private async checkFloorIsFound(spaceUuid: string) {
|
||||
const spaceData = await this.spaceRepository.findOne({
|
||||
where: { uuid: spaceUuid, spaceType: { type: 'floor' } },
|
||||
where: { uuid: spaceUuid, spaceType: { type: SpaceType.FLOOR } },
|
||||
relations: ['spaceType'],
|
||||
});
|
||||
if (!spaceData) {
|
||||
|
||||
@ -7,6 +7,7 @@ import {
|
||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||
import { UserRepository } from '@app/common/modules/user/repositories';
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
|
||||
@Injectable()
|
||||
export class CheckUserRoomGuard implements CanActivate {
|
||||
@ -43,7 +44,7 @@ export class CheckUserRoomGuard implements CanActivate {
|
||||
|
||||
private async checkRoomIsFound(spaceUuid: string) {
|
||||
const spaceData = await this.spaceRepository.findOne({
|
||||
where: { uuid: spaceUuid, spaceType: { type: 'room' } },
|
||||
where: { uuid: spaceUuid, spaceType: { type: SpaceType.ROOM } },
|
||||
relations: ['spaceType'],
|
||||
});
|
||||
if (!spaceData) {
|
||||
|
||||
@ -7,6 +7,7 @@ import {
|
||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||
import { UserRepository } from '@app/common/modules/user/repositories';
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
|
||||
@Injectable()
|
||||
export class CheckUserUnitGuard implements CanActivate {
|
||||
@ -43,7 +44,7 @@ export class CheckUserUnitGuard implements CanActivate {
|
||||
|
||||
private async checkUnitIsFound(spaceUuid: string) {
|
||||
const spaceData = await this.spaceRepository.findOne({
|
||||
where: { uuid: spaceUuid, spaceType: { type: 'unit' } },
|
||||
where: { uuid: spaceUuid, spaceType: { type: SpaceType.UNIT } },
|
||||
relations: ['spaceType'],
|
||||
});
|
||||
if (!spaceData) {
|
||||
|
||||
@ -6,6 +6,7 @@ import { setupSwaggerAuthentication } from '../libs/common/src/util/user-auth.sw
|
||||
import { ValidationPipe } from '@nestjs/common';
|
||||
import { json, urlencoded } from 'body-parser';
|
||||
import { SeederService } from '@app/common/seed/services/seeder.service';
|
||||
import { HttpExceptionFilter } from './common/filters/http-exception/http-exception.filter';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
@ -15,6 +16,7 @@ async function bootstrap() {
|
||||
// Set the body parser limit to 1 MB
|
||||
app.use(json({ limit: '1mb' }));
|
||||
app.use(urlencoded({ limit: '1mb', extended: true }));
|
||||
app.useGlobalFilters(new HttpExceptionFilter());
|
||||
|
||||
app.use(
|
||||
rateLimit({
|
||||
|
||||
@ -1,24 +1,23 @@
|
||||
import { Controller, Get, HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { Controller, Get } from '@nestjs/common';
|
||||
import { RegionService } from '../services/region.service';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
import { ApiTags, ApiOperation } from '@nestjs/swagger';
|
||||
import { ControllerRoute } from '@app/common/constants/controller-route';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
|
||||
@ApiTags('Region Module')
|
||||
@Controller({
|
||||
version: '1',
|
||||
path: 'region',
|
||||
version: EnableDisableStatusEnum.ENABLED,
|
||||
path: ControllerRoute.REGION.ROUTE,
|
||||
})
|
||||
export class RegionController {
|
||||
constructor(private readonly regionService: RegionService) {}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({
|
||||
summary: ControllerRoute.REGION.ACTIONS.GET_REGIONS_SUMMARY,
|
||||
description: ControllerRoute.REGION.ACTIONS.GET_REGIONS_DESCRIPTION,
|
||||
})
|
||||
async getAllRegions() {
|
||||
try {
|
||||
return await this.regionService.getAllRegions();
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.regionService.getAllRegions();
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,9 +3,10 @@ import { RegionService } from './services/region.service';
|
||||
import { RegionController } from './controllers/region.controller';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { RegionRepository } from '@app/common/modules/region/repositories';
|
||||
import { CommonModule } from '@app/common';
|
||||
|
||||
@Module({
|
||||
imports: [ConfigModule],
|
||||
imports: [ConfigModule, CommonModule],
|
||||
controllers: [RegionController],
|
||||
providers: [RegionService, RegionRepository],
|
||||
exports: [RegionService],
|
||||
|
||||
@ -2,23 +2,33 @@ import {
|
||||
BadRequestException,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Inject,
|
||||
Injectable,
|
||||
} from '@nestjs/common';
|
||||
import { RegionRepository } from '@app/common/modules/region/repositories';
|
||||
import { ErrorMessageService } from 'src/error-message/error-message.service';
|
||||
|
||||
@Injectable()
|
||||
export class RegionService {
|
||||
constructor(private readonly regionRepository: RegionRepository) {}
|
||||
constructor(
|
||||
private readonly regionRepository: RegionRepository,
|
||||
@Inject(ErrorMessageService)
|
||||
private readonly errorMessageService: ErrorMessageService,
|
||||
) {}
|
||||
async getAllRegions() {
|
||||
try {
|
||||
const regions = await this.regionRepository.find();
|
||||
|
||||
return regions;
|
||||
} catch (err) {
|
||||
if (err instanceof BadRequestException) {
|
||||
throw err; // Re-throw BadRequestException
|
||||
} else {
|
||||
throw new HttpException('Regions found', HttpStatus.NOT_FOUND);
|
||||
throw new HttpException(
|
||||
this.errorMessageService.getMessage('NOT_FOUND', {
|
||||
entity: 'Regions',
|
||||
}),
|
||||
HttpStatus.NOT_FOUND,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,6 @@ import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Post,
|
||||
UseGuards,
|
||||
@ -11,10 +10,11 @@ import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
||||
import { RoleService } from '../services/role.service';
|
||||
import { AddUserRoleDto } from '../dtos';
|
||||
import { SuperAdminRoleGuard } from 'src/guards/super.admin.role.guard';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
|
||||
@ApiTags('Role Module')
|
||||
@Controller({
|
||||
version: '1',
|
||||
version: EnableDisableStatusEnum.ENABLED,
|
||||
path: 'role',
|
||||
})
|
||||
export class RoleController {
|
||||
@ -23,32 +23,21 @@ export class RoleController {
|
||||
@UseGuards(SuperAdminRoleGuard)
|
||||
@Get('types')
|
||||
async fetchRoleTypes() {
|
||||
try {
|
||||
const roleTypes = await this.roleService.fetchRoleTypes();
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'Role Types fetched Successfully',
|
||||
data: roleTypes,
|
||||
};
|
||||
} catch (err) {
|
||||
throw new Error(err);
|
||||
}
|
||||
const roleTypes = await this.roleService.fetchRoleTypes();
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'Role Types fetched Successfully',
|
||||
data: roleTypes,
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(SuperAdminRoleGuard)
|
||||
@Post()
|
||||
async addUserRoleType(@Body() addUserRoleDto: AddUserRoleDto) {
|
||||
try {
|
||||
await this.roleService.addUserRoleType(addUserRoleDto);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'User Role Added Successfully',
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
await this.roleService.addUserRoleType(addUserRoleDto);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'User Role Added Successfully',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { AddUserRoleDto } from '../dtos/role.add.dto';
|
||||
import { UserRoleRepository } from '@app/common/modules/user/repositories';
|
||||
import { QueryFailedError } from 'typeorm';
|
||||
import { CommonErrorCodes } from '@app/common/constants/error-codes.enum';
|
||||
|
||||
@Injectable()
|
||||
export class RoleService {
|
||||
@ -24,7 +25,7 @@ export class RoleService {
|
||||
} catch (error) {
|
||||
if (
|
||||
error instanceof QueryFailedError &&
|
||||
error.driverError.code === '23505'
|
||||
error.driverError.code === CommonErrorCodes.DUPLICATE_ENTITY
|
||||
) {
|
||||
// Postgres unique constraint violation error code
|
||||
throw new HttpException(
|
||||
|
||||
@ -3,7 +3,6 @@ import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Post,
|
||||
@ -18,11 +17,13 @@ import { CheckUserRoomGuard } from 'src/guards/user.room.guard';
|
||||
import { AdminRoleGuard } from 'src/guards/admin.role.guard';
|
||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||
import { RoomPermissionGuard } from 'src/guards/room.permission.guard';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
|
||||
@ApiTags('Room Module')
|
||||
@Controller({
|
||||
version: '1',
|
||||
path: 'room',
|
||||
version: EnableDisableStatusEnum.ENABLED,
|
||||
path: SpaceType.ROOM,
|
||||
})
|
||||
export class RoomController {
|
||||
constructor(private readonly roomService: RoomService) {}
|
||||
@ -31,101 +32,59 @@ export class RoomController {
|
||||
@UseGuards(JwtAuthGuard, CheckUnitTypeGuard)
|
||||
@Post()
|
||||
async addRoom(@Body() addRoomDto: AddRoomDto) {
|
||||
try {
|
||||
const room = await this.roomService.addRoom(addRoomDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Room added successfully',
|
||||
data: room,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const room = await this.roomService.addRoom(addRoomDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Room added successfully',
|
||||
data: room,
|
||||
};
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, RoomPermissionGuard)
|
||||
@Get(':roomUuid')
|
||||
async getRoomByUuid(@Param('roomUuid') roomUuid: string) {
|
||||
try {
|
||||
const room = await this.roomService.getRoomByUuid(roomUuid);
|
||||
return room;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const room = await this.roomService.getRoomByUuid(roomUuid);
|
||||
return room;
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, RoomPermissionGuard)
|
||||
@Get('parent/:roomUuid')
|
||||
async getRoomParentByUuid(@Param('roomUuid') roomUuid: string) {
|
||||
try {
|
||||
const room = await this.roomService.getRoomParentByUuid(roomUuid);
|
||||
return room;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const room = await this.roomService.getRoomParentByUuid(roomUuid);
|
||||
return room;
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(AdminRoleGuard, CheckUserRoomGuard)
|
||||
@Post('user')
|
||||
async addUserRoom(@Body() addUserRoomDto: AddUserRoomDto) {
|
||||
try {
|
||||
await this.roomService.addUserRoom(addUserRoomDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'user room added successfully',
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
await this.roomService.addUserRoom(addUserRoomDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'user room added successfully',
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('user/:userUuid')
|
||||
async getRoomsByUserId(@Param('userUuid') userUuid: string) {
|
||||
try {
|
||||
return await this.roomService.getRoomsByUserId(userUuid);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.roomService.getRoomsByUserId(userUuid);
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, RoomPermissionGuard)
|
||||
@Put('rename/:roomUuid')
|
||||
@Put(':roomUuid')
|
||||
async renameRoomByUuid(
|
||||
@Param('roomUuid') roomUuid: string,
|
||||
@Body() updateRoomNameDto: UpdateRoomNameDto,
|
||||
) {
|
||||
try {
|
||||
const room = await this.roomService.renameRoomByUuid(
|
||||
roomUuid,
|
||||
updateRoomNameDto,
|
||||
);
|
||||
return room;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const room = await this.roomService.renameRoomByUuid(
|
||||
roomUuid,
|
||||
updateRoomNameDto,
|
||||
);
|
||||
return room;
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,6 +15,8 @@ import {
|
||||
} from '../interface/room.interface';
|
||||
import { UpdateRoomNameDto } from '../dtos/update.room.dto';
|
||||
import { UserSpaceRepository } from '@app/common/modules/user/repositories';
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
import { CommonErrorCodes } from '@app/common/constants/error-codes.enum';
|
||||
|
||||
@Injectable()
|
||||
export class RoomService {
|
||||
@ -28,7 +30,7 @@ export class RoomService {
|
||||
try {
|
||||
const spaceType = await this.spaceTypeRepository.findOne({
|
||||
where: {
|
||||
type: 'room',
|
||||
type: SpaceType.ROOM,
|
||||
},
|
||||
});
|
||||
|
||||
@ -49,12 +51,12 @@ export class RoomService {
|
||||
where: {
|
||||
uuid: roomUuid,
|
||||
spaceType: {
|
||||
type: 'room',
|
||||
type: SpaceType.ROOM,
|
||||
},
|
||||
},
|
||||
relations: ['spaceType'],
|
||||
});
|
||||
if (!room || !room.spaceType || room.spaceType.type !== 'room') {
|
||||
if (!room || !room.spaceType || room.spaceType.type !== SpaceType.ROOM) {
|
||||
throw new BadRequestException('Invalid room UUID');
|
||||
}
|
||||
|
||||
@ -80,12 +82,12 @@ export class RoomService {
|
||||
where: {
|
||||
uuid: roomUuid,
|
||||
spaceType: {
|
||||
type: 'room',
|
||||
type: SpaceType.ROOM,
|
||||
},
|
||||
},
|
||||
relations: ['spaceType', 'parent', 'parent.spaceType'],
|
||||
});
|
||||
if (!room || !room.spaceType || room.spaceType.type !== 'room') {
|
||||
if (!room || !room.spaceType || room.spaceType.type !== SpaceType.ROOM) {
|
||||
throw new BadRequestException('Invalid room UUID');
|
||||
}
|
||||
|
||||
@ -116,7 +118,7 @@ export class RoomService {
|
||||
relations: ['space', 'space.spaceType'],
|
||||
where: {
|
||||
user: { uuid: userUuid },
|
||||
space: { spaceType: { type: 'room' } },
|
||||
space: { spaceType: { type: SpaceType.ROOM } },
|
||||
},
|
||||
});
|
||||
|
||||
@ -145,7 +147,7 @@ export class RoomService {
|
||||
space: { uuid: addUserRoomDto.roomUuid },
|
||||
});
|
||||
} catch (err) {
|
||||
if (err.code === '23505') {
|
||||
if (err.code === CommonErrorCodes.DUPLICATE_ENTITY) {
|
||||
throw new HttpException(
|
||||
'User already belongs to this room',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
@ -167,7 +169,7 @@ export class RoomService {
|
||||
relations: ['spaceType'],
|
||||
});
|
||||
|
||||
if (!room || !room.spaceType || room.spaceType.type !== 'room') {
|
||||
if (!room || !room.spaceType || room.spaceType.type !== SpaceType.ROOM) {
|
||||
throw new BadRequestException('Invalid room UUID');
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,6 @@ import {
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Post,
|
||||
@ -14,10 +13,11 @@ import {
|
||||
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { AddSceneTapToRunDto, UpdateSceneTapToRunDto } from '../dtos/scene.dto';
|
||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
|
||||
@ApiTags('Scene Module')
|
||||
@Controller({
|
||||
version: '1',
|
||||
version: EnableDisableStatusEnum.ENABLED,
|
||||
path: 'scene',
|
||||
})
|
||||
export class SceneController {
|
||||
@ -27,36 +27,22 @@ export class SceneController {
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('tap-to-run')
|
||||
async addTapToRunScene(@Body() addSceneTapToRunDto: AddSceneTapToRunDto) {
|
||||
try {
|
||||
const tapToRunScene =
|
||||
await this.sceneService.addTapToRunScene(addSceneTapToRunDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Scene added successfully',
|
||||
data: tapToRunScene,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const tapToRunScene =
|
||||
await this.sceneService.addTapToRunScene(addSceneTapToRunDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Scene added successfully',
|
||||
data: tapToRunScene,
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('tap-to-run/:unitUuid')
|
||||
async getTapToRunSceneByUnit(@Param('unitUuid') unitUuid: string) {
|
||||
try {
|
||||
const tapToRunScenes =
|
||||
await this.sceneService.getTapToRunSceneByUnit(unitUuid);
|
||||
return tapToRunScenes;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const tapToRunScenes =
|
||||
await this.sceneService.getTapToRunSceneByUnit(unitUuid);
|
||||
return tapToRunScenes;
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ -65,53 +51,31 @@ export class SceneController {
|
||||
@Param('unitUuid') unitUuid: string,
|
||||
@Param('sceneId') sceneId: string,
|
||||
) {
|
||||
try {
|
||||
await this.sceneService.deleteTapToRunScene(unitUuid, sceneId);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'Scene Deleted Successfully',
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
await this.sceneService.deleteTapToRunScene(unitUuid, sceneId);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'Scene Deleted Successfully',
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post('tap-to-run/trigger/:sceneId')
|
||||
async triggerTapToRunScene(@Param('sceneId') sceneId: string) {
|
||||
try {
|
||||
await this.sceneService.triggerTapToRunScene(sceneId);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Scene trigger successfully',
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
await this.sceneService.triggerTapToRunScene(sceneId);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Scene trigger successfully',
|
||||
};
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('tap-to-run/details/:sceneId')
|
||||
async getTapToRunSceneDetails(@Param('sceneId') sceneId: string) {
|
||||
try {
|
||||
const tapToRunScenes =
|
||||
await this.sceneService.getTapToRunSceneDetails(sceneId);
|
||||
return tapToRunScenes;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
``;
|
||||
}
|
||||
const tapToRunScenes =
|
||||
await this.sceneService.getTapToRunSceneDetails(sceneId);
|
||||
return tapToRunScenes;
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ -120,22 +84,15 @@ export class SceneController {
|
||||
@Body() updateSceneTapToRunDto: UpdateSceneTapToRunDto,
|
||||
@Param('sceneId') sceneId: string,
|
||||
) {
|
||||
try {
|
||||
const tapToRunScene = await this.sceneService.updateTapToRunScene(
|
||||
updateSceneTapToRunDto,
|
||||
sceneId,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Scene updated successfully',
|
||||
data: tapToRunScene,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const tapToRunScene = await this.sceneService.updateTapToRunScene(
|
||||
updateSceneTapToRunDto,
|
||||
sceneId,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Scene updated successfully',
|
||||
data: tapToRunScene,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,6 +18,8 @@ import {
|
||||
SceneDetailsResult,
|
||||
} from '../interface/scene.interface';
|
||||
import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter';
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
import { ActionExecutorEnum } from '@app/common/constants/automation.enum';
|
||||
|
||||
@Injectable()
|
||||
export class SceneService {
|
||||
@ -63,7 +65,7 @@ export class SceneService {
|
||||
|
||||
const convertedData = convertKeysToSnakeCase(actions);
|
||||
for (const action of convertedData) {
|
||||
if (action.action_executor === 'device_issue') {
|
||||
if (action.action_executor === ActionExecutorEnum.DEVICE_ISSUE) {
|
||||
const device = await this.deviceService.getDeviceByDeviceUuid(
|
||||
action.entity_id,
|
||||
false,
|
||||
@ -108,12 +110,12 @@ export class SceneService {
|
||||
where: {
|
||||
uuid: unitUuid,
|
||||
spaceType: {
|
||||
type: 'unit',
|
||||
type: SpaceType.UNIT,
|
||||
},
|
||||
},
|
||||
relations: ['spaceType'],
|
||||
});
|
||||
if (!unit || !unit.spaceType || unit.spaceType.type !== 'unit') {
|
||||
if (!unit || !unit.spaceType || unit.spaceType.type !== SpaceType.UNIT) {
|
||||
throw new BadRequestException('Invalid unit UUID');
|
||||
}
|
||||
return {
|
||||
@ -249,7 +251,7 @@ export class SceneService {
|
||||
});
|
||||
|
||||
for (const action of actions) {
|
||||
if (action.actionExecutor === 'device_issue') {
|
||||
if (action.actionExecutor === ActionExecutorEnum.DEVICE_ISSUE) {
|
||||
const device = await this.deviceService.getDeviceByDeviceTuyaUuid(
|
||||
action.entityId,
|
||||
);
|
||||
@ -258,8 +260,8 @@ export class SceneService {
|
||||
action.entityId = device.uuid;
|
||||
}
|
||||
} else if (
|
||||
action.actionExecutor !== 'device_issue' &&
|
||||
action.actionExecutor !== 'delay'
|
||||
action.actionExecutor !== ActionExecutorEnum.DEVICE_ISSUE &&
|
||||
action.actionExecutor !== ActionExecutorEnum.DELAY
|
||||
) {
|
||||
const sceneDetails = await this.getTapToRunSceneDetailsTuya(
|
||||
action.entityId,
|
||||
|
||||
1
src/schedule/controllers/index.ts
Normal file
1
src/schedule/controllers/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './schedule.controller';
|
||||
113
src/schedule/controllers/schedule.controller.ts
Normal file
113
src/schedule/controllers/schedule.controller.ts
Normal file
@ -0,0 +1,113 @@
|
||||
import { ScheduleService } from '../services/schedule.service';
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Param,
|
||||
HttpStatus,
|
||||
UseGuards,
|
||||
Put,
|
||||
Delete,
|
||||
Query,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import {
|
||||
AddScheduleDto,
|
||||
EnableScheduleDto,
|
||||
GetScheduleDeviceDto,
|
||||
UpdateScheduleDto,
|
||||
} from '../dtos/schedule.dto';
|
||||
|
||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
|
||||
@ApiTags('Schedule Module')
|
||||
@Controller({
|
||||
version: EnableDisableStatusEnum.ENABLED,
|
||||
path: 'schedule',
|
||||
})
|
||||
export class ScheduleController {
|
||||
constructor(private readonly scheduleService: ScheduleService) {}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post(':deviceUuid')
|
||||
async addDeviceSchedule(
|
||||
@Param('deviceUuid') deviceUuid: string,
|
||||
@Body() addScheduleDto: AddScheduleDto,
|
||||
) {
|
||||
const schedule = await this.scheduleService.addDeviceSchedule(
|
||||
deviceUuid,
|
||||
addScheduleDto,
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'schedule added successfully',
|
||||
data: schedule,
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get(':deviceUuid')
|
||||
async getDeviceScheduleByCategory(
|
||||
@Param('deviceUuid') deviceUuid: string,
|
||||
@Query() query: GetScheduleDeviceDto,
|
||||
) {
|
||||
return await this.scheduleService.getDeviceScheduleByCategory(
|
||||
deviceUuid,
|
||||
query.category,
|
||||
);
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Delete(':deviceUuid/:scheduleId')
|
||||
async deleteDeviceSchedule(
|
||||
@Param('deviceUuid') deviceUuid: string,
|
||||
@Param('scheduleId') scheduleId: string,
|
||||
) {
|
||||
await this.scheduleService.deleteDeviceSchedule(deviceUuid, scheduleId);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'schedule deleted successfully',
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Put('enable/:deviceUuid')
|
||||
async enableDeviceSchedule(
|
||||
@Param('deviceUuid') deviceUuid: string,
|
||||
@Body() enableScheduleDto: EnableScheduleDto,
|
||||
) {
|
||||
await this.scheduleService.enableDeviceSchedule(
|
||||
deviceUuid,
|
||||
enableScheduleDto,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'schedule updated successfully',
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Put(':deviceUuid')
|
||||
async updateDeviceSchedule(
|
||||
@Param('deviceUuid') deviceUuid: string,
|
||||
@Body() updateScheduleDto: UpdateScheduleDto,
|
||||
) {
|
||||
const schedule = await this.scheduleService.updateDeviceSchedule(
|
||||
deviceUuid,
|
||||
updateScheduleDto,
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'schedule updated successfully',
|
||||
data: schedule,
|
||||
};
|
||||
}
|
||||
}
|
||||
1
src/schedule/dtos/index.ts
Normal file
1
src/schedule/dtos/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './schedule.dto';
|
||||
138
src/schedule/dtos/schedule.dto.ts
Normal file
138
src/schedule/dtos/schedule.dto.ts
Normal file
@ -0,0 +1,138 @@
|
||||
import { WorkingDays } from '@app/common/constants/working-days';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Type } from 'class-transformer';
|
||||
import {
|
||||
IsArray,
|
||||
IsBoolean,
|
||||
IsEnum,
|
||||
IsNotEmpty,
|
||||
IsString,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
export class FunctionDto {
|
||||
@ApiProperty({
|
||||
description: 'code',
|
||||
required: true,
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public code: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'value',
|
||||
required: true,
|
||||
})
|
||||
@IsNotEmpty()
|
||||
public value: any;
|
||||
}
|
||||
|
||||
// Update the main DTO class
|
||||
export class AddScheduleDto {
|
||||
@ApiProperty({
|
||||
description: 'category',
|
||||
required: true,
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public category: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'time',
|
||||
required: true,
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public time: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'function',
|
||||
required: true,
|
||||
type: FunctionDto,
|
||||
})
|
||||
@ValidateNested()
|
||||
@Type(() => FunctionDto)
|
||||
public function: FunctionDto;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'days',
|
||||
enum: WorkingDays,
|
||||
isArray: true,
|
||||
required: true,
|
||||
})
|
||||
@IsArray()
|
||||
@IsEnum(WorkingDays, { each: true })
|
||||
@IsNotEmpty()
|
||||
public days: WorkingDays[];
|
||||
}
|
||||
|
||||
export class EnableScheduleDto {
|
||||
@ApiProperty({
|
||||
description: 'scheduleId',
|
||||
required: true,
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public scheduleId: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'enable',
|
||||
required: true,
|
||||
})
|
||||
@IsBoolean()
|
||||
@IsNotEmpty()
|
||||
public enable: boolean;
|
||||
}
|
||||
export class GetScheduleDeviceDto {
|
||||
@ApiProperty({
|
||||
description: 'category',
|
||||
required: true,
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public category: string;
|
||||
}
|
||||
|
||||
export class UpdateScheduleDto {
|
||||
@ApiProperty({
|
||||
description: 'scheduleId',
|
||||
required: true,
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public scheduleId: string;
|
||||
@ApiProperty({
|
||||
description: 'category',
|
||||
required: true,
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public category: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'time',
|
||||
required: true,
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public time: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'function',
|
||||
required: true,
|
||||
type: FunctionDto,
|
||||
})
|
||||
@ValidateNested()
|
||||
@Type(() => FunctionDto)
|
||||
public function: FunctionDto;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'days',
|
||||
enum: WorkingDays,
|
||||
isArray: true,
|
||||
required: true,
|
||||
})
|
||||
@IsArray()
|
||||
@IsEnum(WorkingDays, { each: true })
|
||||
@IsNotEmpty()
|
||||
public days: WorkingDays[];
|
||||
}
|
||||
10
src/schedule/interfaces/get.schedule.interface.ts
Normal file
10
src/schedule/interfaces/get.schedule.interface.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export interface getDeviceScheduleInterface {
|
||||
success: boolean;
|
||||
result: [];
|
||||
msg: string;
|
||||
}
|
||||
export interface addScheduleDeviceInterface {
|
||||
success: boolean;
|
||||
result: boolean;
|
||||
msg: string;
|
||||
}
|
||||
13
src/schedule/schedule.module.ts
Normal file
13
src/schedule/schedule.module.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ScheduleService } from './services/schedule.service';
|
||||
import { ScheduleController } from './controllers/schedule.controller';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { DeviceRepositoryModule } from '@app/common/modules/device';
|
||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||
@Module({
|
||||
imports: [ConfigModule, DeviceRepositoryModule],
|
||||
controllers: [ScheduleController],
|
||||
providers: [ScheduleService, DeviceRepository],
|
||||
exports: [ScheduleService],
|
||||
})
|
||||
export class ScheduleModule {}
|
||||
1
src/schedule/services/index.ts
Normal file
1
src/schedule/services/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './schedule.service';
|
||||
379
src/schedule/services/schedule.service.ts
Normal file
379
src/schedule/services/schedule.service.ts
Normal file
@ -0,0 +1,379 @@
|
||||
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { TuyaContext } from '@tuya/tuya-connector-nodejs';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import {
|
||||
AddScheduleDto,
|
||||
EnableScheduleDto,
|
||||
UpdateScheduleDto,
|
||||
} from '../dtos/schedule.dto';
|
||||
import {
|
||||
addScheduleDeviceInterface,
|
||||
getDeviceScheduleInterface,
|
||||
} from '../interfaces/get.schedule.interface';
|
||||
|
||||
import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter';
|
||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||
import { ProductType } from '@app/common/constants/product-type.enum';
|
||||
import { convertTimestampToDubaiTime } from '@app/common/helper/convertTimestampToDubaiTime';
|
||||
import {
|
||||
getEnabledDays,
|
||||
getScheduleStatus,
|
||||
} from '@app/common/helper/getScheduleStatus';
|
||||
|
||||
@Injectable()
|
||||
export class ScheduleService {
|
||||
private tuya: TuyaContext;
|
||||
constructor(
|
||||
private readonly configService: ConfigService,
|
||||
private readonly deviceRepository: DeviceRepository,
|
||||
) {
|
||||
const accessKey = this.configService.get<string>('auth-config.ACCESS_KEY');
|
||||
const secretKey = this.configService.get<string>('auth-config.SECRET_KEY');
|
||||
const tuyaEuUrl = this.configService.get<string>('tuya-config.TUYA_EU_URL');
|
||||
this.tuya = new TuyaContext({
|
||||
baseUrl: tuyaEuUrl,
|
||||
accessKey,
|
||||
secretKey,
|
||||
});
|
||||
}
|
||||
|
||||
async enableDeviceSchedule(
|
||||
deviceUuid: string,
|
||||
enableScheduleDto: EnableScheduleDto,
|
||||
) {
|
||||
try {
|
||||
const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid);
|
||||
|
||||
if (!deviceDetails || !deviceDetails.deviceTuyaUuid) {
|
||||
throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
// Corrected condition for supported device types
|
||||
if (
|
||||
deviceDetails.productDevice.prodType !== ProductType.THREE_G &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.ONE_G &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.TWO_G &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.WH &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.ONE_1TG &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.TWO_2TG &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.THREE_3TG &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.GD
|
||||
) {
|
||||
throw new HttpException(
|
||||
'This device is not supported for schedule',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
return await this.enableScheduleDeviceInTuya(
|
||||
deviceDetails.deviceTuyaUuid,
|
||||
enableScheduleDto,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Error While Updating Schedule',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
async enableScheduleDeviceInTuya(
|
||||
deviceId: string,
|
||||
enableScheduleDto: EnableScheduleDto,
|
||||
): Promise<addScheduleDeviceInterface> {
|
||||
try {
|
||||
const path = `/v2.0/cloud/timer/device/${deviceId}/state`;
|
||||
const response = await this.tuya.request({
|
||||
method: 'PUT',
|
||||
path,
|
||||
body: {
|
||||
enable: enableScheduleDto.enable,
|
||||
timer_id: enableScheduleDto.scheduleId,
|
||||
},
|
||||
});
|
||||
|
||||
return response as addScheduleDeviceInterface;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
'Error while updating schedule from Tuya',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
async deleteDeviceSchedule(deviceUuid: string, scheduleId: string) {
|
||||
try {
|
||||
const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid);
|
||||
|
||||
if (!deviceDetails || !deviceDetails.deviceTuyaUuid) {
|
||||
throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
// Corrected condition for supported device types
|
||||
if (
|
||||
deviceDetails.productDevice.prodType !== ProductType.THREE_G &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.ONE_G &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.TWO_G &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.WH &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.ONE_1TG &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.TWO_2TG &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.THREE_3TG &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.GD
|
||||
) {
|
||||
throw new HttpException(
|
||||
'This device is not supported for schedule',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
return await this.deleteScheduleDeviceInTuya(
|
||||
deviceDetails.deviceTuyaUuid,
|
||||
scheduleId,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Error While Deleting Schedule',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
async deleteScheduleDeviceInTuya(
|
||||
deviceId: string,
|
||||
scheduleId: string,
|
||||
): Promise<addScheduleDeviceInterface> {
|
||||
try {
|
||||
const path = `/v2.0/cloud/timer/device/${deviceId}/batch?timer_ids=${scheduleId}`;
|
||||
const response = await this.tuya.request({
|
||||
method: 'DELETE',
|
||||
path,
|
||||
});
|
||||
|
||||
return response as addScheduleDeviceInterface;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
'Error while deleting schedule from Tuya',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
async addDeviceSchedule(deviceUuid: string, addScheduleDto: AddScheduleDto) {
|
||||
try {
|
||||
const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid);
|
||||
|
||||
if (!deviceDetails || !deviceDetails.deviceTuyaUuid) {
|
||||
throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
// Corrected condition for supported device types
|
||||
if (
|
||||
deviceDetails.productDevice.prodType !== ProductType.THREE_G &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.ONE_G &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.TWO_G &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.WH &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.ONE_1TG &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.TWO_2TG &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.THREE_3TG &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.GD
|
||||
) {
|
||||
throw new HttpException(
|
||||
'This device is not supported for schedule',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
await this.addScheduleDeviceInTuya(
|
||||
deviceDetails.deviceTuyaUuid,
|
||||
addScheduleDto,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Error While Adding Schedule',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
async addScheduleDeviceInTuya(
|
||||
deviceId: string,
|
||||
addScheduleDto: AddScheduleDto,
|
||||
): Promise<addScheduleDeviceInterface> {
|
||||
try {
|
||||
const convertedTime = convertTimestampToDubaiTime(addScheduleDto.time);
|
||||
const loops = getScheduleStatus(addScheduleDto.days);
|
||||
|
||||
const path = `/v2.0/cloud/timer/device/${deviceId}`;
|
||||
const response = await this.tuya.request({
|
||||
method: 'POST',
|
||||
path,
|
||||
body: {
|
||||
time: convertedTime.time,
|
||||
timezone_id: 'Asia/Dubai',
|
||||
loops: `${loops}`,
|
||||
functions: [
|
||||
{
|
||||
code: addScheduleDto.function.code,
|
||||
value: addScheduleDto.function.value,
|
||||
},
|
||||
],
|
||||
category: `category_${addScheduleDto.category}`,
|
||||
},
|
||||
});
|
||||
|
||||
return response as addScheduleDeviceInterface;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
'Error adding schedule from Tuya',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
async getDeviceScheduleByCategory(deviceUuid: string, category: string) {
|
||||
try {
|
||||
const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid);
|
||||
|
||||
if (!deviceDetails || !deviceDetails.deviceTuyaUuid) {
|
||||
throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
// Corrected condition for supported device types
|
||||
if (
|
||||
deviceDetails.productDevice.prodType !== ProductType.THREE_G &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.ONE_G &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.TWO_G &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.WH &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.ONE_1TG &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.TWO_2TG &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.THREE_3TG &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.GD
|
||||
) {
|
||||
throw new HttpException(
|
||||
'This device is not supported for schedule',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
const schedules = await this.getScheduleDeviceInTuya(
|
||||
deviceDetails.deviceTuyaUuid,
|
||||
category,
|
||||
);
|
||||
const result = schedules.result.map((schedule: any) => {
|
||||
return {
|
||||
category: schedule.category.replace('category_', ''),
|
||||
enable: schedule.enable,
|
||||
function: {
|
||||
code: schedule.functions[0].code,
|
||||
value: schedule.functions[0].value,
|
||||
},
|
||||
time: schedule.time,
|
||||
schedule_id: schedule.timer_id,
|
||||
timezone_id: schedule.timezone_id,
|
||||
days: getEnabledDays(schedule.loops),
|
||||
};
|
||||
});
|
||||
return convertKeysToCamelCase(result);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Error While Adding Schedule',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
async getScheduleDeviceInTuya(
|
||||
deviceId: string,
|
||||
category: string,
|
||||
): Promise<getDeviceScheduleInterface> {
|
||||
try {
|
||||
const path = `/v2.0/cloud/timer/device/${deviceId}?category=category_${category}`;
|
||||
const response = await this.tuya.request({
|
||||
method: 'GET',
|
||||
path,
|
||||
});
|
||||
|
||||
return response as getDeviceScheduleInterface;
|
||||
} catch (error) {
|
||||
console.error('Error fetching device schedule from Tuya:', error);
|
||||
|
||||
throw new HttpException(
|
||||
'Error fetching device schedule from Tuya',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
async getDeviceByDeviceUuid(
|
||||
deviceUuid: string,
|
||||
withProductDevice: boolean = true,
|
||||
) {
|
||||
return await this.deviceRepository.findOne({
|
||||
where: {
|
||||
uuid: deviceUuid,
|
||||
isActive: true,
|
||||
},
|
||||
...(withProductDevice && { relations: ['productDevice'] }),
|
||||
});
|
||||
}
|
||||
async updateDeviceSchedule(
|
||||
deviceUuid: string,
|
||||
updateScheduleDto: UpdateScheduleDto,
|
||||
) {
|
||||
try {
|
||||
const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid);
|
||||
|
||||
if (!deviceDetails || !deviceDetails.deviceTuyaUuid) {
|
||||
throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
// Corrected condition for supported device types
|
||||
if (
|
||||
deviceDetails.productDevice.prodType !== ProductType.THREE_G &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.ONE_G &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.TWO_G &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.WH &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.ONE_1TG &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.TWO_2TG &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.THREE_3TG &&
|
||||
deviceDetails.productDevice.prodType !== ProductType.GD
|
||||
) {
|
||||
throw new HttpException(
|
||||
'This device is not supported for schedule',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
await this.updateScheduleDeviceInTuya(
|
||||
deviceDetails.deviceTuyaUuid,
|
||||
updateScheduleDto,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Error While Updating Schedule',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
async updateScheduleDeviceInTuya(
|
||||
deviceId: string,
|
||||
updateScheduleDto: UpdateScheduleDto,
|
||||
): Promise<addScheduleDeviceInterface> {
|
||||
try {
|
||||
const convertedTime = convertTimestampToDubaiTime(updateScheduleDto.time);
|
||||
const loops = getScheduleStatus(updateScheduleDto.days);
|
||||
|
||||
const path = `/v2.0/cloud/timer/device/${deviceId}`;
|
||||
const response = await this.tuya.request({
|
||||
method: 'PUT',
|
||||
path,
|
||||
body: {
|
||||
timer_id: updateScheduleDto.scheduleId,
|
||||
time: convertedTime.time,
|
||||
timezone_id: 'Asia/Dubai',
|
||||
loops: `${loops}`,
|
||||
functions: [
|
||||
{
|
||||
code: updateScheduleDto.function.code,
|
||||
value: updateScheduleDto.function.value,
|
||||
},
|
||||
],
|
||||
category: `category_${updateScheduleDto.category}`,
|
||||
},
|
||||
});
|
||||
|
||||
return response as addScheduleDeviceInterface;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
'Error updating schedule from Tuya',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,17 +1,12 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { Controller, Get, UseGuards } from '@nestjs/common';
|
||||
import { TimeZoneService } from '../services/timezone.service';
|
||||
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { JwtAuthGuard } from '../../../libs/common/src/guards/jwt.auth.guard';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
|
||||
@ApiTags('TimeZone Module')
|
||||
@Controller({
|
||||
version: '1',
|
||||
version: EnableDisableStatusEnum.ENABLED,
|
||||
path: 'timezone',
|
||||
})
|
||||
export class TimeZoneController {
|
||||
@ -21,13 +16,6 @@ export class TimeZoneController {
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get()
|
||||
async getAllTimeZones() {
|
||||
try {
|
||||
return await this.timeZoneService.getAllTimeZones();
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.timeZoneService.getAllTimeZones();
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@ import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Post,
|
||||
@ -23,11 +22,13 @@ import { CheckFloorTypeGuard } from 'src/guards/floor.type.guard';
|
||||
import { CheckUserUnitGuard } from 'src/guards/user.unit.guard';
|
||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||
import { UnitPermissionGuard } from 'src/guards/unit.permission.guard';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
|
||||
@ApiTags('Unit Module')
|
||||
@Controller({
|
||||
version: '1',
|
||||
path: 'unit',
|
||||
version: EnableDisableStatusEnum.ENABLED,
|
||||
path: SpaceType.UNIT,
|
||||
})
|
||||
export class UnitController {
|
||||
constructor(private readonly unitService: UnitService) {}
|
||||
@ -36,35 +37,21 @@ export class UnitController {
|
||||
@UseGuards(JwtAuthGuard, CheckFloorTypeGuard)
|
||||
@Post()
|
||||
async addUnit(@Body() addUnitDto: AddUnitDto) {
|
||||
try {
|
||||
const unit = await this.unitService.addUnit(addUnitDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Unit added successfully',
|
||||
data: unit,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const unit = await this.unitService.addUnit(addUnitDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'Unit added successfully',
|
||||
data: unit,
|
||||
};
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, UnitPermissionGuard)
|
||||
@Get(':unitUuid')
|
||||
async getUnitByUuid(@Param('unitUuid') unitUuid: string) {
|
||||
try {
|
||||
const unit = await this.unitService.getUnitByUuid(unitUuid);
|
||||
return unit;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const unit = await this.unitService.getUnitByUuid(unitUuid);
|
||||
return unit;
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@ -74,95 +61,53 @@ export class UnitController {
|
||||
@Param('unitUuid') unitUuid: string,
|
||||
@Query() query: GetUnitChildDto,
|
||||
) {
|
||||
try {
|
||||
const unit = await this.unitService.getUnitChildByUuid(unitUuid, query);
|
||||
return unit;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const unit = await this.unitService.getUnitChildByUuid(unitUuid, query);
|
||||
return unit;
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, UnitPermissionGuard)
|
||||
@Get('parent/:unitUuid')
|
||||
async getUnitParentByUuid(@Param('unitUuid') unitUuid: string) {
|
||||
try {
|
||||
const unit = await this.unitService.getUnitParentByUuid(unitUuid);
|
||||
return unit;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const unit = await this.unitService.getUnitParentByUuid(unitUuid);
|
||||
return unit;
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, CheckUserUnitGuard)
|
||||
@Post('user')
|
||||
async addUserUnit(@Body() addUserUnitDto: AddUserUnitDto) {
|
||||
try {
|
||||
await this.unitService.addUserUnit(addUserUnitDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'user unit added successfully',
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
await this.unitService.addUserUnit(addUserUnitDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'user unit added successfully',
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('user/:userUuid')
|
||||
async getUnitsByUserId(@Param('userUuid') userUuid: string) {
|
||||
try {
|
||||
return await this.unitService.getUnitsByUserId(userUuid);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
return await this.unitService.getUnitsByUserId(userUuid);
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, UnitPermissionGuard)
|
||||
@Put('rename/:unitUuid')
|
||||
@Put(':unitUuid')
|
||||
async renameUnitByUuid(
|
||||
@Param('unitUuid') unitUuid: string,
|
||||
@Body() updateUnitNameDto: UpdateUnitNameDto,
|
||||
) {
|
||||
try {
|
||||
const unit = await this.unitService.renameUnitByUuid(
|
||||
unitUuid,
|
||||
updateUnitNameDto,
|
||||
);
|
||||
return unit;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const unit = await this.unitService.renameUnitByUuid(
|
||||
unitUuid,
|
||||
updateUnitNameDto,
|
||||
);
|
||||
return unit;
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard, UnitPermissionGuard)
|
||||
@Get(':unitUuid/invitation-code')
|
||||
async getUnitInvitationCode(@Param('unitUuid') unitUuid: string) {
|
||||
try {
|
||||
const unit = await this.unitService.getUnitInvitationCode(unitUuid);
|
||||
return unit;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const unit = await this.unitService.getUnitInvitationCode(unitUuid);
|
||||
return unit;
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@ -171,18 +116,11 @@ export class UnitController {
|
||||
async verifyCodeAndAddUserUnit(
|
||||
@Body() addUserUnitUsingCodeDto: AddUserUnitUsingCodeDto,
|
||||
) {
|
||||
try {
|
||||
await this.unitService.verifyCodeAndAddUserUnit(addUserUnitUsingCodeDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'user unit added successfully',
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
await this.unitService.verifyCodeAndAddUserUnit(addUserUnitUsingCodeDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
success: true,
|
||||
message: 'user unit added successfully',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,6 +24,8 @@ import { UserDevicePermissionService } from 'src/user-device-permission/services
|
||||
import { PermissionType } from '@app/common/constants/permission-type.enum';
|
||||
import { TuyaContext } from '@tuya/tuya-connector-nodejs';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||
import { CommonErrorCodes } from '@app/common/constants/error-codes.enum';
|
||||
|
||||
@Injectable()
|
||||
export class UnitService {
|
||||
@ -50,7 +52,7 @@ export class UnitService {
|
||||
try {
|
||||
const spaceType = await this.spaceTypeRepository.findOne({
|
||||
where: {
|
||||
type: 'unit',
|
||||
type: SpaceType.UNIT,
|
||||
},
|
||||
});
|
||||
const tuyaUnit = await this.addUnitTuya(addUnitDto.unitName);
|
||||
@ -95,12 +97,12 @@ export class UnitService {
|
||||
where: {
|
||||
uuid: unitUuid,
|
||||
spaceType: {
|
||||
type: 'unit',
|
||||
type: SpaceType.UNIT,
|
||||
},
|
||||
},
|
||||
relations: ['spaceType'],
|
||||
});
|
||||
if (!unit || !unit.spaceType || unit.spaceType.type !== 'unit') {
|
||||
if (!unit || !unit.spaceType || unit.spaceType.type !== SpaceType.UNIT) {
|
||||
throw new BadRequestException('Invalid unit UUID');
|
||||
}
|
||||
return {
|
||||
@ -131,7 +133,11 @@ export class UnitService {
|
||||
relations: ['children', 'spaceType'],
|
||||
});
|
||||
|
||||
if (!space || !space.spaceType || space.spaceType.type !== 'unit') {
|
||||
if (
|
||||
!space ||
|
||||
!space.spaceType ||
|
||||
space.spaceType.type !== SpaceType.UNIT
|
||||
) {
|
||||
throw new BadRequestException('Invalid unit UUID');
|
||||
}
|
||||
|
||||
@ -174,10 +180,10 @@ export class UnitService {
|
||||
return children
|
||||
.filter(
|
||||
(child) =>
|
||||
child.spaceType.type !== 'unit' &&
|
||||
child.spaceType.type !== 'floor' &&
|
||||
child.spaceType.type !== 'community' &&
|
||||
child.spaceType.type !== 'unit',
|
||||
child.spaceType.type !== SpaceType.UNIT &&
|
||||
child.spaceType.type !== SpaceType.FLOOR &&
|
||||
child.spaceType.type !== SpaceType.COMMUNITY &&
|
||||
child.spaceType.type !== SpaceType.UNIT,
|
||||
) // Filter remaining unit and floor and community and unit types
|
||||
.map((child) => ({
|
||||
uuid: child.uuid,
|
||||
@ -190,10 +196,10 @@ export class UnitService {
|
||||
children
|
||||
.filter(
|
||||
(child) =>
|
||||
child.spaceType.type !== 'unit' &&
|
||||
child.spaceType.type !== 'floor' &&
|
||||
child.spaceType.type !== 'community' &&
|
||||
child.spaceType.type !== 'unit',
|
||||
child.spaceType.type !== SpaceType.UNIT &&
|
||||
child.spaceType.type !== SpaceType.FLOOR &&
|
||||
child.spaceType.type !== SpaceType.COMMUNITY &&
|
||||
child.spaceType.type !== SpaceType.UNIT,
|
||||
) // Filter remaining unit and floor and community and unit types
|
||||
.map(async (child) => ({
|
||||
uuid: child.uuid,
|
||||
@ -212,12 +218,12 @@ export class UnitService {
|
||||
where: {
|
||||
uuid: unitUuid,
|
||||
spaceType: {
|
||||
type: 'unit',
|
||||
type: SpaceType.UNIT,
|
||||
},
|
||||
},
|
||||
relations: ['spaceType', 'parent', 'parent.spaceType'],
|
||||
});
|
||||
if (!unit || !unit.spaceType || unit.spaceType.type !== 'unit') {
|
||||
if (!unit || !unit.spaceType || unit.spaceType.type !== SpaceType.UNIT) {
|
||||
throw new BadRequestException('Invalid unit UUID');
|
||||
}
|
||||
return {
|
||||
@ -246,7 +252,7 @@ export class UnitService {
|
||||
relations: ['space', 'space.spaceType'],
|
||||
where: {
|
||||
user: { uuid: userUuid },
|
||||
space: { spaceType: { type: 'unit' } },
|
||||
space: { spaceType: { type: SpaceType.UNIT } },
|
||||
},
|
||||
});
|
||||
|
||||
@ -276,7 +282,7 @@ export class UnitService {
|
||||
space: { uuid: addUserUnitDto.unitUuid },
|
||||
});
|
||||
} catch (err) {
|
||||
if (err.code === '23505') {
|
||||
if (err.code === CommonErrorCodes.DUPLICATE_ENTITY) {
|
||||
throw new HttpException(
|
||||
'User already belongs to this unit',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
@ -298,7 +304,7 @@ export class UnitService {
|
||||
relations: ['spaceType'],
|
||||
});
|
||||
|
||||
if (!unit || !unit.spaceType || unit.spaceType.type !== 'unit') {
|
||||
if (!unit || !unit.spaceType || unit.spaceType.type !== SpaceType.UNIT) {
|
||||
throw new BadRequestException('Invalid unit UUID');
|
||||
}
|
||||
|
||||
@ -383,7 +389,7 @@ export class UnitService {
|
||||
const unit = await this.spaceRepository.findOneOrFail({
|
||||
where: {
|
||||
invitationCode: inviteCode,
|
||||
spaceType: { type: 'unit' },
|
||||
spaceType: { type: SpaceType.UNIT },
|
||||
},
|
||||
relations: ['spaceType'],
|
||||
});
|
||||
|
||||
@ -3,7 +3,6 @@ import {
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Post,
|
||||
@ -15,10 +14,11 @@ import { UserDevicePermissionService } from '../services/user-device-permission.
|
||||
import { UserDevicePermissionAddDto } from '../dtos/user-device-permission.add.dto';
|
||||
import { UserDevicePermissionEditDto } from '../dtos/user-device-permission.edit.dto';
|
||||
import { AdminRoleGuard } from 'src/guards/admin.role.guard';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
|
||||
@ApiTags('Device Permission Module')
|
||||
@Controller({
|
||||
version: '1',
|
||||
version: EnableDisableStatusEnum.ENABLED,
|
||||
path: 'device-permission',
|
||||
})
|
||||
export class UserDevicePermissionController {
|
||||
@ -28,67 +28,48 @@ export class UserDevicePermissionController {
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(AdminRoleGuard)
|
||||
@Post('add')
|
||||
@Post()
|
||||
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 (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
const addDetails = await this.userDevicePermissionService.addUserPermission(
|
||||
userDevicePermissionDto,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
message: 'User Permission for Devices Added Successfully',
|
||||
data: addDetails,
|
||||
};
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(AdminRoleGuard)
|
||||
@Put('edit/:devicePermissionUuid')
|
||||
@Put(':devicePermissionUuid')
|
||||
async editDevicePermission(
|
||||
@Param('devicePermissionUuid') devicePermissionUuid: string,
|
||||
@Body() userDevicePermissionEditDto: UserDevicePermissionEditDto,
|
||||
) {
|
||||
try {
|
||||
await this.userDevicePermissionService.editUserPermission(
|
||||
devicePermissionUuid,
|
||||
userDevicePermissionEditDto,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'User Permission for Devices Updated Successfully',
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
await this.userDevicePermissionService.editUserPermission(
|
||||
devicePermissionUuid,
|
||||
userDevicePermissionEditDto,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'User Permission for Devices Updated Successfully',
|
||||
};
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(AdminRoleGuard)
|
||||
@Get(':deviceUuid/list')
|
||||
@Get(':deviceUuid')
|
||||
async fetchDevicePermission(@Param('deviceUuid') deviceUuid: string) {
|
||||
try {
|
||||
const deviceDetails =
|
||||
await this.userDevicePermissionService.fetchUserPermission(deviceUuid);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'Device Details fetched Successfully',
|
||||
data: deviceDetails,
|
||||
};
|
||||
} catch (err) {
|
||||
throw new Error(err);
|
||||
}
|
||||
const deviceDetails =
|
||||
await this.userDevicePermissionService.fetchUserPermission(deviceUuid);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'Device Details fetched Successfully',
|
||||
data: deviceDetails,
|
||||
};
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(AdminRoleGuard)
|
||||
@ -96,19 +77,12 @@ export class UserDevicePermissionController {
|
||||
async deleteDevicePermission(
|
||||
@Param('devicePermissionUuid') devicePermissionUuid: string,
|
||||
) {
|
||||
try {
|
||||
await this.userDevicePermissionService.deleteDevicePermission(
|
||||
devicePermissionUuid,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'User Permission for Devices Deleted Successfully',
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Internal server error',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
await this.userDevicePermissionService.deleteDevicePermission(
|
||||
devicePermissionUuid,
|
||||
);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'User Permission for Devices Deleted Successfully',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user