mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-11-27 11:24:55 +00:00
Merge branch 'dev'
This commit is contained in:
@ -90,3 +90,6 @@ FIREBASE_DATABASE_URL=
|
|||||||
|
|
||||||
OTP_LIMITER=
|
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 { JwtService } from '@nestjs/jwt';
|
||||||
import * as argon2 from 'argon2';
|
import * as argon2 from 'argon2';
|
||||||
import { HelperHashService } from '../../helper/services';
|
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 { UserSessionRepository } from '../../../../common/src/modules/session/repositories/session.repository';
|
||||||
import { UserSessionEntity } from '../../../../common/src/modules/session/entities';
|
import { UserSessionEntity } from '../../../../common/src/modules/session/entities';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { OAuth2Client } from 'google-auth-library';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
|
private client: OAuth2Client;
|
||||||
constructor(
|
constructor(
|
||||||
private jwtService: JwtService,
|
private jwtService: JwtService,
|
||||||
private readonly userRepository: UserRepository,
|
private readonly userRepository: UserRepository,
|
||||||
private readonly sessionRepository: UserSessionRepository,
|
private readonly sessionRepository: UserSessionRepository,
|
||||||
private readonly helperHashService: HelperHashService,
|
private readonly helperHashService: HelperHashService,
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
) {}
|
) {
|
||||||
|
this.client = new OAuth2Client(this.configService.get('GOOGLE_CLIENT_ID'));
|
||||||
|
}
|
||||||
|
|
||||||
async validateUser(
|
async validateUser(
|
||||||
email: string,
|
email: string,
|
||||||
@ -80,8 +88,17 @@ export class AuthService {
|
|||||||
type: user.type,
|
type: user.type,
|
||||||
sessionId: user.sessionId,
|
sessionId: user.sessionId,
|
||||||
roles: user?.roles,
|
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);
|
const tokens = await this.getTokens(payload);
|
||||||
await this.updateRefreshToken(user.uuid, tokens.refreshToken);
|
await this.updateRefreshToken(user.uuid, tokens.refreshToken);
|
||||||
return tokens;
|
return tokens;
|
||||||
@ -100,4 +117,19 @@ export class AuthService {
|
|||||||
hashData(data: string) {
|
hashData(data: string) {
|
||||||
return argon2.hash(data);
|
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 { ConfigModule } from '@nestjs/config';
|
||||||
import config from './config';
|
import config from './config';
|
||||||
import { EmailService } from './util/email.service';
|
import { EmailService } from './util/email.service';
|
||||||
|
import { ErrorMessageService } from 'src/error-message/error-message.service';
|
||||||
@Module({
|
@Module({
|
||||||
providers: [CommonService, EmailService],
|
providers: [CommonService, EmailService, ErrorMessageService],
|
||||||
exports: [CommonService, HelperModule, AuthModule, EmailService],
|
exports: [
|
||||||
|
CommonService,
|
||||||
|
HelperModule,
|
||||||
|
AuthModule,
|
||||||
|
EmailService,
|
||||||
|
ErrorMessageService,
|
||||||
|
],
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({
|
ConfigModule.forRoot({
|
||||||
load: config,
|
load: config,
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
import { registerAs } from '@nestjs/config';
|
import { registerAs } from '@nestjs/config';
|
||||||
|
import { BooleanValues } from '../constants/boolean-values.enum';
|
||||||
|
|
||||||
export default registerAs(
|
export default registerAs(
|
||||||
'email-config',
|
'email-config',
|
||||||
(): Record<string, any> => ({
|
(): Record<string, any> => ({
|
||||||
SMTP_HOST: process.env.SMTP_HOST,
|
SMTP_HOST: process.env.SMTP_HOST,
|
||||||
SMTP_PORT: parseInt(process.env.SMTP_PORT),
|
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_USER: process.env.SMTP_USER,
|
||||||
SMTP_SENDER: process.env.SMTP_SENDER,
|
SMTP_SENDER: process.env.SMTP_SENDER,
|
||||||
SMTP_PASSWORD: process.env.SMTP_PASSWORD,
|
SMTP_PASSWORD: process.env.SMTP_PASSWORD,
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { registerAs } from '@nestjs/config';
|
import { registerAs } from '@nestjs/config';
|
||||||
|
import { BooleanValues } from '../constants/boolean-values.enum';
|
||||||
|
|
||||||
export default registerAs(
|
export default registerAs(
|
||||||
'tuya-config',
|
'tuya-config',
|
||||||
@ -7,6 +8,6 @@ export default registerAs(
|
|||||||
TUYA_ACCESS_KEY: process.env.TUYA_ACCESS_KEY,
|
TUYA_ACCESS_KEY: process.env.TUYA_ACCESS_KEY,
|
||||||
TUYA_EU_URL: process.env.TUYA_EU_URL,
|
TUYA_EU_URL: process.env.TUYA_EU_URL,
|
||||||
TRUN_ON_TUYA_SOCKET:
|
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',
|
CPS = 'CPS',
|
||||||
DL = 'DL',
|
DL = 'DL',
|
||||||
WPS = 'WPS',
|
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 {
|
export enum WorkingDays {
|
||||||
Sun = 'Sun',
|
Sun = DaysEnum.SUN,
|
||||||
Mon = 'Mon',
|
Mon = DaysEnum.MON,
|
||||||
Tue = 'Tue',
|
Tue = DaysEnum.TUE,
|
||||||
Wed = 'Wed',
|
Wed = DaysEnum.WED,
|
||||||
Thu = 'Thu',
|
Thu = DaysEnum.THU,
|
||||||
Fri = 'Fri',
|
Fri = DaysEnum.FRI,
|
||||||
Sat = 'Sat',
|
Sat = DaysEnum.SAT,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,10 +2,11 @@ import { Controller, Post, Param } from '@nestjs/common';
|
|||||||
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
||||||
import { AddDeviceStatusDto } from '../dtos/add.devices-status.dto';
|
import { AddDeviceStatusDto } from '../dtos/add.devices-status.dto';
|
||||||
import { DeviceStatusFirebaseService } from '../services/devices-status.service';
|
import { DeviceStatusFirebaseService } from '../services/devices-status.service';
|
||||||
|
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||||
|
|
||||||
@ApiTags('Device Status Firebase Module')
|
@ApiTags('Device Status Firebase Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
version: '1',
|
version: EnableDisableStatusEnum.ENABLED,
|
||||||
path: 'device-status-firebase',
|
path: 'device-status-firebase',
|
||||||
})
|
})
|
||||||
export class DeviceStatusFirebaseController {
|
export class DeviceStatusFirebaseController {
|
||||||
|
|||||||
@ -85,6 +85,7 @@ export class DeviceStatusFirebaseService {
|
|||||||
return await this.deviceRepository.findOne({
|
return await this.deviceRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
deviceTuyaUuid,
|
deviceTuyaUuid,
|
||||||
|
isActive: true,
|
||||||
},
|
},
|
||||||
relations: ['productDevice'],
|
relations: ['productDevice'],
|
||||||
});
|
});
|
||||||
@ -139,6 +140,7 @@ export class DeviceStatusFirebaseService {
|
|||||||
return await this.deviceRepository.findOne({
|
return await this.deviceRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
uuid: deviceUuid,
|
uuid: deviceUuid,
|
||||||
|
isActive: true,
|
||||||
},
|
},
|
||||||
...(withProductDevice && { relations: ['productDevice'] }),
|
...(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({
|
@Column({
|
||||||
nullable: true,
|
nullable: true,
|
||||||
default: true,
|
default: true,
|
||||||
|
type: 'boolean',
|
||||||
})
|
})
|
||||||
isActive: true;
|
isActive: boolean;
|
||||||
|
|
||||||
@ManyToOne(() => UserEntity, (user) => user.userSpaces, { nullable: false })
|
@ManyToOne(() => UserEntity, (user) => user.userSpaces, { nullable: false })
|
||||||
user: UserEntity;
|
user: UserEntity;
|
||||||
|
|||||||
346
package-lock.json
generated
346
package-lock.json
generated
@ -20,13 +20,14 @@
|
|||||||
"@nestjs/websockets": "^10.3.8",
|
"@nestjs/websockets": "^10.3.8",
|
||||||
"@tuya/tuya-connector-nodejs": "^2.1.2",
|
"@tuya/tuya-connector-nodejs": "^2.1.2",
|
||||||
"argon2": "^0.40.1",
|
"argon2": "^0.40.1",
|
||||||
"axios": "^1.6.7",
|
"axios": "^1.7.7",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.1",
|
"class-validator": "^0.14.1",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"express-rate-limit": "^7.1.5",
|
"express-rate-limit": "^7.1.5",
|
||||||
"firebase": "^10.12.5",
|
"firebase": "^10.12.5",
|
||||||
|
"google-auth-library": "^9.14.1",
|
||||||
"helmet": "^7.1.0",
|
"helmet": "^7.1.0",
|
||||||
"ioredis": "^5.3.2",
|
"ioredis": "^5.3.2",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
@ -2258,6 +2259,8 @@
|
|||||||
"version": "1.1.8",
|
"version": "1.1.8",
|
||||||
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.8.tgz",
|
||||||
"integrity": "sha512-qKwC/M/nNNaKUBMQ0nuzm47b7ZYWQHN3pcXq4IIcoSBc2hOIrflAxJduIvvqmhoz3gR2TacTAs8vlsCVPkiEdQ==",
|
"integrity": "sha512-qKwC/M/nNNaKUBMQ0nuzm47b7ZYWQHN3pcXq4IIcoSBc2hOIrflAxJduIvvqmhoz3gR2TacTAs8vlsCVPkiEdQ==",
|
||||||
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"sparse-bitfield": "^3.0.3"
|
"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": {
|
"node_modules/@nestjs/passport": {
|
||||||
"version": "10.0.3",
|
"version": "10.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-10.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-10.0.3.tgz",
|
||||||
@ -3138,7 +3130,9 @@
|
|||||||
"node_modules/@types/webidl-conversions": {
|
"node_modules/@types/webidl-conversions": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
|
"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": {
|
"node_modules/@types/whatwg-url": {
|
||||||
"version": "8.2.2",
|
"version": "8.2.2",
|
||||||
@ -3571,6 +3565,18 @@
|
|||||||
"node": ">=0.4.0"
|
"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": {
|
"node_modules/ajv": {
|
||||||
"version": "8.12.0",
|
"version": "8.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
||||||
@ -3791,11 +3797,12 @@
|
|||||||
"integrity": "sha512-3AungXC4I8kKsS9PuS4JH2nc+0bVY/mjgrephHTIi8fpEeGsTHBUJeosp0Wc1myYMElmD0B3Oc4XL/HVJ4PV2g=="
|
"integrity": "sha512-3AungXC4I8kKsS9PuS4JH2nc+0bVY/mjgrephHTIi8fpEeGsTHBUJeosp0Wc1myYMElmD0B3Oc4XL/HVJ4PV2g=="
|
||||||
},
|
},
|
||||||
"node_modules/axios": {
|
"node_modules/axios": {
|
||||||
"version": "1.6.7",
|
"version": "1.7.7",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
|
||||||
"integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==",
|
"integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"follow-redirects": "^1.15.4",
|
"follow-redirects": "^1.15.6",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"proxy-from-env": "^1.1.0"
|
"proxy-from-env": "^1.1.0"
|
||||||
}
|
}
|
||||||
@ -3969,6 +3976,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
|
||||||
"integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ=="
|
"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": {
|
"node_modules/binary-extensions": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||||
@ -4131,14 +4147,6 @@
|
|||||||
"node-int64": "^0.4.0"
|
"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": {
|
"node_modules/buffer": {
|
||||||
"version": "5.7.1",
|
"version": "5.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||||
@ -5902,15 +5910,16 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/follow-redirects": {
|
"node_modules/follow-redirects": {
|
||||||
"version": "1.15.5",
|
"version": "1.15.9",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||||
"integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
|
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "individual",
|
"type": "individual",
|
||||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4.0"
|
"node": ">=4.0"
|
||||||
},
|
},
|
||||||
@ -6071,6 +6080,35 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"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": {
|
"node_modules/gensync": {
|
||||||
"version": "1.0.0-beta.2",
|
"version": "1.0.0-beta.2",
|
||||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||||
@ -6209,6 +6247,44 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"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": {
|
"node_modules/gopd": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
||||||
@ -6232,6 +6308,40 @@
|
|||||||
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
|
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
|
||||||
"dev": true
|
"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": {
|
"node_modules/har-schema": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
||||||
@ -6399,6 +6509,19 @@
|
|||||||
"npm": ">=1.3.7"
|
"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": {
|
"node_modules/human-signals": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
|
||||||
@ -6704,7 +6827,6 @@
|
|||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
|
||||||
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
|
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
},
|
},
|
||||||
@ -7548,6 +7670,15 @@
|
|||||||
"node": ">=4"
|
"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": {
|
"node_modules/json-buffer": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
||||||
@ -7666,14 +7797,6 @@
|
|||||||
"safe-buffer": "^5.0.1"
|
"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": {
|
"node_modules/keyv": {
|
||||||
"version": "4.5.4",
|
"version": "4.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||||
@ -7911,7 +8034,9 @@
|
|||||||
"node_modules/memory-pager": {
|
"node_modules/memory-pager": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
|
"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": {
|
"node_modules/merge-descriptors": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
@ -8146,125 +8271,6 @@
|
|||||||
"node": ">=14.20.1"
|
"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": {
|
"node_modules/morgan": {
|
||||||
"version": "1.10.0",
|
"version": "1.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz",
|
||||||
@ -8304,25 +8310,6 @@
|
|||||||
"node": ">= 0.8"
|
"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": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
@ -9956,11 +9943,6 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"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": {
|
"node_modules/signal-exit": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
||||||
@ -10045,6 +10027,8 @@
|
|||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
|
||||||
"integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
|
"integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
|
||||||
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"memory-pager": "^1.0.2"
|
"memory-pager": "^1.0.2"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,13 +31,14 @@
|
|||||||
"@nestjs/websockets": "^10.3.8",
|
"@nestjs/websockets": "^10.3.8",
|
||||||
"@tuya/tuya-connector-nodejs": "^2.1.2",
|
"@tuya/tuya-connector-nodejs": "^2.1.2",
|
||||||
"argon2": "^0.40.1",
|
"argon2": "^0.40.1",
|
||||||
"axios": "^1.6.7",
|
"axios": "^1.7.7",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.1",
|
"class-validator": "^0.14.1",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"express-rate-limit": "^7.1.5",
|
"express-rate-limit": "^7.1.5",
|
||||||
"firebase": "^10.12.5",
|
"firebase": "^10.12.5",
|
||||||
|
"google-auth-library": "^9.14.1",
|
||||||
"helmet": "^7.1.0",
|
"helmet": "^7.1.0",
|
||||||
"ioredis": "^5.3.2",
|
"ioredis": "^5.3.2",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import { Module } from '@nestjs/common';
|
|||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import config from './config';
|
import config from './config';
|
||||||
import { AuthenticationModule } from './auth/auth.module';
|
import { AuthenticationModule } from './auth/auth.module';
|
||||||
import { AuthenticationController } from './auth/controllers/authentication.controller';
|
|
||||||
import { UserModule } from './users/user.module';
|
import { UserModule } from './users/user.module';
|
||||||
import { RoomModule } from './room/room.module';
|
import { RoomModule } from './room/room.module';
|
||||||
import { GroupModule } from './group/group.module';
|
import { GroupModule } from './group/group.module';
|
||||||
@ -24,6 +23,7 @@ import { AutomationModule } from './automation/automation.module';
|
|||||||
import { RegionModule } from './region/region.module';
|
import { RegionModule } from './region/region.module';
|
||||||
import { TimeZoneModule } from './timezone/timezone.module';
|
import { TimeZoneModule } from './timezone/timezone.module';
|
||||||
import { VisitorPasswordModule } from './vistor-password/visitor-password.module';
|
import { VisitorPasswordModule } from './vistor-password/visitor-password.module';
|
||||||
|
import { ScheduleModule } from './schedule/schedule.module';
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({
|
ConfigModule.forRoot({
|
||||||
@ -50,8 +50,8 @@ import { VisitorPasswordModule } from './vistor-password/visitor-password.module
|
|||||||
RegionModule,
|
RegionModule,
|
||||||
TimeZoneModule,
|
TimeZoneModule,
|
||||||
VisitorPasswordModule,
|
VisitorPasswordModule,
|
||||||
|
ScheduleModule,
|
||||||
],
|
],
|
||||||
controllers: [AuthenticationController],
|
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: APP_INTERCEPTOR,
|
provide: APP_INTERCEPTOR,
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { AuthenticationController } from './controllers/authentication.controller';
|
|
||||||
import { AuthenticationService } from './services/authentication.service';
|
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import { UserRepositoryModule } from '@app/common/modules/user/user.repository.module';
|
import { UserRepositoryModule } from '@app/common/modules/user/user.repository.module';
|
||||||
import { CommonModule } from '../../libs/common/src';
|
import { CommonModule } from '../../libs/common/src';
|
||||||
@ -16,9 +14,8 @@ import { RoleTypeRepository } from '@app/common/modules/role-type/repositories';
|
|||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ConfigModule, UserRepositoryModule, CommonModule],
|
imports: [ConfigModule, UserRepositoryModule, CommonModule],
|
||||||
controllers: [AuthenticationController, UserAuthController],
|
controllers: [UserAuthController],
|
||||||
providers: [
|
providers: [
|
||||||
AuthenticationService,
|
|
||||||
UserAuthService,
|
UserAuthService,
|
||||||
UserRepository,
|
UserRepository,
|
||||||
UserSessionRepository,
|
UserSessionRepository,
|
||||||
@ -26,6 +23,6 @@ import { RoleTypeRepository } from '@app/common/modules/role-type/repositories';
|
|||||||
UserRoleRepository,
|
UserRoleRepository,
|
||||||
RoleTypeRepository,
|
RoleTypeRepository,
|
||||||
],
|
],
|
||||||
exports: [AuthenticationService, UserAuthService],
|
exports: [UserAuthService],
|
||||||
})
|
})
|
||||||
export class AuthenticationModule {}
|
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';
|
export * from './user-auth.controller';
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
Body,
|
Body,
|
||||||
Controller,
|
Controller,
|
||||||
Delete,
|
|
||||||
Get,
|
Get,
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
Param,
|
|
||||||
Post,
|
Post,
|
||||||
Req,
|
Req,
|
||||||
UseGuards,
|
UseGuards,
|
||||||
@ -17,9 +15,10 @@ import { UserLoginDto } from '../dtos/user-login.dto';
|
|||||||
import { ForgetPasswordDto, UserOtpDto, VerifyOtpDto } from '../dtos';
|
import { ForgetPasswordDto, UserOtpDto, VerifyOtpDto } from '../dtos';
|
||||||
import { RefreshTokenGuard } from '@app/common/guards/jwt-refresh.auth.guard';
|
import { RefreshTokenGuard } from '@app/common/guards/jwt-refresh.auth.guard';
|
||||||
import { SuperAdminRoleGuard } from 'src/guards/super.admin.role.guard';
|
import { SuperAdminRoleGuard } from 'src/guards/super.admin.role.guard';
|
||||||
|
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||||
|
|
||||||
@Controller({
|
@Controller({
|
||||||
version: '1',
|
version: EnableDisableStatusEnum.ENABLED,
|
||||||
path: 'authentication',
|
path: 'authentication',
|
||||||
})
|
})
|
||||||
@ApiTags('Auth')
|
@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')
|
@Post('user/send-otp')
|
||||||
async sendOtp(@Body() otpDto: UserOtpDto) {
|
async sendOtp(@Body() otpDto: UserOtpDto) {
|
||||||
const otpCode = await this.userAuthService.generateOTP(otpDto);
|
const otpCode = await this.userAuthService.generateOTP(otpDto);
|
||||||
@ -99,7 +84,7 @@ export class UserAuthController {
|
|||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(SuperAdminRoleGuard)
|
@UseGuards(SuperAdminRoleGuard)
|
||||||
@Get('user/list')
|
@Get('user')
|
||||||
async userList() {
|
async userList() {
|
||||||
const userList = await this.userAuthService.userList();
|
const userList = await this.userAuthService.userList();
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -41,5 +41,5 @@ export class UserSignUpDto {
|
|||||||
|
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
public regionUuid: string;
|
public regionUuid?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +1,23 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
import { IsEmail, IsOptional, IsString } from 'class-validator';
|
||||||
|
|
||||||
export class UserLoginDto {
|
export class UserLoginDto {
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
@IsEmail()
|
@IsEmail()
|
||||||
@IsNotEmpty()
|
@IsOptional()
|
||||||
email: string;
|
email?: string;
|
||||||
|
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
password: string;
|
password?: string;
|
||||||
|
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
regionUuid?: string;
|
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';
|
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 { UserRepository } from '../../../libs/common/src/modules/user/repositories';
|
||||||
import {
|
import {
|
||||||
BadRequestException,
|
BadRequestException,
|
||||||
ForbiddenException,
|
ForbiddenException,
|
||||||
Injectable,
|
Injectable,
|
||||||
UnauthorizedException,
|
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { UserSignUpDto } from '../dtos/user-auth.dto';
|
import { UserSignUpDto } from '../dtos/user-auth.dto';
|
||||||
import { HelperHashService } from '../../../libs/common/src/helper/services';
|
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 { differenceInSeconds } from '@app/common/helper/differenceInSeconds';
|
||||||
import { LessThan, MoreThan } from 'typeorm';
|
import { LessThan, MoreThan } from 'typeorm';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { UUID } from 'typeorm/driver/mongodb/bson.typings';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserAuthService {
|
export class UserAuthService {
|
||||||
@ -31,8 +29,6 @@ export class UserAuthService {
|
|||||||
private readonly helperHashService: HelperHashService,
|
private readonly helperHashService: HelperHashService,
|
||||||
private readonly authService: AuthService,
|
private readonly authService: AuthService,
|
||||||
private readonly emailService: EmailService,
|
private readonly emailService: EmailService,
|
||||||
private readonly userRoleRepository: UserRoleRepository,
|
|
||||||
private readonly roleTypeRepository: RoleTypeRepository,
|
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@ -93,13 +89,38 @@ export class UserAuthService {
|
|||||||
|
|
||||||
async userLogin(data: UserLoginDto) {
|
async userLogin(data: UserLoginDto) {
|
||||||
try {
|
try {
|
||||||
const user = await this.authService.validateUser(
|
let user;
|
||||||
data.email,
|
if (data.googleCode) {
|
||||||
data.password,
|
const googleUserData = await this.authService.login({
|
||||||
data.regionUuid,
|
googleCode: data.googleCode,
|
||||||
);
|
});
|
||||||
if (!user) {
|
const userExists = await this.userRepository.exists({
|
||||||
throw new UnauthorizedException('Invalid login credentials.');
|
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([
|
const session = await Promise.all([
|
||||||
await this.sessionRepository.update(
|
await this.sessionRepository.update(
|
||||||
@ -114,7 +135,7 @@ export class UserAuthService {
|
|||||||
isLoggedOut: false,
|
isLoggedOut: false,
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
return await this.authService.login({
|
const res = await this.authService.login({
|
||||||
email: user.email,
|
email: user.email,
|
||||||
userId: user.uuid,
|
userId: user.uuid,
|
||||||
uuid: user.uuid,
|
uuid: user.uuid,
|
||||||
@ -123,19 +144,12 @@ export class UserAuthService {
|
|||||||
}),
|
}),
|
||||||
sessionId: session[1].uuid,
|
sessionId: session[1].uuid,
|
||||||
});
|
});
|
||||||
|
return res;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new BadRequestException('Invalid credentials');
|
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> {
|
async findOneById(id: string): Promise<UserEntity> {
|
||||||
return await this.userRepository.findOne({ where: { uuid: id } });
|
return await this.userRepository.findOne({ where: { uuid: id } });
|
||||||
}
|
}
|
||||||
@ -225,7 +239,15 @@ export class UserAuthService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!otp) {
|
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) {
|
if (otp.otpCode !== data.otpCode) {
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import {
|
|||||||
Controller,
|
Controller,
|
||||||
Delete,
|
Delete,
|
||||||
Get,
|
Get,
|
||||||
HttpException,
|
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
Param,
|
Param,
|
||||||
Post,
|
Post,
|
||||||
@ -18,10 +17,11 @@ import {
|
|||||||
UpdateAutomationStatusDto,
|
UpdateAutomationStatusDto,
|
||||||
} from '../dtos/automation.dto';
|
} from '../dtos/automation.dto';
|
||||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||||
|
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||||
|
|
||||||
@ApiTags('Automation Module')
|
@ApiTags('Automation Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
version: '1',
|
version: EnableDisableStatusEnum.ENABLED,
|
||||||
path: 'automation',
|
path: 'automation',
|
||||||
})
|
})
|
||||||
export class AutomationController {
|
export class AutomationController {
|
||||||
@ -31,52 +31,30 @@ export class AutomationController {
|
|||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Post()
|
@Post()
|
||||||
async addAutomation(@Body() addAutomationDto: AddAutomationDto) {
|
async addAutomation(@Body() addAutomationDto: AddAutomationDto) {
|
||||||
try {
|
const automation =
|
||||||
const automation =
|
await this.automationService.addAutomation(addAutomationDto);
|
||||||
await this.automationService.addAutomation(addAutomationDto);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.CREATED,
|
||||||
statusCode: HttpStatus.CREATED,
|
success: true,
|
||||||
success: true,
|
message: 'Automation added successfully',
|
||||||
message: 'Automation added successfully',
|
data: automation,
|
||||||
data: automation,
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Get(':unitUuid')
|
@Get(':unitUuid')
|
||||||
async getAutomationByUnit(@Param('unitUuid') unitUuid: string) {
|
async getAutomationByUnit(@Param('unitUuid') unitUuid: string) {
|
||||||
try {
|
const automation =
|
||||||
const automation =
|
await this.automationService.getAutomationByUnit(unitUuid);
|
||||||
await this.automationService.getAutomationByUnit(unitUuid);
|
return automation;
|
||||||
return automation;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Get('details/:automationId')
|
@Get('details/:automationId')
|
||||||
async getAutomationDetails(@Param('automationId') automationId: string) {
|
async getAutomationDetails(@Param('automationId') automationId: string) {
|
||||||
try {
|
const automation =
|
||||||
const automation =
|
await this.automationService.getAutomationDetails(automationId);
|
||||||
await this.automationService.getAutomationDetails(automationId);
|
return automation;
|
||||||
return automation;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
``;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@ -85,18 +63,11 @@ export class AutomationController {
|
|||||||
@Param('unitUuid') unitUuid: string,
|
@Param('unitUuid') unitUuid: string,
|
||||||
@Param('automationId') automationId: string,
|
@Param('automationId') automationId: string,
|
||||||
) {
|
) {
|
||||||
try {
|
await this.automationService.deleteAutomation(unitUuid, automationId);
|
||||||
await this.automationService.deleteAutomation(unitUuid, automationId);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.OK,
|
||||||
statusCode: HttpStatus.OK,
|
message: 'Automation Deleted Successfully',
|
||||||
message: 'Automation Deleted Successfully',
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@ -105,23 +76,16 @@ export class AutomationController {
|
|||||||
@Body() updateAutomationDto: UpdateAutomationDto,
|
@Body() updateAutomationDto: UpdateAutomationDto,
|
||||||
@Param('automationId') automationId: string,
|
@Param('automationId') automationId: string,
|
||||||
) {
|
) {
|
||||||
try {
|
const automation = await this.automationService.updateAutomation(
|
||||||
const automation = await this.automationService.updateAutomation(
|
updateAutomationDto,
|
||||||
updateAutomationDto,
|
automationId,
|
||||||
automationId,
|
);
|
||||||
);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.CREATED,
|
||||||
statusCode: HttpStatus.CREATED,
|
success: true,
|
||||||
success: true,
|
message: 'Automation updated successfully',
|
||||||
message: 'Automation updated successfully',
|
data: automation,
|
||||||
data: automation,
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@ -130,21 +94,14 @@ export class AutomationController {
|
|||||||
@Body() updateAutomationStatusDto: UpdateAutomationStatusDto,
|
@Body() updateAutomationStatusDto: UpdateAutomationStatusDto,
|
||||||
@Param('automationId') automationId: string,
|
@Param('automationId') automationId: string,
|
||||||
) {
|
) {
|
||||||
try {
|
await this.automationService.updateAutomationStatus(
|
||||||
await this.automationService.updateAutomationStatus(
|
updateAutomationStatusDto,
|
||||||
updateAutomationStatusDto,
|
automationId,
|
||||||
automationId,
|
);
|
||||||
);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.CREATED,
|
||||||
statusCode: HttpStatus.CREATED,
|
success: true,
|
||||||
success: true,
|
message: 'Automation status updated successfully',
|
||||||
message: 'Automation status updated successfully',
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,11 @@ import {
|
|||||||
GetAutomationByUnitInterface,
|
GetAutomationByUnitInterface,
|
||||||
} from '../interface/automation.interface';
|
} from '../interface/automation.interface';
|
||||||
import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter';
|
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()
|
@Injectable()
|
||||||
export class AutomationService {
|
export class AutomationService {
|
||||||
@ -64,7 +69,7 @@ export class AutomationService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
for (const action of actions) {
|
for (const action of actions) {
|
||||||
if (action.action_executor === 'device_issue') {
|
if (action.action_executor === ActionExecutorEnum.DEVICE_ISSUE) {
|
||||||
const device = await this.deviceService.getDeviceByDeviceUuid(
|
const device = await this.deviceService.getDeviceByDeviceUuid(
|
||||||
action.entity_id,
|
action.entity_id,
|
||||||
false,
|
false,
|
||||||
@ -76,7 +81,7 @@ export class AutomationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const condition of conditions) {
|
for (const condition of conditions) {
|
||||||
if (condition.entity_type === 'device_report') {
|
if (condition.entity_type === EntityTypeEnum.DEVICE_REPORT) {
|
||||||
const device = await this.deviceService.getDeviceByDeviceUuid(
|
const device = await this.deviceService.getDeviceByDeviceUuid(
|
||||||
condition.entity_id,
|
condition.entity_id,
|
||||||
false,
|
false,
|
||||||
@ -127,12 +132,12 @@ export class AutomationService {
|
|||||||
where: {
|
where: {
|
||||||
uuid: unitUuid,
|
uuid: unitUuid,
|
||||||
spaceType: {
|
spaceType: {
|
||||||
type: 'unit',
|
type: SpaceType.UNIT,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
relations: ['spaceType'],
|
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');
|
throw new BadRequestException('Invalid unit UUID');
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@ -240,7 +245,7 @@ export class AutomationService {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
for (const action of actions) {
|
for (const action of actions) {
|
||||||
if (action.actionExecutor === 'device_issue') {
|
if (action.actionExecutor === ActionExecutorEnum.DEVICE_ISSUE) {
|
||||||
const device = await this.deviceService.getDeviceByDeviceTuyaUuid(
|
const device = await this.deviceService.getDeviceByDeviceTuyaUuid(
|
||||||
action.entityId,
|
action.entityId,
|
||||||
);
|
);
|
||||||
@ -249,8 +254,8 @@ export class AutomationService {
|
|||||||
action.entityId = device.uuid;
|
action.entityId = device.uuid;
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
action.actionExecutor !== 'device_issue' &&
|
action.actionExecutor !== ActionExecutorEnum.DEVICE_ISSUE &&
|
||||||
action.actionExecutor !== 'delay'
|
action.actionExecutor !== ActionExecutorEnum.DELAY
|
||||||
) {
|
) {
|
||||||
const sceneDetails = await this.getTapToRunSceneDetailsTuya(
|
const sceneDetails = await this.getTapToRunSceneDetailsTuya(
|
||||||
action.entityId,
|
action.entityId,
|
||||||
@ -268,7 +273,7 @@ export class AutomationService {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
for (const condition of conditions) {
|
for (const condition of conditions) {
|
||||||
if (condition.entityType === 'device_report') {
|
if (condition.entityType === EntityTypeEnum.DEVICE_REPORT) {
|
||||||
const device = await this.deviceService.getDeviceByDeviceTuyaUuid(
|
const device = await this.deviceService.getDeviceByDeviceTuyaUuid(
|
||||||
condition.entityId,
|
condition.entityId,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import {
|
|||||||
Body,
|
Body,
|
||||||
Controller,
|
Controller,
|
||||||
Get,
|
Get,
|
||||||
HttpException,
|
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
Param,
|
Param,
|
||||||
Post,
|
Post,
|
||||||
@ -20,11 +19,13 @@ import { CheckUserBuildingGuard } from 'src/guards/user.building.guard';
|
|||||||
import { AdminRoleGuard } from 'src/guards/admin.role.guard';
|
import { AdminRoleGuard } from 'src/guards/admin.role.guard';
|
||||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||||
import { BuildingPermissionGuard } from 'src/guards/building.permission.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')
|
@ApiTags('Building Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
version: '1',
|
version: EnableDisableStatusEnum.ENABLED,
|
||||||
path: 'building',
|
path: SpaceType.BUILDING,
|
||||||
})
|
})
|
||||||
export class BuildingController {
|
export class BuildingController {
|
||||||
constructor(private readonly buildingService: BuildingService) {}
|
constructor(private readonly buildingService: BuildingService) {}
|
||||||
@ -33,36 +34,21 @@ export class BuildingController {
|
|||||||
@UseGuards(JwtAuthGuard, CheckCommunityTypeGuard)
|
@UseGuards(JwtAuthGuard, CheckCommunityTypeGuard)
|
||||||
@Post()
|
@Post()
|
||||||
async addBuilding(@Body() addBuildingDto: AddBuildingDto) {
|
async addBuilding(@Body() addBuildingDto: AddBuildingDto) {
|
||||||
try {
|
const building = await this.buildingService.addBuilding(addBuildingDto);
|
||||||
const building = await this.buildingService.addBuilding(addBuildingDto);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.CREATED,
|
||||||
statusCode: HttpStatus.CREATED,
|
success: true,
|
||||||
success: true,
|
message: 'Building added successfully',
|
||||||
message: 'Building added successfully',
|
data: building,
|
||||||
data: building,
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard, BuildingPermissionGuard)
|
@UseGuards(JwtAuthGuard, BuildingPermissionGuard)
|
||||||
@Get(':buildingUuid')
|
@Get(':buildingUuid')
|
||||||
async getBuildingByUuid(@Param('buildingUuid') buildingUuid: string) {
|
async getBuildingByUuid(@Param('buildingUuid') buildingUuid: string) {
|
||||||
try {
|
const building = await this.buildingService.getBuildingByUuid(buildingUuid);
|
||||||
const building =
|
return building;
|
||||||
await this.buildingService.getBuildingByUuid(buildingUuid);
|
|
||||||
return building;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@ -72,84 +58,49 @@ export class BuildingController {
|
|||||||
@Param('buildingUuid') buildingUuid: string,
|
@Param('buildingUuid') buildingUuid: string,
|
||||||
@Query() query: GetBuildingChildDto,
|
@Query() query: GetBuildingChildDto,
|
||||||
) {
|
) {
|
||||||
try {
|
const building = await this.buildingService.getBuildingChildByUuid(
|
||||||
const building = await this.buildingService.getBuildingChildByUuid(
|
buildingUuid,
|
||||||
buildingUuid,
|
query,
|
||||||
query,
|
);
|
||||||
);
|
return building;
|
||||||
return building;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard, BuildingPermissionGuard)
|
@UseGuards(JwtAuthGuard, BuildingPermissionGuard)
|
||||||
@Get('parent/:buildingUuid')
|
@Get('parent/:buildingUuid')
|
||||||
async getBuildingParentByUuid(@Param('buildingUuid') buildingUuid: string) {
|
async getBuildingParentByUuid(@Param('buildingUuid') buildingUuid: string) {
|
||||||
try {
|
const building =
|
||||||
const building =
|
await this.buildingService.getBuildingParentByUuid(buildingUuid);
|
||||||
await this.buildingService.getBuildingParentByUuid(buildingUuid);
|
return building;
|
||||||
return building;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(AdminRoleGuard, CheckUserBuildingGuard)
|
@UseGuards(AdminRoleGuard, CheckUserBuildingGuard)
|
||||||
@Post('user')
|
@Post('user')
|
||||||
async addUserBuilding(@Body() addUserBuildingDto: AddUserBuildingDto) {
|
async addUserBuilding(@Body() addUserBuildingDto: AddUserBuildingDto) {
|
||||||
try {
|
await this.buildingService.addUserBuilding(addUserBuildingDto);
|
||||||
await this.buildingService.addUserBuilding(addUserBuildingDto);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.CREATED,
|
||||||
statusCode: HttpStatus.CREATED,
|
success: true,
|
||||||
success: true,
|
message: 'user building added successfully',
|
||||||
message: 'user building added successfully',
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Get('user/:userUuid')
|
@Get('user/:userUuid')
|
||||||
async getBuildingsByUserId(@Param('userUuid') userUuid: string) {
|
async getBuildingsByUserId(@Param('userUuid') userUuid: string) {
|
||||||
try {
|
return await this.buildingService.getBuildingsByUserId(userUuid);
|
||||||
return await this.buildingService.getBuildingsByUserId(userUuid);
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard, BuildingPermissionGuard)
|
@UseGuards(JwtAuthGuard, BuildingPermissionGuard)
|
||||||
@Put('rename/:buildingUuid')
|
@Put(':buildingUuid')
|
||||||
async renameBuildingByUuid(
|
async renameBuildingByUuid(
|
||||||
@Param('buildingUuid') buildingUuid: string,
|
@Param('buildingUuid') buildingUuid: string,
|
||||||
@Body() updateBuildingDto: UpdateBuildingNameDto,
|
@Body() updateBuildingDto: UpdateBuildingNameDto,
|
||||||
) {
|
) {
|
||||||
try {
|
const building = await this.buildingService.renameBuildingByUuid(
|
||||||
const building = await this.buildingService.renameBuildingByUuid(
|
buildingUuid,
|
||||||
buildingUuid,
|
updateBuildingDto,
|
||||||
updateBuildingDto,
|
);
|
||||||
);
|
return building;
|
||||||
return building;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { BooleanValues } from '@app/common/constants/boolean-values.enum';
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { Transform } from 'class-transformer';
|
import { Transform } from 'class-transformer';
|
||||||
import {
|
import {
|
||||||
@ -45,7 +46,7 @@ export class GetBuildingChildDto {
|
|||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
@Transform((value) => {
|
@Transform((value) => {
|
||||||
return value.obj.includeSubSpaces === 'true';
|
return value.obj.includeSubSpaces === BooleanValues.TRUE;
|
||||||
})
|
})
|
||||||
public includeSubSpaces: boolean = false;
|
public includeSubSpaces: boolean = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,8 @@ import {
|
|||||||
import { SpaceEntity } from '@app/common/modules/space/entities';
|
import { SpaceEntity } from '@app/common/modules/space/entities';
|
||||||
import { UpdateBuildingNameDto } from '../dtos/update.building.dto';
|
import { UpdateBuildingNameDto } from '../dtos/update.building.dto';
|
||||||
import { UserSpaceRepository } from '@app/common/modules/user/repositories';
|
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()
|
@Injectable()
|
||||||
export class BuildingService {
|
export class BuildingService {
|
||||||
@ -31,7 +33,7 @@ export class BuildingService {
|
|||||||
try {
|
try {
|
||||||
const spaceType = await this.spaceTypeRepository.findOne({
|
const spaceType = await this.spaceTypeRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
type: 'building',
|
type: SpaceType.BUILDING,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -61,7 +63,7 @@ export class BuildingService {
|
|||||||
where: {
|
where: {
|
||||||
uuid: buildingUuid,
|
uuid: buildingUuid,
|
||||||
spaceType: {
|
spaceType: {
|
||||||
type: 'building',
|
type: SpaceType.BUILDING,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
relations: ['spaceType'],
|
relations: ['spaceType'],
|
||||||
@ -69,7 +71,7 @@ export class BuildingService {
|
|||||||
if (
|
if (
|
||||||
!building ||
|
!building ||
|
||||||
!building.spaceType ||
|
!building.spaceType ||
|
||||||
building.spaceType.type !== 'building'
|
building.spaceType.type !== SpaceType.BUILDING
|
||||||
) {
|
) {
|
||||||
throw new BadRequestException('Invalid building UUID');
|
throw new BadRequestException('Invalid building UUID');
|
||||||
}
|
}
|
||||||
@ -99,7 +101,11 @@ export class BuildingService {
|
|||||||
where: { uuid: buildingUuid },
|
where: { uuid: buildingUuid },
|
||||||
relations: ['children', 'spaceType'],
|
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');
|
throw new BadRequestException('Invalid building UUID');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,8 +153,8 @@ export class BuildingService {
|
|||||||
return children
|
return children
|
||||||
.filter(
|
.filter(
|
||||||
(child) =>
|
(child) =>
|
||||||
child.spaceType.type !== 'building' &&
|
child.spaceType.type !== SpaceType.BUILDING &&
|
||||||
child.spaceType.type !== 'community',
|
child.spaceType.type !== SpaceType.COMMUNITY,
|
||||||
) // Filter remaining building and community types
|
) // Filter remaining building and community types
|
||||||
.map((child) => ({
|
.map((child) => ({
|
||||||
uuid: child.uuid,
|
uuid: child.uuid,
|
||||||
@ -161,8 +167,8 @@ export class BuildingService {
|
|||||||
children
|
children
|
||||||
.filter(
|
.filter(
|
||||||
(child) =>
|
(child) =>
|
||||||
child.spaceType.type !== 'building' &&
|
child.spaceType.type !== SpaceType.BUILDING &&
|
||||||
child.spaceType.type !== 'community',
|
child.spaceType.type !== SpaceType.COMMUNITY,
|
||||||
) // Filter remaining building and community types
|
) // Filter remaining building and community types
|
||||||
.map(async (child) => ({
|
.map(async (child) => ({
|
||||||
uuid: child.uuid,
|
uuid: child.uuid,
|
||||||
@ -183,7 +189,7 @@ export class BuildingService {
|
|||||||
where: {
|
where: {
|
||||||
uuid: buildingUuid,
|
uuid: buildingUuid,
|
||||||
spaceType: {
|
spaceType: {
|
||||||
type: 'building',
|
type: SpaceType.BUILDING,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
relations: ['spaceType', 'parent', 'parent.spaceType'],
|
relations: ['spaceType', 'parent', 'parent.spaceType'],
|
||||||
@ -191,7 +197,7 @@ export class BuildingService {
|
|||||||
if (
|
if (
|
||||||
!building ||
|
!building ||
|
||||||
!building.spaceType ||
|
!building.spaceType ||
|
||||||
building.spaceType.type !== 'building'
|
building.spaceType.type !== SpaceType.BUILDING
|
||||||
) {
|
) {
|
||||||
throw new BadRequestException('Invalid building UUID');
|
throw new BadRequestException('Invalid building UUID');
|
||||||
}
|
}
|
||||||
@ -222,7 +228,7 @@ export class BuildingService {
|
|||||||
relations: ['space', 'space.spaceType'],
|
relations: ['space', 'space.spaceType'],
|
||||||
where: {
|
where: {
|
||||||
user: { uuid: userUuid },
|
user: { uuid: userUuid },
|
||||||
space: { spaceType: { type: 'building' } },
|
space: { spaceType: { type: SpaceType.BUILDING } },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -254,7 +260,7 @@ export class BuildingService {
|
|||||||
space: { uuid: addUserBuildingDto.buildingUuid },
|
space: { uuid: addUserBuildingDto.buildingUuid },
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.code === '23505') {
|
if (err.code === CommonErrorCodes.DUPLICATE_ENTITY) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
'User already belongs to this building',
|
'User already belongs to this building',
|
||||||
HttpStatus.BAD_REQUEST,
|
HttpStatus.BAD_REQUEST,
|
||||||
@ -279,7 +285,7 @@ export class BuildingService {
|
|||||||
if (
|
if (
|
||||||
!building ||
|
!building ||
|
||||||
!building.spaceType ||
|
!building.spaceType ||
|
||||||
building.spaceType.type !== 'building'
|
building.spaceType.type !== SpaceType.BUILDING
|
||||||
) {
|
) {
|
||||||
throw new BadRequestException('Invalid building UUID');
|
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,
|
Body,
|
||||||
Controller,
|
Controller,
|
||||||
Get,
|
Get,
|
||||||
HttpException,
|
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
Param,
|
Param,
|
||||||
Post,
|
Post,
|
||||||
@ -18,15 +17,16 @@ import {
|
|||||||
} from '../dtos/add.community.dto';
|
} from '../dtos/add.community.dto';
|
||||||
import { GetCommunityChildDto } from '../dtos/get.community.dto';
|
import { GetCommunityChildDto } from '../dtos/get.community.dto';
|
||||||
import { UpdateCommunityNameDto } from '../dtos/update.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 { AdminRoleGuard } from 'src/guards/admin.role.guard';
|
||||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.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';
|
// import { CommunityPermissionGuard } from 'src/guards/community.permission.guard';
|
||||||
|
|
||||||
@ApiTags('Community Module')
|
@ApiTags('Community Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
version: '1',
|
version: EnableDisableStatusEnum.ENABLED,
|
||||||
path: 'community',
|
path: SpaceType.COMMUNITY,
|
||||||
})
|
})
|
||||||
export class CommunityController {
|
export class CommunityController {
|
||||||
constructor(private readonly communityService: CommunityService) {}
|
constructor(private readonly communityService: CommunityService) {}
|
||||||
@ -35,51 +35,29 @@ export class CommunityController {
|
|||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Post()
|
@Post()
|
||||||
async addCommunity(@Body() addCommunityDto: AddCommunityDto) {
|
async addCommunity(@Body() addCommunityDto: AddCommunityDto) {
|
||||||
try {
|
const community = await this.communityService.addCommunity(addCommunityDto);
|
||||||
const community =
|
return {
|
||||||
await this.communityService.addCommunity(addCommunityDto);
|
statusCode: HttpStatus.CREATED,
|
||||||
return {
|
success: true,
|
||||||
statusCode: HttpStatus.CREATED,
|
message: 'Community added successfully',
|
||||||
success: true,
|
data: community,
|
||||||
message: 'Community added successfully',
|
};
|
||||||
data: community,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Get(':communityUuid')
|
@Get(':communityUuid')
|
||||||
async getCommunityByUuid(@Param('communityUuid') communityUuid: string) {
|
async getCommunityByUuid(@Param('communityUuid') communityUuid: string) {
|
||||||
try {
|
const community =
|
||||||
const community =
|
await this.communityService.getCommunityByUuid(communityUuid);
|
||||||
await this.communityService.getCommunityByUuid(communityUuid);
|
return community;
|
||||||
return community;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Get()
|
@Get()
|
||||||
async getCommunities() {
|
async getCommunities() {
|
||||||
try {
|
const communities = await this.communityService.getCommunities();
|
||||||
const communities = await this.communityService.getCommunities();
|
return communities;
|
||||||
return communities;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@ -88,69 +66,41 @@ export class CommunityController {
|
|||||||
@Param('communityUuid') communityUuid: string,
|
@Param('communityUuid') communityUuid: string,
|
||||||
@Query() query: GetCommunityChildDto,
|
@Query() query: GetCommunityChildDto,
|
||||||
) {
|
) {
|
||||||
try {
|
const community = await this.communityService.getCommunityChildByUuid(
|
||||||
const community = await this.communityService.getCommunityChildByUuid(
|
communityUuid,
|
||||||
communityUuid,
|
query,
|
||||||
query,
|
);
|
||||||
);
|
return community;
|
||||||
return community;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Get('user/:userUuid')
|
@Get('user/:userUuid')
|
||||||
async getCommunitiesByUserId(@Param('userUuid') userUuid: string) {
|
async getCommunitiesByUserId(@Param('userUuid') userUuid: string) {
|
||||||
try {
|
return await this.communityService.getCommunitiesByUserId(userUuid);
|
||||||
return await this.communityService.getCommunitiesByUserId(userUuid);
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(AdminRoleGuard)
|
@UseGuards(AdminRoleGuard)
|
||||||
@Post('user')
|
@Post('user')
|
||||||
async addUserCommunity(@Body() addUserCommunityDto: AddUserCommunityDto) {
|
async addUserCommunity(@Body() addUserCommunityDto: AddUserCommunityDto) {
|
||||||
try {
|
await this.communityService.addUserCommunity(addUserCommunityDto);
|
||||||
await this.communityService.addUserCommunity(addUserCommunityDto);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.CREATED,
|
||||||
statusCode: HttpStatus.CREATED,
|
success: true,
|
||||||
success: true,
|
message: 'user community added successfully',
|
||||||
message: 'user community added successfully',
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Put('rename/:communityUuid')
|
@Put(':communityUuid')
|
||||||
async renameCommunityByUuid(
|
async renameCommunityByUuid(
|
||||||
@Param('communityUuid') communityUuid: string,
|
@Param('communityUuid') communityUuid: string,
|
||||||
@Body() updateCommunityDto: UpdateCommunityNameDto,
|
@Body() updateCommunityDto: UpdateCommunityNameDto,
|
||||||
) {
|
) {
|
||||||
try {
|
const community = await this.communityService.renameCommunityByUuid(
|
||||||
const community = await this.communityService.renameCommunityByUuid(
|
communityUuid,
|
||||||
communityUuid,
|
updateCommunityDto,
|
||||||
updateCommunityDto,
|
);
|
||||||
);
|
return community;
|
||||||
return community;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { BooleanValues } from '@app/common/constants/boolean-values.enum';
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { Transform } from 'class-transformer';
|
import { Transform } from 'class-transformer';
|
||||||
import {
|
import {
|
||||||
@ -45,7 +46,7 @@ export class GetCommunityChildDto {
|
|||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
@Transform((value) => {
|
@Transform((value) => {
|
||||||
return value.obj.includeSubSpaces === 'true';
|
return value.obj.includeSubSpaces === BooleanValues.TRUE;
|
||||||
})
|
})
|
||||||
public includeSubSpaces: boolean = false;
|
public includeSubSpaces: boolean = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,8 @@ import {
|
|||||||
import { SpaceEntity } from '@app/common/modules/space/entities';
|
import { SpaceEntity } from '@app/common/modules/space/entities';
|
||||||
import { UpdateCommunityNameDto } from '../dtos/update.community.dto';
|
import { UpdateCommunityNameDto } from '../dtos/update.community.dto';
|
||||||
import { UserSpaceRepository } from '@app/common/modules/user/repositories';
|
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()
|
@Injectable()
|
||||||
export class CommunityService {
|
export class CommunityService {
|
||||||
@ -31,7 +33,7 @@ export class CommunityService {
|
|||||||
try {
|
try {
|
||||||
const spaceType = await this.spaceTypeRepository.findOne({
|
const spaceType = await this.spaceTypeRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
type: 'community',
|
type: SpaceType.COMMUNITY,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -53,7 +55,7 @@ export class CommunityService {
|
|||||||
where: {
|
where: {
|
||||||
uuid: communityUuid,
|
uuid: communityUuid,
|
||||||
spaceType: {
|
spaceType: {
|
||||||
type: 'community',
|
type: SpaceType.COMMUNITY,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
relations: ['spaceType'],
|
relations: ['spaceType'],
|
||||||
@ -61,7 +63,7 @@ export class CommunityService {
|
|||||||
if (
|
if (
|
||||||
!community ||
|
!community ||
|
||||||
!community.spaceType ||
|
!community.spaceType ||
|
||||||
community.spaceType.type !== 'community'
|
community.spaceType.type !== SpaceType.COMMUNITY
|
||||||
) {
|
) {
|
||||||
throw new BadRequestException('Invalid community UUID');
|
throw new BadRequestException('Invalid community UUID');
|
||||||
}
|
}
|
||||||
@ -83,7 +85,7 @@ export class CommunityService {
|
|||||||
async getCommunities(): Promise<GetCommunitiesInterface> {
|
async getCommunities(): Promise<GetCommunitiesInterface> {
|
||||||
try {
|
try {
|
||||||
const community = await this.spaceRepository.find({
|
const community = await this.spaceRepository.find({
|
||||||
where: { spaceType: { type: 'community' } },
|
where: { spaceType: { type: SpaceType.COMMUNITY } },
|
||||||
relations: ['spaceType'],
|
relations: ['spaceType'],
|
||||||
});
|
});
|
||||||
return community.map((community) => ({
|
return community.map((community) => ({
|
||||||
@ -109,7 +111,11 @@ export class CommunityService {
|
|||||||
relations: ['children', 'spaceType'],
|
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');
|
throw new BadRequestException('Invalid community UUID');
|
||||||
}
|
}
|
||||||
const totalCount = await this.spaceRepository.count({
|
const totalCount = await this.spaceRepository.count({
|
||||||
@ -152,7 +158,7 @@ export class CommunityService {
|
|||||||
|
|
||||||
if (!children || children.length === 0 || !includeSubSpaces) {
|
if (!children || children.length === 0 || !includeSubSpaces) {
|
||||||
return children
|
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) => ({
|
.map((child) => ({
|
||||||
uuid: child.uuid,
|
uuid: child.uuid,
|
||||||
name: child.spaceName,
|
name: child.spaceName,
|
||||||
@ -162,7 +168,7 @@ export class CommunityService {
|
|||||||
|
|
||||||
const childHierarchies = await Promise.all(
|
const childHierarchies = await Promise.all(
|
||||||
children
|
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) => ({
|
.map(async (child) => ({
|
||||||
uuid: child.uuid,
|
uuid: child.uuid,
|
||||||
name: child.spaceName,
|
name: child.spaceName,
|
||||||
@ -182,7 +188,7 @@ export class CommunityService {
|
|||||||
relations: ['space', 'space.spaceType'],
|
relations: ['space', 'space.spaceType'],
|
||||||
where: {
|
where: {
|
||||||
user: { uuid: userUuid },
|
user: { uuid: userUuid },
|
||||||
space: { spaceType: { type: 'community' } },
|
space: { spaceType: { type: SpaceType.COMMUNITY } },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -215,7 +221,7 @@ export class CommunityService {
|
|||||||
space: { uuid: addUserCommunityDto.communityUuid },
|
space: { uuid: addUserCommunityDto.communityUuid },
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.code === '23505') {
|
if (err.code === CommonErrorCodes.DUPLICATE_ENTITY) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
'User already belongs to this community',
|
'User already belongs to this community',
|
||||||
HttpStatus.BAD_REQUEST,
|
HttpStatus.BAD_REQUEST,
|
||||||
@ -240,7 +246,7 @@ export class CommunityService {
|
|||||||
if (
|
if (
|
||||||
!community ||
|
!community ||
|
||||||
!community.spaceType ||
|
!community.spaceType ||
|
||||||
community.spaceType.type !== 'community'
|
community.spaceType.type !== SpaceType.COMMUNITY
|
||||||
) {
|
) {
|
||||||
throw new BadRequestException('Invalid community UUID');
|
throw new BadRequestException('Invalid community UUID');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import {
|
|||||||
Controller,
|
Controller,
|
||||||
Delete,
|
Delete,
|
||||||
Get,
|
Get,
|
||||||
HttpException,
|
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
Param,
|
Param,
|
||||||
Post,
|
Post,
|
||||||
@ -14,10 +13,11 @@ import { DeviceMessagesSubscriptionService } from '../services/device-messages.s
|
|||||||
import { DeviceMessagesAddDto } from '../dtos/device-messages.dto';
|
import { DeviceMessagesAddDto } from '../dtos/device-messages.dto';
|
||||||
|
|
||||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||||
|
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||||
|
|
||||||
@ApiTags('Device Messages Status Module')
|
@ApiTags('Device Messages Status Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
version: '1',
|
version: EnableDisableStatusEnum.ENABLED,
|
||||||
path: 'device-messages/subscription',
|
path: 'device-messages/subscription',
|
||||||
})
|
})
|
||||||
export class DeviceMessagesSubscriptionController {
|
export class DeviceMessagesSubscriptionController {
|
||||||
@ -31,22 +31,15 @@ export class DeviceMessagesSubscriptionController {
|
|||||||
async addDeviceMessagesSubscription(
|
async addDeviceMessagesSubscription(
|
||||||
@Body() deviceMessagesAddDto: DeviceMessagesAddDto,
|
@Body() deviceMessagesAddDto: DeviceMessagesAddDto,
|
||||||
) {
|
) {
|
||||||
try {
|
const addDetails =
|
||||||
const addDetails =
|
await this.deviceMessagesSubscriptionService.addDeviceMessagesSubscription(
|
||||||
await this.deviceMessagesSubscriptionService.addDeviceMessagesSubscription(
|
deviceMessagesAddDto,
|
||||||
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,
|
|
||||||
);
|
);
|
||||||
}
|
return {
|
||||||
|
statusCode: HttpStatus.CREATED,
|
||||||
|
message: 'Device Messages Subscription Added Successfully',
|
||||||
|
data: addDetails,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@ -56,23 +49,16 @@ export class DeviceMessagesSubscriptionController {
|
|||||||
@Param('deviceUuid') deviceUuid: string,
|
@Param('deviceUuid') deviceUuid: string,
|
||||||
@Param('userUuid') userUuid: string,
|
@Param('userUuid') userUuid: string,
|
||||||
) {
|
) {
|
||||||
try {
|
const deviceDetails =
|
||||||
const deviceDetails =
|
await this.deviceMessagesSubscriptionService.getDeviceMessagesSubscription(
|
||||||
await this.deviceMessagesSubscriptionService.getDeviceMessagesSubscription(
|
userUuid,
|
||||||
userUuid,
|
deviceUuid,
|
||||||
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,
|
|
||||||
);
|
);
|
||||||
}
|
return {
|
||||||
|
statusCode: HttpStatus.OK,
|
||||||
|
message: 'User Device Subscription fetched Successfully',
|
||||||
|
data: deviceDetails,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@ -80,19 +66,12 @@ export class DeviceMessagesSubscriptionController {
|
|||||||
async deleteDeviceMessagesSubscription(
|
async deleteDeviceMessagesSubscription(
|
||||||
@Body() deviceMessagesAddDto: DeviceMessagesAddDto,
|
@Body() deviceMessagesAddDto: DeviceMessagesAddDto,
|
||||||
) {
|
) {
|
||||||
try {
|
await this.deviceMessagesSubscriptionService.deleteDeviceMessagesSubscription(
|
||||||
await this.deviceMessagesSubscriptionService.deleteDeviceMessagesSubscription(
|
deviceMessagesAddDto,
|
||||||
deviceMessagesAddDto,
|
);
|
||||||
);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.OK,
|
||||||
statusCode: HttpStatus.OK,
|
message: 'User subscription deleted Successfully',
|
||||||
message: 'User subscription deleted Successfully',
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
import { DeviceMessagesAddDto } from '../dtos/device-messages.dto';
|
import { DeviceMessagesAddDto } from '../dtos/device-messages.dto';
|
||||||
import { DeviceNotificationRepository } from '@app/common/modules/device/repositories';
|
import { DeviceNotificationRepository } from '@app/common/modules/device/repositories';
|
||||||
|
import { CommonErrorCodes } from '@app/common/constants/error-codes.enum';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DeviceMessagesSubscriptionService {
|
export class DeviceMessagesSubscriptionService {
|
||||||
@ -21,7 +22,7 @@ export class DeviceMessagesSubscriptionService {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.code === '23505') {
|
if (error.code === CommonErrorCodes.DUPLICATE_ENTITY) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
'This User already belongs to this device',
|
'This User already belongs to this device',
|
||||||
HttpStatus.BAD_REQUEST,
|
HttpStatus.BAD_REQUEST,
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import {
|
|||||||
Post,
|
Post,
|
||||||
Query,
|
Query,
|
||||||
Param,
|
Param,
|
||||||
HttpException,
|
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
UseGuards,
|
UseGuards,
|
||||||
Req,
|
Req,
|
||||||
@ -18,17 +17,24 @@ import {
|
|||||||
GetDeviceByRoomUuidDto,
|
GetDeviceByRoomUuidDto,
|
||||||
GetDeviceLogsDto,
|
GetDeviceLogsDto,
|
||||||
} from '../dtos/get.device.dto';
|
} 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 { CheckRoomGuard } from 'src/guards/room.guard';
|
||||||
import { CheckUserHavePermission } from 'src/guards/user.device.permission.guard';
|
import { CheckUserHavePermission } from 'src/guards/user.device.permission.guard';
|
||||||
import { CheckUserHaveControllablePermission } from 'src/guards/user.device.controllable.permission.guard';
|
import { CheckUserHaveControllablePermission } from 'src/guards/user.device.controllable.permission.guard';
|
||||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||||
import { CheckDeviceGuard } from 'src/guards/device.guard';
|
import { CheckDeviceGuard } from 'src/guards/device.guard';
|
||||||
import { SuperAdminRoleGuard } from 'src/guards/super.admin.role.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')
|
@ApiTags('Device Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
version: '1',
|
version: EnableDisableStatusEnum.ENABLED,
|
||||||
path: 'device',
|
path: 'device',
|
||||||
})
|
})
|
||||||
export class DeviceController {
|
export class DeviceController {
|
||||||
@ -37,67 +43,39 @@ export class DeviceController {
|
|||||||
@UseGuards(SuperAdminRoleGuard, CheckDeviceGuard)
|
@UseGuards(SuperAdminRoleGuard, CheckDeviceGuard)
|
||||||
@Post()
|
@Post()
|
||||||
async addDeviceUser(@Body() addDeviceDto: AddDeviceDto) {
|
async addDeviceUser(@Body() addDeviceDto: AddDeviceDto) {
|
||||||
try {
|
const device = await this.deviceService.addDeviceUser(addDeviceDto);
|
||||||
const device = await this.deviceService.addDeviceUser(addDeviceDto);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: HttpStatus.CREATED,
|
statusCode: HttpStatus.CREATED,
|
||||||
success: true,
|
success: true,
|
||||||
message: 'device added successfully',
|
message: 'device added successfully',
|
||||||
data: device,
|
data: device,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Get('user/:userUuid')
|
@Get('user/:userUuid')
|
||||||
async getDevicesByUser(@Param('userUuid') userUuid: string) {
|
async getDevicesByUser(@Param('userUuid') userUuid: string) {
|
||||||
try {
|
return await this.deviceService.getDevicesByUser(userUuid);
|
||||||
return await this.deviceService.getDevicesByUser(userUuid);
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard, CheckRoomGuard)
|
@UseGuards(JwtAuthGuard, CheckRoomGuard)
|
||||||
@Get('room')
|
@Get(SpaceType.ROOM)
|
||||||
async getDevicesByRoomId(
|
async getDevicesByRoomId(
|
||||||
@Query() getDeviceByRoomUuidDto: GetDeviceByRoomUuidDto,
|
@Query() getDeviceByRoomUuidDto: GetDeviceByRoomUuidDto,
|
||||||
@Req() req: any,
|
@Req() req: any,
|
||||||
) {
|
) {
|
||||||
try {
|
const userUuid = req.user.uuid;
|
||||||
const userUuid = req.user.uuid;
|
return await this.deviceService.getDevicesByRoomId(
|
||||||
return await this.deviceService.getDevicesByRoomId(
|
getDeviceByRoomUuidDto,
|
||||||
getDeviceByRoomUuidDto,
|
userUuid,
|
||||||
userUuid,
|
);
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Get('unit/:unitUuid')
|
@Get('unit/:unitUuid')
|
||||||
async getDevicesByUnitId(@Param('unitUuid') unitUuid: string) {
|
async getDevicesByUnitId(@Param('unitUuid') unitUuid: string) {
|
||||||
try {
|
return await this.deviceService.getDevicesByUnitId(unitUuid);
|
||||||
return await this.deviceService.getDevicesByUnitId(unitUuid);
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard, CheckRoomGuard)
|
@UseGuards(JwtAuthGuard, CheckRoomGuard)
|
||||||
@ -105,23 +83,16 @@ export class DeviceController {
|
|||||||
async updateDeviceInRoom(
|
async updateDeviceInRoom(
|
||||||
@Body() updateDeviceInRoomDto: UpdateDeviceInRoomDto,
|
@Body() updateDeviceInRoomDto: UpdateDeviceInRoomDto,
|
||||||
) {
|
) {
|
||||||
try {
|
const device = await this.deviceService.updateDeviceInRoom(
|
||||||
const device = await this.deviceService.updateDeviceInRoom(
|
updateDeviceInRoomDto,
|
||||||
updateDeviceInRoomDto,
|
);
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: HttpStatus.CREATED,
|
statusCode: HttpStatus.CREATED,
|
||||||
success: true,
|
success: true,
|
||||||
message: 'device updated in room successfully',
|
message: 'device updated in room successfully',
|
||||||
data: device,
|
data: device,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@ -131,18 +102,11 @@ export class DeviceController {
|
|||||||
@Param('deviceUuid') deviceUuid: string,
|
@Param('deviceUuid') deviceUuid: string,
|
||||||
@Req() req: any,
|
@Req() req: any,
|
||||||
) {
|
) {
|
||||||
try {
|
const userUuid = req.user.uuid;
|
||||||
const userUuid = req.user.uuid;
|
return await this.deviceService.getDeviceDetailsByDeviceId(
|
||||||
return await this.deviceService.getDeviceDetailsByDeviceId(
|
deviceUuid,
|
||||||
deviceUuid,
|
userUuid,
|
||||||
userUuid,
|
);
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard, CheckUserHavePermission)
|
@UseGuards(JwtAuthGuard, CheckUserHavePermission)
|
||||||
@ -150,29 +114,13 @@ export class DeviceController {
|
|||||||
async getDeviceInstructionByDeviceId(
|
async getDeviceInstructionByDeviceId(
|
||||||
@Param('deviceUuid') deviceUuid: string,
|
@Param('deviceUuid') deviceUuid: string,
|
||||||
) {
|
) {
|
||||||
try {
|
return await this.deviceService.getDeviceInstructionByDeviceId(deviceUuid);
|
||||||
return await this.deviceService.getDeviceInstructionByDeviceId(
|
|
||||||
deviceUuid,
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard, CheckUserHavePermission)
|
@UseGuards(JwtAuthGuard, CheckUserHavePermission)
|
||||||
@Get(':deviceUuid/functions/status')
|
@Get(':deviceUuid/functions/status')
|
||||||
async getDevicesInstructionStatus(@Param('deviceUuid') deviceUuid: string) {
|
async getDevicesInstructionStatus(@Param('deviceUuid') deviceUuid: string) {
|
||||||
try {
|
return await this.deviceService.getDevicesInstructionStatus(deviceUuid);
|
||||||
return await this.deviceService.getDevicesInstructionStatus(deviceUuid);
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@ -182,17 +130,7 @@ export class DeviceController {
|
|||||||
@Body() controlDeviceDto: ControlDeviceDto,
|
@Body() controlDeviceDto: ControlDeviceDto,
|
||||||
@Param('deviceUuid') deviceUuid: string,
|
@Param('deviceUuid') deviceUuid: string,
|
||||||
) {
|
) {
|
||||||
try {
|
return await this.deviceService.controlDevice(controlDeviceDto, deviceUuid);
|
||||||
return await this.deviceService.controlDevice(
|
|
||||||
controlDeviceDto,
|
|
||||||
deviceUuid,
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@ -201,43 +139,22 @@ export class DeviceController {
|
|||||||
@Param('deviceUuid') deviceUuid: string,
|
@Param('deviceUuid') deviceUuid: string,
|
||||||
@Param('firmwareVersion') firmwareVersion: number,
|
@Param('firmwareVersion') firmwareVersion: number,
|
||||||
) {
|
) {
|
||||||
try {
|
return await this.deviceService.updateDeviceFirmware(
|
||||||
return await this.deviceService.updateDeviceFirmware(
|
deviceUuid,
|
||||||
deviceUuid,
|
firmwareVersion,
|
||||||
firmwareVersion,
|
);
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Get('gateway/:gatewayUuid/devices')
|
@Get('gateway/:gatewayUuid/devices')
|
||||||
async getDevicesInGateway(@Param('gatewayUuid') gatewayUuid: string) {
|
async getDevicesInGateway(@Param('gatewayUuid') gatewayUuid: string) {
|
||||||
try {
|
return await this.deviceService.getDevicesInGateway(gatewayUuid);
|
||||||
return await this.deviceService.getDevicesInGateway(gatewayUuid);
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Get()
|
@Get()
|
||||||
async getAllDevices() {
|
async getAllDevices() {
|
||||||
try {
|
return await this.deviceService.getAllDevices();
|
||||||
return await this.deviceService.getAllDevices();
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@ -246,13 +163,32 @@ export class DeviceController {
|
|||||||
@Param('deviceUuid') deviceUuid: string,
|
@Param('deviceUuid') deviceUuid: string,
|
||||||
@Query() query: GetDeviceLogsDto,
|
@Query() query: GetDeviceLogsDto,
|
||||||
) {
|
) {
|
||||||
try {
|
return await this.deviceService.getDeviceLogs(deviceUuid, query);
|
||||||
return await this.deviceService.getDeviceLogs(deviceUuid, query);
|
}
|
||||||
} catch (error) {
|
@ApiBearerAuth()
|
||||||
throw new HttpException(
|
@UseGuards(JwtAuthGuard)
|
||||||
error.message || 'Internal server error',
|
@Post('control/batch')
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
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 { ApiProperty } from '@nestjs/swagger';
|
||||||
import { IsNotEmpty, IsString } from 'class-validator';
|
import { IsArray, IsNotEmpty, IsString } from 'class-validator';
|
||||||
|
|
||||||
export class ControlDeviceDto {
|
export class ControlDeviceDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
@ -16,3 +16,41 @@ export class ControlDeviceDto {
|
|||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
public value: any;
|
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 { ApiProperty } from '@nestjs/swagger';
|
||||||
import { IsNotEmpty, IsString } from 'class-validator';
|
import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||||
|
|
||||||
export class GetDeviceByRoomUuidDto {
|
export class GetDeviceByRoomUuidDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
@ -18,4 +18,18 @@ export class GetDeviceLogsDto {
|
|||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
public code: string;
|
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 {
|
export interface getDeviceLogsInterface {
|
||||||
data: [];
|
data: [];
|
||||||
startTime: number;
|
startTime: string;
|
||||||
endTime: number;
|
endTime: string;
|
||||||
deviceUuid?: string;
|
deviceUuid?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,12 @@ import {
|
|||||||
GetDeviceByRoomUuidDto,
|
GetDeviceByRoomUuidDto,
|
||||||
GetDeviceLogsDto,
|
GetDeviceLogsDto,
|
||||||
} from '../dtos/get.device.dto';
|
} 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 { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter';
|
||||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||||
import { PermissionType } from '@app/common/constants/permission-type.enum';
|
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 { ProductType } from '@app/common/constants/product-type.enum';
|
||||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||||
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service';
|
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()
|
@Injectable()
|
||||||
export class DeviceService {
|
export class DeviceService {
|
||||||
@ -101,7 +109,7 @@ export class DeviceService {
|
|||||||
}
|
}
|
||||||
return deviceSaved;
|
return deviceSaved;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.code === '23505') {
|
if (error.code === CommonErrorCodes.DUPLICATE_ENTITY) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
'Device already exists',
|
'Device already exists',
|
||||||
HttpStatus.BAD_REQUEST,
|
HttpStatus.BAD_REQUEST,
|
||||||
@ -121,6 +129,7 @@ export class DeviceService {
|
|||||||
const devices = await this.deviceRepository.find({
|
const devices = await this.deviceRepository.find({
|
||||||
where: {
|
where: {
|
||||||
user: { uuid: userUuid },
|
user: { uuid: userUuid },
|
||||||
|
isActive: true,
|
||||||
permission: {
|
permission: {
|
||||||
userUuid,
|
userUuid,
|
||||||
permissionType: {
|
permissionType: {
|
||||||
@ -167,6 +176,7 @@ export class DeviceService {
|
|||||||
const devices = await this.deviceRepository.find({
|
const devices = await this.deviceRepository.find({
|
||||||
where: {
|
where: {
|
||||||
spaceDevice: { uuid: getDeviceByRoomUuidDto.roomUuid },
|
spaceDevice: { uuid: getDeviceByRoomUuidDto.roomUuid },
|
||||||
|
isActive: true,
|
||||||
permission: {
|
permission: {
|
||||||
userUuid,
|
userUuid,
|
||||||
permissionType: {
|
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(
|
async controlDeviceTuya(
|
||||||
deviceUuid: string,
|
deviceUuid: string,
|
||||||
controlDeviceDto: ControlDeviceDto,
|
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) {
|
async getDeviceDetailsByDeviceId(deviceUuid: string, userUuid: string) {
|
||||||
try {
|
try {
|
||||||
const userDevicePermission = await this.getUserDevicePermission(
|
const userDevicePermission = await this.getUserDevicePermission(
|
||||||
@ -359,7 +544,7 @@ export class DeviceService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const { productName, productId, id, ...rest } = camelCaseResponse.result;
|
const { productId, id, ...rest } = camelCaseResponse.result;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...rest,
|
...rest,
|
||||||
@ -492,19 +677,25 @@ export class DeviceService {
|
|||||||
|
|
||||||
const devices = await Promise.all(
|
const devices = await Promise.all(
|
||||||
response.map(async (device: any) => {
|
response.map(async (device: any) => {
|
||||||
const deviceDetails = await this.getDeviceByDeviceTuyaUuid(device.id);
|
try {
|
||||||
if (deviceDetails.deviceTuyaUuid) {
|
const deviceDetails = await this.getDeviceByDeviceTuyaUuid(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
device.id,
|
||||||
const { id, ...rest } = device;
|
);
|
||||||
return {
|
if (deviceDetails.deviceTuyaUuid) {
|
||||||
...rest,
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
tuyaUuid: deviceDetails.deviceTuyaUuid,
|
const { id, ...rest } = device;
|
||||||
uuid: deviceDetails.uuid,
|
return {
|
||||||
productUuid: deviceDetails.productDevice.uuid,
|
...rest,
|
||||||
productType: deviceDetails.productDevice.prodType,
|
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: {
|
parent: {
|
||||||
uuid: unitUuid,
|
uuid: unitUuid,
|
||||||
},
|
},
|
||||||
|
devicesSpaceEntity: {
|
||||||
|
isActive: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
relations: ['devicesSpaceEntity', 'devicesSpaceEntity.productDevice'],
|
relations: ['devicesSpaceEntity', 'devicesSpaceEntity.productDevice'],
|
||||||
});
|
});
|
||||||
@ -627,6 +821,7 @@ export class DeviceService {
|
|||||||
async getAllDevices(): Promise<GetDeviceDetailsInterface[]> {
|
async getAllDevices(): Promise<GetDeviceDetailsInterface[]> {
|
||||||
try {
|
try {
|
||||||
const devices = await this.deviceRepository.find({
|
const devices = await this.deviceRepository.find({
|
||||||
|
where: { isActive: true },
|
||||||
relations: [
|
relations: [
|
||||||
'spaceDevice.parent',
|
'spaceDevice.parent',
|
||||||
'productDevice',
|
'productDevice',
|
||||||
@ -644,14 +839,40 @@ export class DeviceService {
|
|||||||
await this.getDevicesInstructionStatus(device.uuid);
|
await this.getDevicesInstructionStatus(device.uuid);
|
||||||
|
|
||||||
const batteryStatus: any = doorLockInstructionsStatus.status.find(
|
const batteryStatus: any = doorLockInstructionsStatus.status.find(
|
||||||
(status: any) => status.code === 'residual_electricity',
|
(status: any) =>
|
||||||
|
status.code === BatteryStatus.RESIDUAL_ELECTRICITY,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (batteryStatus) {
|
if (batteryStatus) {
|
||||||
battery = batteryStatus.value;
|
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 spaceDevice = device?.spaceDevice;
|
||||||
const parentDevice = spaceDevice?.parent;
|
const parentDevice = spaceDevice?.parent;
|
||||||
return {
|
return {
|
||||||
@ -677,7 +898,7 @@ export class DeviceService {
|
|||||||
|
|
||||||
// Filter out rejected promises and extract the fulfilled values
|
// Filter out rejected promises and extract the fulfilled values
|
||||||
const fulfilledDevices = devicesData
|
const fulfilledDevices = devicesData
|
||||||
.filter((result) => result.status === 'fulfilled')
|
.filter((result) => result.status === DeviceStatuses.FULLFILLED)
|
||||||
.map(
|
.map(
|
||||||
(result) =>
|
(result) =>
|
||||||
(result as PromiseFulfilledResult<GetDeviceDetailsInterface>).value,
|
(result as PromiseFulfilledResult<GetDeviceDetailsInterface>).value,
|
||||||
@ -702,6 +923,8 @@ export class DeviceService {
|
|||||||
const response = await this.getDeviceLogsTuya(
|
const response = await this.getDeviceLogsTuya(
|
||||||
deviceDetails.deviceTuyaUuid,
|
deviceDetails.deviceTuyaUuid,
|
||||||
query.code,
|
query.code,
|
||||||
|
query.startTime,
|
||||||
|
query.endTime,
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -718,11 +941,11 @@ export class DeviceService {
|
|||||||
async getDeviceLogsTuya(
|
async getDeviceLogsTuya(
|
||||||
deviceId: string,
|
deviceId: string,
|
||||||
code: string,
|
code: string,
|
||||||
|
startTime: string = (Date.now() - 1 * 60 * 60 * 1000).toString(),
|
||||||
|
endTime: string = Date.now().toString(),
|
||||||
): Promise<getDeviceLogsInterface> {
|
): Promise<getDeviceLogsInterface> {
|
||||||
try {
|
try {
|
||||||
const now = Date.now();
|
const path = `/v2.0/cloud/thing/${deviceId}/report-logs?start_time=${startTime}&end_time=${endTime}&codes=${code}&size=50`;
|
||||||
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 response = await this.tuya.request({
|
const response = await this.tuya.request({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path,
|
path,
|
||||||
@ -731,8 +954,8 @@ export class DeviceService {
|
|||||||
const camelCaseResponse = convertKeysToCamelCase(response);
|
const camelCaseResponse = convertKeysToCamelCase(response);
|
||||||
const logs = camelCaseResponse.result.logs ?? [];
|
const logs = camelCaseResponse.result.logs ?? [];
|
||||||
return {
|
return {
|
||||||
startTime: oneHourAgo,
|
startTime,
|
||||||
endTime: now,
|
endTime,
|
||||||
data: logs,
|
data: logs,
|
||||||
} as getDeviceLogsInterface;
|
} as getDeviceLogsInterface;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import {
|
|||||||
Controller,
|
Controller,
|
||||||
Post,
|
Post,
|
||||||
Param,
|
Param,
|
||||||
HttpException,
|
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
Get,
|
Get,
|
||||||
Delete,
|
Delete,
|
||||||
@ -16,10 +15,11 @@ import { AddDoorLockOnlineDto } from '../dtos/add.online-temp.dto';
|
|||||||
import { AddDoorLockOfflineTempMultipleTimeDto } from '../dtos/add.offline-temp.dto';
|
import { AddDoorLockOfflineTempMultipleTimeDto } from '../dtos/add.offline-temp.dto';
|
||||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||||
import { UpdateDoorLockOfflineTempDto } from '../dtos/update.offline-temp.dto';
|
import { UpdateDoorLockOfflineTempDto } from '../dtos/update.offline-temp.dto';
|
||||||
|
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||||
|
|
||||||
@ApiTags('Door Lock Module')
|
@ApiTags('Door Lock Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
version: '1',
|
version: EnableDisableStatusEnum.ENABLED,
|
||||||
path: 'door-lock',
|
path: 'door-lock',
|
||||||
})
|
})
|
||||||
export class DoorLockController {
|
export class DoorLockController {
|
||||||
@ -31,27 +31,20 @@ export class DoorLockController {
|
|||||||
@Body() addDoorLockDto: AddDoorLockOnlineDto,
|
@Body() addDoorLockDto: AddDoorLockOnlineDto,
|
||||||
@Param('doorLockUuid') doorLockUuid: string,
|
@Param('doorLockUuid') doorLockUuid: string,
|
||||||
) {
|
) {
|
||||||
try {
|
const temporaryPassword =
|
||||||
const temporaryPassword =
|
await this.doorLockService.addOnlineTemporaryPassword(
|
||||||
await this.doorLockService.addOnlineTemporaryPassword(
|
addDoorLockDto,
|
||||||
addDoorLockDto,
|
doorLockUuid,
|
||||||
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,
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
return {
|
||||||
|
statusCode: HttpStatus.CREATED,
|
||||||
|
success: true,
|
||||||
|
message: 'online temporary password added successfully',
|
||||||
|
data: {
|
||||||
|
id: temporaryPassword.id,
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@ -59,24 +52,17 @@ export class DoorLockController {
|
|||||||
async addOfflineOneTimeTemporaryPassword(
|
async addOfflineOneTimeTemporaryPassword(
|
||||||
@Param('doorLockUuid') doorLockUuid: string,
|
@Param('doorLockUuid') doorLockUuid: string,
|
||||||
) {
|
) {
|
||||||
try {
|
const temporaryPassword =
|
||||||
const temporaryPassword =
|
await this.doorLockService.addOfflineOneTimeTemporaryPassword(
|
||||||
await this.doorLockService.addOfflineOneTimeTemporaryPassword(
|
doorLockUuid,
|
||||||
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,
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
return {
|
||||||
|
statusCode: HttpStatus.CREATED,
|
||||||
|
success: true,
|
||||||
|
message: 'offline temporary password added successfully',
|
||||||
|
data: temporaryPassword,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@ -86,25 +72,18 @@ export class DoorLockController {
|
|||||||
addDoorLockOfflineTempMultipleTimeDto: AddDoorLockOfflineTempMultipleTimeDto,
|
addDoorLockOfflineTempMultipleTimeDto: AddDoorLockOfflineTempMultipleTimeDto,
|
||||||
@Param('doorLockUuid') doorLockUuid: string,
|
@Param('doorLockUuid') doorLockUuid: string,
|
||||||
) {
|
) {
|
||||||
try {
|
const temporaryPassword =
|
||||||
const temporaryPassword =
|
await this.doorLockService.addOfflineMultipleTimeTemporaryPassword(
|
||||||
await this.doorLockService.addOfflineMultipleTimeTemporaryPassword(
|
addDoorLockOfflineTempMultipleTimeDto,
|
||||||
addDoorLockOfflineTempMultipleTimeDto,
|
doorLockUuid,
|
||||||
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,
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
return {
|
||||||
|
statusCode: HttpStatus.CREATED,
|
||||||
|
success: true,
|
||||||
|
message: 'offline temporary password added successfully',
|
||||||
|
data: temporaryPassword,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@ -112,16 +91,9 @@ export class DoorLockController {
|
|||||||
async getOnlineTemporaryPasswords(
|
async getOnlineTemporaryPasswords(
|
||||||
@Param('doorLockUuid') doorLockUuid: string,
|
@Param('doorLockUuid') doorLockUuid: string,
|
||||||
) {
|
) {
|
||||||
try {
|
return await this.doorLockService.getOnlineTemporaryPasswordsMultiple(
|
||||||
return await this.doorLockService.getOnlineTemporaryPasswordsMultiple(
|
doorLockUuid,
|
||||||
doorLockUuid,
|
);
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@ -130,21 +102,11 @@ export class DoorLockController {
|
|||||||
@Param('doorLockUuid') doorLockUuid: string,
|
@Param('doorLockUuid') doorLockUuid: string,
|
||||||
@Param('passwordId') passwordId: string,
|
@Param('passwordId') passwordId: string,
|
||||||
) {
|
) {
|
||||||
try {
|
await this.doorLockService.deleteDoorLockPassword(doorLockUuid, passwordId);
|
||||||
await this.doorLockService.deleteDoorLockPassword(
|
return {
|
||||||
doorLockUuid,
|
statusCode: HttpStatus.OK,
|
||||||
passwordId,
|
message: 'Temporary Password deleted Successfully',
|
||||||
);
|
};
|
||||||
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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@ -152,16 +114,9 @@ export class DoorLockController {
|
|||||||
async getOfflineOneTimeTemporaryPasswords(
|
async getOfflineOneTimeTemporaryPasswords(
|
||||||
@Param('doorLockUuid') doorLockUuid: string,
|
@Param('doorLockUuid') doorLockUuid: string,
|
||||||
) {
|
) {
|
||||||
try {
|
return await this.doorLockService.getOfflineOneTimeTemporaryPasswords(
|
||||||
return await this.doorLockService.getOfflineOneTimeTemporaryPasswords(
|
doorLockUuid,
|
||||||
doorLockUuid,
|
);
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@ -169,16 +124,9 @@ export class DoorLockController {
|
|||||||
async getOfflineMultipleTimeTemporaryPasswords(
|
async getOfflineMultipleTimeTemporaryPasswords(
|
||||||
@Param('doorLockUuid') doorLockUuid: string,
|
@Param('doorLockUuid') doorLockUuid: string,
|
||||||
) {
|
) {
|
||||||
try {
|
return await this.doorLockService.getOfflineMultipleTimeTemporaryPasswords(
|
||||||
return await this.doorLockService.getOfflineMultipleTimeTemporaryPasswords(
|
doorLockUuid,
|
||||||
doorLockUuid,
|
);
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@ -190,44 +138,30 @@ export class DoorLockController {
|
|||||||
@Param('doorLockUuid') doorLockUuid: string,
|
@Param('doorLockUuid') doorLockUuid: string,
|
||||||
@Param('passwordId') passwordId: string,
|
@Param('passwordId') passwordId: string,
|
||||||
) {
|
) {
|
||||||
try {
|
const temporaryPassword =
|
||||||
const temporaryPassword =
|
await this.doorLockService.updateOfflineTemporaryPassword(
|
||||||
await this.doorLockService.updateOfflineTemporaryPassword(
|
updateDoorLockOfflineTempDto,
|
||||||
updateDoorLockOfflineTempDto,
|
doorLockUuid,
|
||||||
doorLockUuid,
|
passwordId,
|
||||||
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,
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
return {
|
||||||
|
statusCode: HttpStatus.CREATED,
|
||||||
|
success: true,
|
||||||
|
message: 'offline temporary password updated successfully',
|
||||||
|
data: temporaryPassword,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Post('open/:doorLockUuid')
|
@Post('open/:doorLockUuid')
|
||||||
async openDoorLock(@Param('doorLockUuid') doorLockUuid: string) {
|
async openDoorLock(@Param('doorLockUuid') doorLockUuid: string) {
|
||||||
try {
|
await this.doorLockService.openDoorLock(doorLockUuid);
|
||||||
await this.doorLockService.openDoorLock(doorLockUuid);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: HttpStatus.CREATED,
|
statusCode: HttpStatus.CREATED,
|
||||||
success: true,
|
success: true,
|
||||||
message: 'door lock opened successfully',
|
message: 'door lock opened successfully',
|
||||||
};
|
};
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,6 +24,15 @@ import { UpdateDoorLockOfflineTempDto } from '../dtos/update.offline-temp.dto';
|
|||||||
import { defaultDoorLockPass } from '@app/common/constants/default.door-lock-pass';
|
import { defaultDoorLockPass } from '@app/common/constants/default.door-lock-pass';
|
||||||
import { VisitorPasswordRepository } from '@app/common/modules/visitor-password/repositories';
|
import { VisitorPasswordRepository } from '@app/common/modules/visitor-password/repositories';
|
||||||
import { DeviceService } from 'src/device/services';
|
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()
|
@Injectable()
|
||||||
export class DoorLockService {
|
export class DoorLockService {
|
||||||
@ -115,7 +124,7 @@ export class DoorLockService {
|
|||||||
);
|
);
|
||||||
const passwords = await this.getTemporaryOfflinePasswordsTuya(
|
const passwords = await this.getTemporaryOfflinePasswordsTuya(
|
||||||
deviceDetails.deviceTuyaUuid,
|
deviceDetails.deviceTuyaUuid,
|
||||||
'multiple',
|
PasswordType.MULTIPLE,
|
||||||
isExpired,
|
isExpired,
|
||||||
);
|
);
|
||||||
if (!passwords.result.records.length && fromVisitor) {
|
if (!passwords.result.records.length && fromVisitor) {
|
||||||
@ -502,7 +511,7 @@ export class DoorLockService {
|
|||||||
}
|
}
|
||||||
const createOnceOfflinePass = await this.addOfflineTemporaryPasswordTuya(
|
const createOnceOfflinePass = await this.addOfflineTemporaryPasswordTuya(
|
||||||
deviceDetails.deviceTuyaUuid,
|
deviceDetails.deviceTuyaUuid,
|
||||||
'multiple',
|
PasswordType.MULTIPLE,
|
||||||
addDoorLockOfflineTempMultipleTimeDto,
|
addDoorLockOfflineTempMultipleTimeDto,
|
||||||
);
|
);
|
||||||
if (!createOnceOfflinePass.success) {
|
if (!createOnceOfflinePass.success) {
|
||||||
@ -566,7 +575,7 @@ export class DoorLockService {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
path,
|
path,
|
||||||
body: {
|
body: {
|
||||||
...(type === 'multiple' && {
|
...(type === PasswordType.MULTIPLE && {
|
||||||
effective_time: addDoorLockOfflineTempMultipleTimeDto.effectiveTime,
|
effective_time: addDoorLockOfflineTempMultipleTimeDto.effectiveTime,
|
||||||
invalid_time: addDoorLockOfflineTempMultipleTimeDto.invalidTime,
|
invalid_time: addDoorLockOfflineTempMultipleTimeDto.invalidTime,
|
||||||
}),
|
}),
|
||||||
@ -711,7 +720,7 @@ export class DoorLockService {
|
|||||||
schedule_list: scheduleList,
|
schedule_list: scheduleList,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
type: '0',
|
type: EnableDisableStatusEnum.DISABLED,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -725,7 +734,15 @@ export class DoorLockService {
|
|||||||
}
|
}
|
||||||
getWorkingDayValue(days) {
|
getWorkingDayValue(days) {
|
||||||
// Array representing the days of the week
|
// 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
|
// Initialize a binary string with 7 bits
|
||||||
let binaryString = '0000000';
|
let binaryString = '0000000';
|
||||||
@ -734,10 +751,10 @@ export class DoorLockService {
|
|||||||
days.forEach((day) => {
|
days.forEach((day) => {
|
||||||
const index = weekDays.indexOf(day);
|
const index = weekDays.indexOf(day);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
// Set the corresponding bit to '1'
|
// Set the corresponding bit to EnableDisableStatusEnum.ENABLED
|
||||||
binaryString =
|
binaryString =
|
||||||
binaryString.substring(0, index) +
|
binaryString.substring(0, index) +
|
||||||
'1' +
|
EnableDisableStatusEnum.ENABLED +
|
||||||
binaryString.substring(index + 1);
|
binaryString.substring(index + 1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -749,17 +766,27 @@ export class DoorLockService {
|
|||||||
}
|
}
|
||||||
getDaysFromWorkingDayValue(workingDayValue) {
|
getDaysFromWorkingDayValue(workingDayValue) {
|
||||||
// Array representing the days of the week
|
// 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
|
// 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
|
// Initialize an array to hold the days of the week
|
||||||
const days = [];
|
const days = [];
|
||||||
|
|
||||||
// Iterate through the binary string and weekDays array
|
// Iterate through the binary string and weekDays array
|
||||||
for (let i = 0; i < binaryString.length; i++) {
|
for (let i = 0; i < binaryString.length; i++) {
|
||||||
if (binaryString[i] === '1') {
|
if (binaryString[i] === EnableDisableStatusEnum.ENABLED) {
|
||||||
days.push(weekDays[i]);
|
days.push(weekDays[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -769,8 +796,8 @@ export class DoorLockService {
|
|||||||
timeToMinutes(timeStr) {
|
timeToMinutes(timeStr) {
|
||||||
try {
|
try {
|
||||||
// Special case for "24:00"
|
// Special case for "24:00"
|
||||||
if (timeStr === '24:00') {
|
if (timeStr === CommonHours.TWENTY_FOUR) {
|
||||||
return 1440;
|
return CommonHourMinutes.TWENTY_FOUR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Regular expression to validate the 24-hour time format (HH:MM)
|
// Regular expression to validate the 24-hour time format (HH:MM)
|
||||||
@ -798,20 +825,26 @@ export class DoorLockService {
|
|||||||
if (
|
if (
|
||||||
typeof totalMinutes !== 'number' ||
|
typeof totalMinutes !== 'number' ||
|
||||||
totalMinutes < 0 ||
|
totalMinutes < 0 ||
|
||||||
totalMinutes > 1440
|
totalMinutes > CommonHourMinutes.TWENTY_FOUR
|
||||||
) {
|
) {
|
||||||
throw new Error('Invalid minutes value');
|
throw new Error('Invalid minutes value');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalMinutes === 1440) {
|
if (totalMinutes === CommonHourMinutes.TWENTY_FOUR) {
|
||||||
return '24:00';
|
return CommonHours.TWENTY_FOUR;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hours = Math.floor(totalMinutes / 60);
|
const hours = Math.floor(totalMinutes / 60);
|
||||||
const minutes = totalMinutes % 60;
|
const minutes = totalMinutes % 60;
|
||||||
|
|
||||||
const formattedHours = String(hours).padStart(2, '0');
|
const formattedHours = String(hours).padStart(
|
||||||
const formattedMinutes = String(minutes).padStart(2, '0');
|
2,
|
||||||
|
EnableDisableStatusEnum.DISABLED,
|
||||||
|
);
|
||||||
|
const formattedMinutes = String(minutes).padStart(
|
||||||
|
2,
|
||||||
|
EnableDisableStatusEnum.DISABLED,
|
||||||
|
);
|
||||||
|
|
||||||
return `${formattedHours}:${formattedMinutes}`;
|
return `${formattedHours}:${formattedMinutes}`;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -826,6 +859,7 @@ export class DoorLockService {
|
|||||||
return await this.deviceRepository.findOne({
|
return await this.deviceRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
uuid: deviceUuid,
|
uuid: deviceUuid,
|
||||||
|
isActive: true,
|
||||||
},
|
},
|
||||||
...(withProductDevice && { relations: ['productDevice'] }),
|
...(withProductDevice && { relations: ['productDevice'] }),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
import * as CryptoJS from 'crypto-js';
|
import * as CryptoJS from 'crypto-js';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PasswordEncryptionService {
|
export class PasswordEncryptionService {
|
||||||
@ -43,7 +44,9 @@ export class PasswordEncryptionService {
|
|||||||
'auth-config.SECRET_KEY',
|
'auth-config.SECRET_KEY',
|
||||||
);
|
);
|
||||||
// The accessSecret must be 32 bytes, ensure it is properly padded or truncated
|
// 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);
|
const plainTextTicketKey = this.decrypt(ticketKey, paddedAccessSecret);
|
||||||
|
|
||||||
return this.encrypt(plainTextPassword, plainTextTicketKey);
|
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,
|
Body,
|
||||||
Controller,
|
Controller,
|
||||||
Get,
|
Get,
|
||||||
HttpException,
|
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
Param,
|
Param,
|
||||||
Post,
|
Post,
|
||||||
@ -20,11 +19,13 @@ import { CheckUserFloorGuard } from 'src/guards/user.floor.guard';
|
|||||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||||
import { AdminRoleGuard } from 'src/guards/admin.role.guard';
|
import { AdminRoleGuard } from 'src/guards/admin.role.guard';
|
||||||
import { FloorPermissionGuard } from 'src/guards/floor.permission.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')
|
@ApiTags('Floor Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
version: '1',
|
version: EnableDisableStatusEnum.ENABLED,
|
||||||
path: 'floor',
|
path: SpaceType.FLOOR,
|
||||||
})
|
})
|
||||||
export class FloorController {
|
export class FloorController {
|
||||||
constructor(private readonly floorService: FloorService) {}
|
constructor(private readonly floorService: FloorService) {}
|
||||||
@ -33,35 +34,21 @@ export class FloorController {
|
|||||||
@UseGuards(JwtAuthGuard, CheckBuildingTypeGuard)
|
@UseGuards(JwtAuthGuard, CheckBuildingTypeGuard)
|
||||||
@Post()
|
@Post()
|
||||||
async addFloor(@Body() addFloorDto: AddFloorDto) {
|
async addFloor(@Body() addFloorDto: AddFloorDto) {
|
||||||
try {
|
const floor = await this.floorService.addFloor(addFloorDto);
|
||||||
const floor = await this.floorService.addFloor(addFloorDto);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.CREATED,
|
||||||
statusCode: HttpStatus.CREATED,
|
success: true,
|
||||||
success: true,
|
message: 'Floor added successfully',
|
||||||
message: 'Floor added successfully',
|
data: floor,
|
||||||
data: floor,
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard, FloorPermissionGuard)
|
@UseGuards(JwtAuthGuard, FloorPermissionGuard)
|
||||||
@Get(':floorUuid')
|
@Get(':floorUuid')
|
||||||
async getFloorByUuid(@Param('floorUuid') floorUuid: string) {
|
async getFloorByUuid(@Param('floorUuid') floorUuid: string) {
|
||||||
try {
|
const floor = await this.floorService.getFloorByUuid(floorUuid);
|
||||||
const floor = await this.floorService.getFloorByUuid(floorUuid);
|
return floor;
|
||||||
return floor;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@ -71,85 +58,47 @@ export class FloorController {
|
|||||||
@Param('floorUuid') floorUuid: string,
|
@Param('floorUuid') floorUuid: string,
|
||||||
@Query() query: GetFloorChildDto,
|
@Query() query: GetFloorChildDto,
|
||||||
) {
|
) {
|
||||||
try {
|
const floor = await this.floorService.getFloorChildByUuid(floorUuid, query);
|
||||||
const floor = await this.floorService.getFloorChildByUuid(
|
return floor;
|
||||||
floorUuid,
|
|
||||||
query,
|
|
||||||
);
|
|
||||||
return floor;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard, FloorPermissionGuard)
|
@UseGuards(JwtAuthGuard, FloorPermissionGuard)
|
||||||
@Get('parent/:floorUuid')
|
@Get('parent/:floorUuid')
|
||||||
async getFloorParentByUuid(@Param('floorUuid') floorUuid: string) {
|
async getFloorParentByUuid(@Param('floorUuid') floorUuid: string) {
|
||||||
try {
|
const floor = await this.floorService.getFloorParentByUuid(floorUuid);
|
||||||
const floor = await this.floorService.getFloorParentByUuid(floorUuid);
|
return floor;
|
||||||
return floor;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(AdminRoleGuard, CheckUserFloorGuard)
|
@UseGuards(AdminRoleGuard, CheckUserFloorGuard)
|
||||||
@Post('user')
|
@Post('user')
|
||||||
async addUserFloor(@Body() addUserFloorDto: AddUserFloorDto) {
|
async addUserFloor(@Body() addUserFloorDto: AddUserFloorDto) {
|
||||||
try {
|
await this.floorService.addUserFloor(addUserFloorDto);
|
||||||
await this.floorService.addUserFloor(addUserFloorDto);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.CREATED,
|
||||||
statusCode: HttpStatus.CREATED,
|
success: true,
|
||||||
success: true,
|
message: 'user floor added successfully',
|
||||||
message: 'user floor added successfully',
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Get('user/:userUuid')
|
@Get('user/:userUuid')
|
||||||
async getFloorsByUserId(@Param('userUuid') userUuid: string) {
|
async getFloorsByUserId(@Param('userUuid') userUuid: string) {
|
||||||
try {
|
return await this.floorService.getFloorsByUserId(userUuid);
|
||||||
return await this.floorService.getFloorsByUserId(userUuid);
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard, FloorPermissionGuard)
|
@UseGuards(JwtAuthGuard, FloorPermissionGuard)
|
||||||
@Put('rename/:floorUuid')
|
@Put(':floorUuid')
|
||||||
async renameFloorByUuid(
|
async renameFloorByUuid(
|
||||||
@Param('floorUuid') floorUuid: string,
|
@Param('floorUuid') floorUuid: string,
|
||||||
@Body() updateFloorNameDto: UpdateFloorNameDto,
|
@Body() updateFloorNameDto: UpdateFloorNameDto,
|
||||||
) {
|
) {
|
||||||
try {
|
const floor = await this.floorService.renameFloorByUuid(
|
||||||
const floor = await this.floorService.renameFloorByUuid(
|
floorUuid,
|
||||||
floorUuid,
|
updateFloorNameDto,
|
||||||
updateFloorNameDto,
|
);
|
||||||
);
|
return floor;
|
||||||
return floor;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { BooleanValues } from '@app/common/constants/boolean-values.enum';
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { Transform } from 'class-transformer';
|
import { Transform } from 'class-transformer';
|
||||||
import {
|
import {
|
||||||
@ -45,7 +46,7 @@ export class GetFloorChildDto {
|
|||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
@Transform((value) => {
|
@Transform((value) => {
|
||||||
return value.obj.includeSubSpaces === 'true';
|
return value.obj.includeSubSpaces === BooleanValues.TRUE;
|
||||||
})
|
})
|
||||||
public includeSubSpaces: boolean = false;
|
public includeSubSpaces: boolean = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,8 @@ import {
|
|||||||
import { SpaceEntity } from '@app/common/modules/space/entities';
|
import { SpaceEntity } from '@app/common/modules/space/entities';
|
||||||
import { UpdateFloorNameDto } from '../dtos/update.floor.dto';
|
import { UpdateFloorNameDto } from '../dtos/update.floor.dto';
|
||||||
import { UserSpaceRepository } from '@app/common/modules/user/repositories';
|
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()
|
@Injectable()
|
||||||
export class FloorService {
|
export class FloorService {
|
||||||
@ -31,7 +33,7 @@ export class FloorService {
|
|||||||
try {
|
try {
|
||||||
const spaceType = await this.spaceTypeRepository.findOne({
|
const spaceType = await this.spaceTypeRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
type: 'floor',
|
type: SpaceType.FLOOR,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -52,12 +54,16 @@ export class FloorService {
|
|||||||
where: {
|
where: {
|
||||||
uuid: floorUuid,
|
uuid: floorUuid,
|
||||||
spaceType: {
|
spaceType: {
|
||||||
type: 'floor',
|
type: SpaceType.FLOOR,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
relations: ['spaceType'],
|
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');
|
throw new BadRequestException('Invalid floor UUID');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +94,11 @@ export class FloorService {
|
|||||||
relations: ['children', 'spaceType'],
|
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');
|
throw new BadRequestException('Invalid floor UUID');
|
||||||
}
|
}
|
||||||
const totalCount = await this.spaceRepository.count({
|
const totalCount = await this.spaceRepository.count({
|
||||||
@ -135,9 +145,9 @@ export class FloorService {
|
|||||||
return children
|
return children
|
||||||
.filter(
|
.filter(
|
||||||
(child) =>
|
(child) =>
|
||||||
child.spaceType.type !== 'floor' &&
|
child.spaceType.type !== SpaceType.FLOOR &&
|
||||||
child.spaceType.type !== 'building' &&
|
child.spaceType.type !== SpaceType.BUILDING &&
|
||||||
child.spaceType.type !== 'community',
|
child.spaceType.type !== SpaceType.COMMUNITY,
|
||||||
) // Filter remaining floor and building and community types
|
) // Filter remaining floor and building and community types
|
||||||
.map((child) => ({
|
.map((child) => ({
|
||||||
uuid: child.uuid,
|
uuid: child.uuid,
|
||||||
@ -150,9 +160,9 @@ export class FloorService {
|
|||||||
children
|
children
|
||||||
.filter(
|
.filter(
|
||||||
(child) =>
|
(child) =>
|
||||||
child.spaceType.type !== 'floor' &&
|
child.spaceType.type !== SpaceType.FLOOR &&
|
||||||
child.spaceType.type !== 'building' &&
|
child.spaceType.type !== SpaceType.BUILDING &&
|
||||||
child.spaceType.type !== 'community',
|
child.spaceType.type !== SpaceType.COMMUNITY,
|
||||||
) // Filter remaining floor and building and community types
|
) // Filter remaining floor and building and community types
|
||||||
.map(async (child) => ({
|
.map(async (child) => ({
|
||||||
uuid: child.uuid,
|
uuid: child.uuid,
|
||||||
@ -171,12 +181,16 @@ export class FloorService {
|
|||||||
where: {
|
where: {
|
||||||
uuid: floorUuid,
|
uuid: floorUuid,
|
||||||
spaceType: {
|
spaceType: {
|
||||||
type: 'floor',
|
type: SpaceType.FLOOR,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
relations: ['spaceType', 'parent', 'parent.spaceType'],
|
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');
|
throw new BadRequestException('Invalid floor UUID');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +221,7 @@ export class FloorService {
|
|||||||
relations: ['space', 'space.spaceType'],
|
relations: ['space', 'space.spaceType'],
|
||||||
where: {
|
where: {
|
||||||
user: { uuid: userUuid },
|
user: { uuid: userUuid },
|
||||||
space: { spaceType: { type: 'floor' } },
|
space: { spaceType: { type: SpaceType.FLOOR } },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -239,7 +253,7 @@ export class FloorService {
|
|||||||
space: { uuid: addUserFloorDto.floorUuid },
|
space: { uuid: addUserFloorDto.floorUuid },
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.code === '23505') {
|
if (err.code === CommonErrorCodes.DUPLICATE_ENTITY) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
'User already belongs to this floor',
|
'User already belongs to this floor',
|
||||||
HttpStatus.BAD_REQUEST,
|
HttpStatus.BAD_REQUEST,
|
||||||
@ -261,7 +275,11 @@ export class FloorService {
|
|||||||
relations: ['spaceType'],
|
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');
|
throw new BadRequestException('Invalid floor UUID');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,20 +1,13 @@
|
|||||||
import { GroupService } from '../services/group.service';
|
import { GroupService } from '../services/group.service';
|
||||||
import {
|
import { Controller, Get, UseGuards, Param, Req } from '@nestjs/common';
|
||||||
Controller,
|
|
||||||
Get,
|
|
||||||
UseGuards,
|
|
||||||
Param,
|
|
||||||
HttpException,
|
|
||||||
HttpStatus,
|
|
||||||
Req,
|
|
||||||
} from '@nestjs/common';
|
|
||||||
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
|
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
|
||||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||||
import { UnitPermissionGuard } from 'src/guards/unit.permission.guard';
|
import { UnitPermissionGuard } from 'src/guards/unit.permission.guard';
|
||||||
|
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||||
|
|
||||||
@ApiTags('Group Module')
|
@ApiTags('Group Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
version: '1',
|
version: EnableDisableStatusEnum.ENABLED,
|
||||||
path: 'group',
|
path: 'group',
|
||||||
})
|
})
|
||||||
export class GroupController {
|
export class GroupController {
|
||||||
@ -24,14 +17,7 @@ export class GroupController {
|
|||||||
@UseGuards(JwtAuthGuard, UnitPermissionGuard)
|
@UseGuards(JwtAuthGuard, UnitPermissionGuard)
|
||||||
@Get(':unitUuid')
|
@Get(':unitUuid')
|
||||||
async getGroupsBySpaceUuid(@Param('unitUuid') unitUuid: string) {
|
async getGroupsBySpaceUuid(@Param('unitUuid') unitUuid: string) {
|
||||||
try {
|
return await this.groupService.getGroupsByUnitUuid(unitUuid);
|
||||||
return await this.groupService.getGroupsByUnitUuid(unitUuid);
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard, UnitPermissionGuard)
|
@UseGuards(JwtAuthGuard, UnitPermissionGuard)
|
||||||
@ -41,19 +27,12 @@ export class GroupController {
|
|||||||
@Param('groupName') groupName: string,
|
@Param('groupName') groupName: string,
|
||||||
@Req() req: any,
|
@Req() req: any,
|
||||||
) {
|
) {
|
||||||
try {
|
const userUuid = req.user.uuid;
|
||||||
const userUuid = req.user.uuid;
|
|
||||||
|
|
||||||
return await this.groupService.getUnitDevicesByGroupName(
|
return await this.groupService.getUnitDevicesByGroupName(
|
||||||
unitUuid,
|
unitUuid,
|
||||||
groupName,
|
groupName,
|
||||||
userUuid,
|
userUuid,
|
||||||
);
|
);
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter';
|
|||||||
import { ProductRepository } from '@app/common/modules/product/repositories';
|
import { ProductRepository } from '@app/common/modules/product/repositories';
|
||||||
import { PermissionType } from '@app/common/constants/permission-type.enum';
|
import { PermissionType } from '@app/common/constants/permission-type.enum';
|
||||||
import { In } from 'typeorm';
|
import { In } from 'typeorm';
|
||||||
|
import { ProductType } from '@app/common/constants/product-type.enum';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GroupService {
|
export class GroupService {
|
||||||
@ -44,8 +45,24 @@ export class GroupService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const uniqueGroupNames = [...new Set(groupNames)];
|
const uniqueGroupNames = [...new Set(groupNames)];
|
||||||
|
const groups = uniqueGroupNames.map((groupName) => ({
|
||||||
return uniqueGroupNames.map((groupName) => ({ 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) {
|
} catch (error) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
'This unit does not have any groups',
|
'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 { SpacePermissionService } from '@app/common/helper/services/space.permission.service';
|
||||||
import {
|
import {
|
||||||
BadRequestException,
|
BadRequestException,
|
||||||
@ -24,7 +25,7 @@ export class BuildingPermissionGuard implements CanActivate {
|
|||||||
await this.permissionService.checkUserPermission(
|
await this.permissionService.checkUserPermission(
|
||||||
buildingUuid,
|
buildingUuid,
|
||||||
user.uuid,
|
user.uuid,
|
||||||
'building',
|
SpaceType.BUILDING,
|
||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||||
import {
|
import {
|
||||||
Injectable,
|
Injectable,
|
||||||
@ -42,7 +43,7 @@ export class CheckBuildingTypeGuard implements CanActivate {
|
|||||||
if (
|
if (
|
||||||
!buildingData ||
|
!buildingData ||
|
||||||
!buildingData.spaceType ||
|
!buildingData.spaceType ||
|
||||||
buildingData.spaceType.type !== 'building'
|
buildingData.spaceType.type !== SpaceType.BUILDING
|
||||||
) {
|
) {
|
||||||
throw new BadRequestException('Invalid building UUID');
|
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 { SpacePermissionService } from '@app/common/helper/services/space.permission.service';
|
||||||
import {
|
import {
|
||||||
BadRequestException,
|
BadRequestException,
|
||||||
@ -24,7 +25,7 @@ export class CommunityPermissionGuard implements CanActivate {
|
|||||||
await this.permissionService.checkUserPermission(
|
await this.permissionService.checkUserPermission(
|
||||||
communityUuid,
|
communityUuid,
|
||||||
user.uuid,
|
user.uuid,
|
||||||
'community',
|
SpaceType.COMMUNITY,
|
||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import {
|
|||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||||
import { BadRequestException } from '@nestjs/common';
|
import { BadRequestException } from '@nestjs/common';
|
||||||
|
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CheckCommunityTypeGuard implements CanActivate {
|
export class CheckCommunityTypeGuard implements CanActivate {
|
||||||
@ -43,7 +44,7 @@ export class CheckCommunityTypeGuard implements CanActivate {
|
|||||||
if (
|
if (
|
||||||
!communityData ||
|
!communityData ||
|
||||||
!communityData.spaceType ||
|
!communityData.spaceType ||
|
||||||
communityData.spaceType.type !== 'community'
|
communityData.spaceType.type !== SpaceType.COMMUNITY
|
||||||
) {
|
) {
|
||||||
throw new BadRequestException('Invalid community UUID');
|
throw new BadRequestException('Invalid community UUID');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,7 @@ export class CheckProductUuidForAllDevicesGuard implements CanActivate {
|
|||||||
|
|
||||||
async checkAllDevicesHaveSameProductUuid(deviceUuids: string[]) {
|
async checkAllDevicesHaveSameProductUuid(deviceUuids: string[]) {
|
||||||
const firstDevice = await this.deviceRepository.findOne({
|
const firstDevice = await this.deviceRepository.findOne({
|
||||||
where: { uuid: deviceUuids[0] },
|
where: { uuid: deviceUuids[0], isActive: true },
|
||||||
relations: ['productDevice'],
|
relations: ['productDevice'],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ export class CheckProductUuidForAllDevicesGuard implements CanActivate {
|
|||||||
|
|
||||||
for (let i = 1; i < deviceUuids.length; i++) {
|
for (let i = 1; i < deviceUuids.length; i++) {
|
||||||
const device = await this.deviceRepository.findOne({
|
const device = await this.deviceRepository.findOne({
|
||||||
where: { uuid: deviceUuids[i] },
|
where: { uuid: deviceUuids[i], isActive: true },
|
||||||
relations: ['productDevice'],
|
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 { SpacePermissionService } from '@app/common/helper/services/space.permission.service';
|
||||||
import {
|
import {
|
||||||
BadRequestException,
|
BadRequestException,
|
||||||
@ -24,7 +25,7 @@ export class FloorPermissionGuard implements CanActivate {
|
|||||||
await this.permissionService.checkUserPermission(
|
await this.permissionService.checkUserPermission(
|
||||||
floorUuid,
|
floorUuid,
|
||||||
user.uuid,
|
user.uuid,
|
||||||
'floor',
|
SpaceType.FLOOR,
|
||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||||
import {
|
import {
|
||||||
Injectable,
|
Injectable,
|
||||||
@ -42,7 +43,7 @@ export class CheckFloorTypeGuard implements CanActivate {
|
|||||||
if (
|
if (
|
||||||
!floorData ||
|
!floorData ||
|
||||||
!floorData.spaceType ||
|
!floorData.spaceType ||
|
||||||
floorData.spaceType.type !== 'floor'
|
floorData.spaceType.type !== SpaceType.FLOOR
|
||||||
) {
|
) {
|
||||||
throw new BadRequestException('Invalid floor UUID');
|
throw new BadRequestException('Invalid floor UUID');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import {
|
|||||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||||
|
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CheckRoomGuard implements CanActivate {
|
export class CheckRoomGuard implements CanActivate {
|
||||||
@ -43,7 +44,7 @@ export class CheckRoomGuard implements CanActivate {
|
|||||||
where: {
|
where: {
|
||||||
uuid: roomUuid,
|
uuid: roomUuid,
|
||||||
spaceType: {
|
spaceType: {
|
||||||
type: 'room',
|
type: SpaceType.ROOM,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -55,6 +56,7 @@ export class CheckRoomGuard implements CanActivate {
|
|||||||
const response = await this.deviceRepository.findOne({
|
const response = await this.deviceRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
uuid: deviceUuid,
|
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 { SpacePermissionService } from '@app/common/helper/services/space.permission.service';
|
||||||
import {
|
import {
|
||||||
BadRequestException,
|
BadRequestException,
|
||||||
@ -24,7 +25,7 @@ export class RoomPermissionGuard implements CanActivate {
|
|||||||
await this.permissionService.checkUserPermission(
|
await this.permissionService.checkUserPermission(
|
||||||
roomUuid,
|
roomUuid,
|
||||||
user.uuid,
|
user.uuid,
|
||||||
'room',
|
SpaceType.ROOM,
|
||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
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 { SpacePermissionService } from '@app/common/helper/services/space.permission.service';
|
||||||
import {
|
import {
|
||||||
BadRequestException,
|
BadRequestException,
|
||||||
@ -24,7 +25,7 @@ export class UnitPermissionGuard implements CanActivate {
|
|||||||
await this.permissionService.checkUserPermission(
|
await this.permissionService.checkUserPermission(
|
||||||
unitUuid,
|
unitUuid,
|
||||||
user.uuid,
|
user.uuid,
|
||||||
'unit',
|
SpaceType.UNIT,
|
||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||||
import {
|
import {
|
||||||
Injectable,
|
Injectable,
|
||||||
@ -42,7 +43,7 @@ export class CheckUnitTypeGuard implements CanActivate {
|
|||||||
if (
|
if (
|
||||||
!unitData ||
|
!unitData ||
|
||||||
!unitData.spaceType ||
|
!unitData.spaceType ||
|
||||||
unitData.spaceType.type !== 'unit'
|
unitData.spaceType.type !== SpaceType.UNIT
|
||||||
) {
|
) {
|
||||||
throw new BadRequestException('Invalid unit UUID');
|
throw new BadRequestException('Invalid unit UUID');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||||
import { UserRepository } from '@app/common/modules/user/repositories';
|
import { UserRepository } from '@app/common/modules/user/repositories';
|
||||||
|
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CheckUserBuildingGuard implements CanActivate {
|
export class CheckUserBuildingGuard implements CanActivate {
|
||||||
@ -43,7 +44,7 @@ export class CheckUserBuildingGuard implements CanActivate {
|
|||||||
|
|
||||||
private async checkBuildingIsFound(spaceUuid: string) {
|
private async checkBuildingIsFound(spaceUuid: string) {
|
||||||
const spaceData = await this.spaceRepository.findOne({
|
const spaceData = await this.spaceRepository.findOne({
|
||||||
where: { uuid: spaceUuid, spaceType: { type: 'building' } },
|
where: { uuid: spaceUuid, spaceType: { type: SpaceType.BUILDING } },
|
||||||
relations: ['spaceType'],
|
relations: ['spaceType'],
|
||||||
});
|
});
|
||||||
if (!spaceData) {
|
if (!spaceData) {
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||||
import { UserRepository } from '@app/common/modules/user/repositories';
|
import { UserRepository } from '@app/common/modules/user/repositories';
|
||||||
|
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CheckUserCommunityGuard implements CanActivate {
|
export class CheckUserCommunityGuard implements CanActivate {
|
||||||
@ -43,7 +44,7 @@ export class CheckUserCommunityGuard implements CanActivate {
|
|||||||
|
|
||||||
private async checkCommunityIsFound(spaceUuid: string) {
|
private async checkCommunityIsFound(spaceUuid: string) {
|
||||||
const spaceData = await this.spaceRepository.findOne({
|
const spaceData = await this.spaceRepository.findOne({
|
||||||
where: { uuid: spaceUuid, spaceType: { type: 'community' } },
|
where: { uuid: spaceUuid, spaceType: { type: SpaceType.COMMUNITY } },
|
||||||
relations: ['spaceType'],
|
relations: ['spaceType'],
|
||||||
});
|
});
|
||||||
if (!spaceData) {
|
if (!spaceData) {
|
||||||
|
|||||||
@ -58,7 +58,11 @@ export class CheckUserHaveControllablePermission implements CanActivate {
|
|||||||
deviceUuid: string,
|
deviceUuid: string,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const device = await this.deviceRepository.findOne({
|
const device = await this.deviceRepository.findOne({
|
||||||
where: { uuid: deviceUuid, permission: { userUuid: userUuid } },
|
where: {
|
||||||
|
uuid: deviceUuid,
|
||||||
|
isActive: true,
|
||||||
|
permission: { userUuid: userUuid },
|
||||||
|
},
|
||||||
relations: ['permission', 'permission.permissionType'],
|
relations: ['permission', 'permission.permissionType'],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -59,7 +59,11 @@ export class CheckUserHavePermission implements CanActivate {
|
|||||||
deviceUuid: string,
|
deviceUuid: string,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const device = await this.deviceRepository.findOne({
|
const device = await this.deviceRepository.findOne({
|
||||||
where: { uuid: deviceUuid, permission: { userUuid: userUuid } },
|
where: {
|
||||||
|
uuid: deviceUuid,
|
||||||
|
permission: { userUuid: userUuid },
|
||||||
|
isActive: true,
|
||||||
|
},
|
||||||
relations: ['permission', 'permission.permissionType'],
|
relations: ['permission', 'permission.permissionType'],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||||
import { UserRepository } from '@app/common/modules/user/repositories';
|
import { UserRepository } from '@app/common/modules/user/repositories';
|
||||||
|
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CheckUserFloorGuard implements CanActivate {
|
export class CheckUserFloorGuard implements CanActivate {
|
||||||
@ -43,7 +44,7 @@ export class CheckUserFloorGuard implements CanActivate {
|
|||||||
|
|
||||||
private async checkFloorIsFound(spaceUuid: string) {
|
private async checkFloorIsFound(spaceUuid: string) {
|
||||||
const spaceData = await this.spaceRepository.findOne({
|
const spaceData = await this.spaceRepository.findOne({
|
||||||
where: { uuid: spaceUuid, spaceType: { type: 'floor' } },
|
where: { uuid: spaceUuid, spaceType: { type: SpaceType.FLOOR } },
|
||||||
relations: ['spaceType'],
|
relations: ['spaceType'],
|
||||||
});
|
});
|
||||||
if (!spaceData) {
|
if (!spaceData) {
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||||
import { UserRepository } from '@app/common/modules/user/repositories';
|
import { UserRepository } from '@app/common/modules/user/repositories';
|
||||||
|
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CheckUserRoomGuard implements CanActivate {
|
export class CheckUserRoomGuard implements CanActivate {
|
||||||
@ -43,7 +44,7 @@ export class CheckUserRoomGuard implements CanActivate {
|
|||||||
|
|
||||||
private async checkRoomIsFound(spaceUuid: string) {
|
private async checkRoomIsFound(spaceUuid: string) {
|
||||||
const spaceData = await this.spaceRepository.findOne({
|
const spaceData = await this.spaceRepository.findOne({
|
||||||
where: { uuid: spaceUuid, spaceType: { type: 'room' } },
|
where: { uuid: spaceUuid, spaceType: { type: SpaceType.ROOM } },
|
||||||
relations: ['spaceType'],
|
relations: ['spaceType'],
|
||||||
});
|
});
|
||||||
if (!spaceData) {
|
if (!spaceData) {
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||||
import { UserRepository } from '@app/common/modules/user/repositories';
|
import { UserRepository } from '@app/common/modules/user/repositories';
|
||||||
|
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CheckUserUnitGuard implements CanActivate {
|
export class CheckUserUnitGuard implements CanActivate {
|
||||||
@ -43,7 +44,7 @@ export class CheckUserUnitGuard implements CanActivate {
|
|||||||
|
|
||||||
private async checkUnitIsFound(spaceUuid: string) {
|
private async checkUnitIsFound(spaceUuid: string) {
|
||||||
const spaceData = await this.spaceRepository.findOne({
|
const spaceData = await this.spaceRepository.findOne({
|
||||||
where: { uuid: spaceUuid, spaceType: { type: 'unit' } },
|
where: { uuid: spaceUuid, spaceType: { type: SpaceType.UNIT } },
|
||||||
relations: ['spaceType'],
|
relations: ['spaceType'],
|
||||||
});
|
});
|
||||||
if (!spaceData) {
|
if (!spaceData) {
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { setupSwaggerAuthentication } from '../libs/common/src/util/user-auth.sw
|
|||||||
import { ValidationPipe } from '@nestjs/common';
|
import { ValidationPipe } from '@nestjs/common';
|
||||||
import { json, urlencoded } from 'body-parser';
|
import { json, urlencoded } from 'body-parser';
|
||||||
import { SeederService } from '@app/common/seed/services/seeder.service';
|
import { SeederService } from '@app/common/seed/services/seeder.service';
|
||||||
|
import { HttpExceptionFilter } from './common/filters/http-exception/http-exception.filter';
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const app = await NestFactory.create(AppModule);
|
const app = await NestFactory.create(AppModule);
|
||||||
@ -15,6 +16,7 @@ async function bootstrap() {
|
|||||||
// Set the body parser limit to 1 MB
|
// Set the body parser limit to 1 MB
|
||||||
app.use(json({ limit: '1mb' }));
|
app.use(json({ limit: '1mb' }));
|
||||||
app.use(urlencoded({ limit: '1mb', extended: true }));
|
app.use(urlencoded({ limit: '1mb', extended: true }));
|
||||||
|
app.useGlobalFilters(new HttpExceptionFilter());
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
rateLimit({
|
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 { 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')
|
@ApiTags('Region Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
version: '1',
|
version: EnableDisableStatusEnum.ENABLED,
|
||||||
path: 'region',
|
path: ControllerRoute.REGION.ROUTE,
|
||||||
})
|
})
|
||||||
export class RegionController {
|
export class RegionController {
|
||||||
constructor(private readonly regionService: RegionService) {}
|
constructor(private readonly regionService: RegionService) {}
|
||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
|
@ApiOperation({
|
||||||
|
summary: ControllerRoute.REGION.ACTIONS.GET_REGIONS_SUMMARY,
|
||||||
|
description: ControllerRoute.REGION.ACTIONS.GET_REGIONS_DESCRIPTION,
|
||||||
|
})
|
||||||
async getAllRegions() {
|
async getAllRegions() {
|
||||||
try {
|
return await this.regionService.getAllRegions();
|
||||||
return await this.regionService.getAllRegions();
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,9 +3,10 @@ import { RegionService } from './services/region.service';
|
|||||||
import { RegionController } from './controllers/region.controller';
|
import { RegionController } from './controllers/region.controller';
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import { RegionRepository } from '@app/common/modules/region/repositories';
|
import { RegionRepository } from '@app/common/modules/region/repositories';
|
||||||
|
import { CommonModule } from '@app/common';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ConfigModule],
|
imports: [ConfigModule, CommonModule],
|
||||||
controllers: [RegionController],
|
controllers: [RegionController],
|
||||||
providers: [RegionService, RegionRepository],
|
providers: [RegionService, RegionRepository],
|
||||||
exports: [RegionService],
|
exports: [RegionService],
|
||||||
|
|||||||
@ -2,23 +2,33 @@ import {
|
|||||||
BadRequestException,
|
BadRequestException,
|
||||||
HttpException,
|
HttpException,
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
|
Inject,
|
||||||
Injectable,
|
Injectable,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { RegionRepository } from '@app/common/modules/region/repositories';
|
import { RegionRepository } from '@app/common/modules/region/repositories';
|
||||||
|
import { ErrorMessageService } from 'src/error-message/error-message.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RegionService {
|
export class RegionService {
|
||||||
constructor(private readonly regionRepository: RegionRepository) {}
|
constructor(
|
||||||
|
private readonly regionRepository: RegionRepository,
|
||||||
|
@Inject(ErrorMessageService)
|
||||||
|
private readonly errorMessageService: ErrorMessageService,
|
||||||
|
) {}
|
||||||
async getAllRegions() {
|
async getAllRegions() {
|
||||||
try {
|
try {
|
||||||
const regions = await this.regionRepository.find();
|
const regions = await this.regionRepository.find();
|
||||||
|
|
||||||
return regions;
|
return regions;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof BadRequestException) {
|
if (err instanceof BadRequestException) {
|
||||||
throw err; // Re-throw BadRequestException
|
throw err; // Re-throw BadRequestException
|
||||||
} else {
|
} 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,
|
Body,
|
||||||
Controller,
|
Controller,
|
||||||
Get,
|
Get,
|
||||||
HttpException,
|
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
Post,
|
Post,
|
||||||
UseGuards,
|
UseGuards,
|
||||||
@ -11,10 +10,11 @@ import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
|||||||
import { RoleService } from '../services/role.service';
|
import { RoleService } from '../services/role.service';
|
||||||
import { AddUserRoleDto } from '../dtos';
|
import { AddUserRoleDto } from '../dtos';
|
||||||
import { SuperAdminRoleGuard } from 'src/guards/super.admin.role.guard';
|
import { SuperAdminRoleGuard } from 'src/guards/super.admin.role.guard';
|
||||||
|
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||||
|
|
||||||
@ApiTags('Role Module')
|
@ApiTags('Role Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
version: '1',
|
version: EnableDisableStatusEnum.ENABLED,
|
||||||
path: 'role',
|
path: 'role',
|
||||||
})
|
})
|
||||||
export class RoleController {
|
export class RoleController {
|
||||||
@ -23,32 +23,21 @@ export class RoleController {
|
|||||||
@UseGuards(SuperAdminRoleGuard)
|
@UseGuards(SuperAdminRoleGuard)
|
||||||
@Get('types')
|
@Get('types')
|
||||||
async fetchRoleTypes() {
|
async fetchRoleTypes() {
|
||||||
try {
|
const roleTypes = await this.roleService.fetchRoleTypes();
|
||||||
const roleTypes = await this.roleService.fetchRoleTypes();
|
return {
|
||||||
return {
|
statusCode: HttpStatus.OK,
|
||||||
statusCode: HttpStatus.OK,
|
message: 'Role Types fetched Successfully',
|
||||||
message: 'Role Types fetched Successfully',
|
data: roleTypes,
|
||||||
data: roleTypes,
|
};
|
||||||
};
|
|
||||||
} catch (err) {
|
|
||||||
throw new Error(err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(SuperAdminRoleGuard)
|
@UseGuards(SuperAdminRoleGuard)
|
||||||
@Post()
|
@Post()
|
||||||
async addUserRoleType(@Body() addUserRoleDto: AddUserRoleDto) {
|
async addUserRoleType(@Body() addUserRoleDto: AddUserRoleDto) {
|
||||||
try {
|
await this.roleService.addUserRoleType(addUserRoleDto);
|
||||||
await this.roleService.addUserRoleType(addUserRoleDto);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.OK,
|
||||||
statusCode: HttpStatus.OK,
|
message: 'User Role Added Successfully',
|
||||||
message: 'User Role Added Successfully',
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
|||||||
import { AddUserRoleDto } from '../dtos/role.add.dto';
|
import { AddUserRoleDto } from '../dtos/role.add.dto';
|
||||||
import { UserRoleRepository } from '@app/common/modules/user/repositories';
|
import { UserRoleRepository } from '@app/common/modules/user/repositories';
|
||||||
import { QueryFailedError } from 'typeorm';
|
import { QueryFailedError } from 'typeorm';
|
||||||
|
import { CommonErrorCodes } from '@app/common/constants/error-codes.enum';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RoleService {
|
export class RoleService {
|
||||||
@ -24,7 +25,7 @@ export class RoleService {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (
|
if (
|
||||||
error instanceof QueryFailedError &&
|
error instanceof QueryFailedError &&
|
||||||
error.driverError.code === '23505'
|
error.driverError.code === CommonErrorCodes.DUPLICATE_ENTITY
|
||||||
) {
|
) {
|
||||||
// Postgres unique constraint violation error code
|
// Postgres unique constraint violation error code
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import {
|
|||||||
Body,
|
Body,
|
||||||
Controller,
|
Controller,
|
||||||
Get,
|
Get,
|
||||||
HttpException,
|
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
Param,
|
Param,
|
||||||
Post,
|
Post,
|
||||||
@ -18,11 +17,13 @@ import { CheckUserRoomGuard } from 'src/guards/user.room.guard';
|
|||||||
import { AdminRoleGuard } from 'src/guards/admin.role.guard';
|
import { AdminRoleGuard } from 'src/guards/admin.role.guard';
|
||||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||||
import { RoomPermissionGuard } from 'src/guards/room.permission.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')
|
@ApiTags('Room Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
version: '1',
|
version: EnableDisableStatusEnum.ENABLED,
|
||||||
path: 'room',
|
path: SpaceType.ROOM,
|
||||||
})
|
})
|
||||||
export class RoomController {
|
export class RoomController {
|
||||||
constructor(private readonly roomService: RoomService) {}
|
constructor(private readonly roomService: RoomService) {}
|
||||||
@ -31,101 +32,59 @@ export class RoomController {
|
|||||||
@UseGuards(JwtAuthGuard, CheckUnitTypeGuard)
|
@UseGuards(JwtAuthGuard, CheckUnitTypeGuard)
|
||||||
@Post()
|
@Post()
|
||||||
async addRoom(@Body() addRoomDto: AddRoomDto) {
|
async addRoom(@Body() addRoomDto: AddRoomDto) {
|
||||||
try {
|
const room = await this.roomService.addRoom(addRoomDto);
|
||||||
const room = await this.roomService.addRoom(addRoomDto);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.CREATED,
|
||||||
statusCode: HttpStatus.CREATED,
|
success: true,
|
||||||
success: true,
|
message: 'Room added successfully',
|
||||||
message: 'Room added successfully',
|
data: room,
|
||||||
data: room,
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard, RoomPermissionGuard)
|
@UseGuards(JwtAuthGuard, RoomPermissionGuard)
|
||||||
@Get(':roomUuid')
|
@Get(':roomUuid')
|
||||||
async getRoomByUuid(@Param('roomUuid') roomUuid: string) {
|
async getRoomByUuid(@Param('roomUuid') roomUuid: string) {
|
||||||
try {
|
const room = await this.roomService.getRoomByUuid(roomUuid);
|
||||||
const room = await this.roomService.getRoomByUuid(roomUuid);
|
return room;
|
||||||
return room;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard, RoomPermissionGuard)
|
@UseGuards(JwtAuthGuard, RoomPermissionGuard)
|
||||||
@Get('parent/:roomUuid')
|
@Get('parent/:roomUuid')
|
||||||
async getRoomParentByUuid(@Param('roomUuid') roomUuid: string) {
|
async getRoomParentByUuid(@Param('roomUuid') roomUuid: string) {
|
||||||
try {
|
const room = await this.roomService.getRoomParentByUuid(roomUuid);
|
||||||
const room = await this.roomService.getRoomParentByUuid(roomUuid);
|
return room;
|
||||||
return room;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(AdminRoleGuard, CheckUserRoomGuard)
|
@UseGuards(AdminRoleGuard, CheckUserRoomGuard)
|
||||||
@Post('user')
|
@Post('user')
|
||||||
async addUserRoom(@Body() addUserRoomDto: AddUserRoomDto) {
|
async addUserRoom(@Body() addUserRoomDto: AddUserRoomDto) {
|
||||||
try {
|
await this.roomService.addUserRoom(addUserRoomDto);
|
||||||
await this.roomService.addUserRoom(addUserRoomDto);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.CREATED,
|
||||||
statusCode: HttpStatus.CREATED,
|
success: true,
|
||||||
success: true,
|
message: 'user room added successfully',
|
||||||
message: 'user room added successfully',
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Get('user/:userUuid')
|
@Get('user/:userUuid')
|
||||||
async getRoomsByUserId(@Param('userUuid') userUuid: string) {
|
async getRoomsByUserId(@Param('userUuid') userUuid: string) {
|
||||||
try {
|
return await this.roomService.getRoomsByUserId(userUuid);
|
||||||
return await this.roomService.getRoomsByUserId(userUuid);
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard, RoomPermissionGuard)
|
@UseGuards(JwtAuthGuard, RoomPermissionGuard)
|
||||||
@Put('rename/:roomUuid')
|
@Put(':roomUuid')
|
||||||
async renameRoomByUuid(
|
async renameRoomByUuid(
|
||||||
@Param('roomUuid') roomUuid: string,
|
@Param('roomUuid') roomUuid: string,
|
||||||
@Body() updateRoomNameDto: UpdateRoomNameDto,
|
@Body() updateRoomNameDto: UpdateRoomNameDto,
|
||||||
) {
|
) {
|
||||||
try {
|
const room = await this.roomService.renameRoomByUuid(
|
||||||
const room = await this.roomService.renameRoomByUuid(
|
roomUuid,
|
||||||
roomUuid,
|
updateRoomNameDto,
|
||||||
updateRoomNameDto,
|
);
|
||||||
);
|
return room;
|
||||||
return room;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,8 @@ import {
|
|||||||
} from '../interface/room.interface';
|
} from '../interface/room.interface';
|
||||||
import { UpdateRoomNameDto } from '../dtos/update.room.dto';
|
import { UpdateRoomNameDto } from '../dtos/update.room.dto';
|
||||||
import { UserSpaceRepository } from '@app/common/modules/user/repositories';
|
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()
|
@Injectable()
|
||||||
export class RoomService {
|
export class RoomService {
|
||||||
@ -28,7 +30,7 @@ export class RoomService {
|
|||||||
try {
|
try {
|
||||||
const spaceType = await this.spaceTypeRepository.findOne({
|
const spaceType = await this.spaceTypeRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
type: 'room',
|
type: SpaceType.ROOM,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -49,12 +51,12 @@ export class RoomService {
|
|||||||
where: {
|
where: {
|
||||||
uuid: roomUuid,
|
uuid: roomUuid,
|
||||||
spaceType: {
|
spaceType: {
|
||||||
type: 'room',
|
type: SpaceType.ROOM,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
relations: ['spaceType'],
|
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');
|
throw new BadRequestException('Invalid room UUID');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,12 +82,12 @@ export class RoomService {
|
|||||||
where: {
|
where: {
|
||||||
uuid: roomUuid,
|
uuid: roomUuid,
|
||||||
spaceType: {
|
spaceType: {
|
||||||
type: 'room',
|
type: SpaceType.ROOM,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
relations: ['spaceType', 'parent', 'parent.spaceType'],
|
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');
|
throw new BadRequestException('Invalid room UUID');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +118,7 @@ export class RoomService {
|
|||||||
relations: ['space', 'space.spaceType'],
|
relations: ['space', 'space.spaceType'],
|
||||||
where: {
|
where: {
|
||||||
user: { uuid: userUuid },
|
user: { uuid: userUuid },
|
||||||
space: { spaceType: { type: 'room' } },
|
space: { spaceType: { type: SpaceType.ROOM } },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -145,7 +147,7 @@ export class RoomService {
|
|||||||
space: { uuid: addUserRoomDto.roomUuid },
|
space: { uuid: addUserRoomDto.roomUuid },
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.code === '23505') {
|
if (err.code === CommonErrorCodes.DUPLICATE_ENTITY) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
'User already belongs to this room',
|
'User already belongs to this room',
|
||||||
HttpStatus.BAD_REQUEST,
|
HttpStatus.BAD_REQUEST,
|
||||||
@ -167,7 +169,7 @@ export class RoomService {
|
|||||||
relations: ['spaceType'],
|
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');
|
throw new BadRequestException('Invalid room UUID');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import {
|
|||||||
Controller,
|
Controller,
|
||||||
Delete,
|
Delete,
|
||||||
Get,
|
Get,
|
||||||
HttpException,
|
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
Param,
|
Param,
|
||||||
Post,
|
Post,
|
||||||
@ -14,10 +13,11 @@ import {
|
|||||||
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
|
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
|
||||||
import { AddSceneTapToRunDto, UpdateSceneTapToRunDto } from '../dtos/scene.dto';
|
import { AddSceneTapToRunDto, UpdateSceneTapToRunDto } from '../dtos/scene.dto';
|
||||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||||
|
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||||
|
|
||||||
@ApiTags('Scene Module')
|
@ApiTags('Scene Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
version: '1',
|
version: EnableDisableStatusEnum.ENABLED,
|
||||||
path: 'scene',
|
path: 'scene',
|
||||||
})
|
})
|
||||||
export class SceneController {
|
export class SceneController {
|
||||||
@ -27,36 +27,22 @@ export class SceneController {
|
|||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Post('tap-to-run')
|
@Post('tap-to-run')
|
||||||
async addTapToRunScene(@Body() addSceneTapToRunDto: AddSceneTapToRunDto) {
|
async addTapToRunScene(@Body() addSceneTapToRunDto: AddSceneTapToRunDto) {
|
||||||
try {
|
const tapToRunScene =
|
||||||
const tapToRunScene =
|
await this.sceneService.addTapToRunScene(addSceneTapToRunDto);
|
||||||
await this.sceneService.addTapToRunScene(addSceneTapToRunDto);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.CREATED,
|
||||||
statusCode: HttpStatus.CREATED,
|
success: true,
|
||||||
success: true,
|
message: 'Scene added successfully',
|
||||||
message: 'Scene added successfully',
|
data: tapToRunScene,
|
||||||
data: tapToRunScene,
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Get('tap-to-run/:unitUuid')
|
@Get('tap-to-run/:unitUuid')
|
||||||
async getTapToRunSceneByUnit(@Param('unitUuid') unitUuid: string) {
|
async getTapToRunSceneByUnit(@Param('unitUuid') unitUuid: string) {
|
||||||
try {
|
const tapToRunScenes =
|
||||||
const tapToRunScenes =
|
await this.sceneService.getTapToRunSceneByUnit(unitUuid);
|
||||||
await this.sceneService.getTapToRunSceneByUnit(unitUuid);
|
return tapToRunScenes;
|
||||||
return tapToRunScenes;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@ -65,53 +51,31 @@ export class SceneController {
|
|||||||
@Param('unitUuid') unitUuid: string,
|
@Param('unitUuid') unitUuid: string,
|
||||||
@Param('sceneId') sceneId: string,
|
@Param('sceneId') sceneId: string,
|
||||||
) {
|
) {
|
||||||
try {
|
await this.sceneService.deleteTapToRunScene(unitUuid, sceneId);
|
||||||
await this.sceneService.deleteTapToRunScene(unitUuid, sceneId);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.OK,
|
||||||
statusCode: HttpStatus.OK,
|
message: 'Scene Deleted Successfully',
|
||||||
message: 'Scene Deleted Successfully',
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Post('tap-to-run/trigger/:sceneId')
|
@Post('tap-to-run/trigger/:sceneId')
|
||||||
async triggerTapToRunScene(@Param('sceneId') sceneId: string) {
|
async triggerTapToRunScene(@Param('sceneId') sceneId: string) {
|
||||||
try {
|
await this.sceneService.triggerTapToRunScene(sceneId);
|
||||||
await this.sceneService.triggerTapToRunScene(sceneId);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.CREATED,
|
||||||
statusCode: HttpStatus.CREATED,
|
success: true,
|
||||||
success: true,
|
message: 'Scene trigger successfully',
|
||||||
message: 'Scene trigger successfully',
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Get('tap-to-run/details/:sceneId')
|
@Get('tap-to-run/details/:sceneId')
|
||||||
async getTapToRunSceneDetails(@Param('sceneId') sceneId: string) {
|
async getTapToRunSceneDetails(@Param('sceneId') sceneId: string) {
|
||||||
try {
|
const tapToRunScenes =
|
||||||
const tapToRunScenes =
|
await this.sceneService.getTapToRunSceneDetails(sceneId);
|
||||||
await this.sceneService.getTapToRunSceneDetails(sceneId);
|
return tapToRunScenes;
|
||||||
return tapToRunScenes;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
``;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@ -120,22 +84,15 @@ export class SceneController {
|
|||||||
@Body() updateSceneTapToRunDto: UpdateSceneTapToRunDto,
|
@Body() updateSceneTapToRunDto: UpdateSceneTapToRunDto,
|
||||||
@Param('sceneId') sceneId: string,
|
@Param('sceneId') sceneId: string,
|
||||||
) {
|
) {
|
||||||
try {
|
const tapToRunScene = await this.sceneService.updateTapToRunScene(
|
||||||
const tapToRunScene = await this.sceneService.updateTapToRunScene(
|
updateSceneTapToRunDto,
|
||||||
updateSceneTapToRunDto,
|
sceneId,
|
||||||
sceneId,
|
);
|
||||||
);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.CREATED,
|
||||||
statusCode: HttpStatus.CREATED,
|
success: true,
|
||||||
success: true,
|
message: 'Scene updated successfully',
|
||||||
message: 'Scene updated successfully',
|
data: tapToRunScene,
|
||||||
data: tapToRunScene,
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,8 @@ import {
|
|||||||
SceneDetailsResult,
|
SceneDetailsResult,
|
||||||
} from '../interface/scene.interface';
|
} from '../interface/scene.interface';
|
||||||
import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter';
|
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()
|
@Injectable()
|
||||||
export class SceneService {
|
export class SceneService {
|
||||||
@ -63,7 +65,7 @@ export class SceneService {
|
|||||||
|
|
||||||
const convertedData = convertKeysToSnakeCase(actions);
|
const convertedData = convertKeysToSnakeCase(actions);
|
||||||
for (const action of convertedData) {
|
for (const action of convertedData) {
|
||||||
if (action.action_executor === 'device_issue') {
|
if (action.action_executor === ActionExecutorEnum.DEVICE_ISSUE) {
|
||||||
const device = await this.deviceService.getDeviceByDeviceUuid(
|
const device = await this.deviceService.getDeviceByDeviceUuid(
|
||||||
action.entity_id,
|
action.entity_id,
|
||||||
false,
|
false,
|
||||||
@ -108,12 +110,12 @@ export class SceneService {
|
|||||||
where: {
|
where: {
|
||||||
uuid: unitUuid,
|
uuid: unitUuid,
|
||||||
spaceType: {
|
spaceType: {
|
||||||
type: 'unit',
|
type: SpaceType.UNIT,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
relations: ['spaceType'],
|
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');
|
throw new BadRequestException('Invalid unit UUID');
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@ -249,7 +251,7 @@ export class SceneService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (const action of actions) {
|
for (const action of actions) {
|
||||||
if (action.actionExecutor === 'device_issue') {
|
if (action.actionExecutor === ActionExecutorEnum.DEVICE_ISSUE) {
|
||||||
const device = await this.deviceService.getDeviceByDeviceTuyaUuid(
|
const device = await this.deviceService.getDeviceByDeviceTuyaUuid(
|
||||||
action.entityId,
|
action.entityId,
|
||||||
);
|
);
|
||||||
@ -258,8 +260,8 @@ export class SceneService {
|
|||||||
action.entityId = device.uuid;
|
action.entityId = device.uuid;
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
action.actionExecutor !== 'device_issue' &&
|
action.actionExecutor !== ActionExecutorEnum.DEVICE_ISSUE &&
|
||||||
action.actionExecutor !== 'delay'
|
action.actionExecutor !== ActionExecutorEnum.DELAY
|
||||||
) {
|
) {
|
||||||
const sceneDetails = await this.getTapToRunSceneDetailsTuya(
|
const sceneDetails = await this.getTapToRunSceneDetailsTuya(
|
||||||
action.entityId,
|
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 {
|
import { Controller, Get, UseGuards } from '@nestjs/common';
|
||||||
Controller,
|
|
||||||
Get,
|
|
||||||
HttpException,
|
|
||||||
HttpStatus,
|
|
||||||
UseGuards,
|
|
||||||
} from '@nestjs/common';
|
|
||||||
import { TimeZoneService } from '../services/timezone.service';
|
import { TimeZoneService } from '../services/timezone.service';
|
||||||
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
|
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
|
||||||
import { JwtAuthGuard } from '../../../libs/common/src/guards/jwt.auth.guard';
|
import { JwtAuthGuard } from '../../../libs/common/src/guards/jwt.auth.guard';
|
||||||
|
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||||
|
|
||||||
@ApiTags('TimeZone Module')
|
@ApiTags('TimeZone Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
version: '1',
|
version: EnableDisableStatusEnum.ENABLED,
|
||||||
path: 'timezone',
|
path: 'timezone',
|
||||||
})
|
})
|
||||||
export class TimeZoneController {
|
export class TimeZoneController {
|
||||||
@ -21,13 +16,6 @@ export class TimeZoneController {
|
|||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Get()
|
@Get()
|
||||||
async getAllTimeZones() {
|
async getAllTimeZones() {
|
||||||
try {
|
return await this.timeZoneService.getAllTimeZones();
|
||||||
return await this.timeZoneService.getAllTimeZones();
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import {
|
|||||||
Body,
|
Body,
|
||||||
Controller,
|
Controller,
|
||||||
Get,
|
Get,
|
||||||
HttpException,
|
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
Param,
|
Param,
|
||||||
Post,
|
Post,
|
||||||
@ -23,11 +22,13 @@ import { CheckFloorTypeGuard } from 'src/guards/floor.type.guard';
|
|||||||
import { CheckUserUnitGuard } from 'src/guards/user.unit.guard';
|
import { CheckUserUnitGuard } from 'src/guards/user.unit.guard';
|
||||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||||
import { UnitPermissionGuard } from 'src/guards/unit.permission.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')
|
@ApiTags('Unit Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
version: '1',
|
version: EnableDisableStatusEnum.ENABLED,
|
||||||
path: 'unit',
|
path: SpaceType.UNIT,
|
||||||
})
|
})
|
||||||
export class UnitController {
|
export class UnitController {
|
||||||
constructor(private readonly unitService: UnitService) {}
|
constructor(private readonly unitService: UnitService) {}
|
||||||
@ -36,35 +37,21 @@ export class UnitController {
|
|||||||
@UseGuards(JwtAuthGuard, CheckFloorTypeGuard)
|
@UseGuards(JwtAuthGuard, CheckFloorTypeGuard)
|
||||||
@Post()
|
@Post()
|
||||||
async addUnit(@Body() addUnitDto: AddUnitDto) {
|
async addUnit(@Body() addUnitDto: AddUnitDto) {
|
||||||
try {
|
const unit = await this.unitService.addUnit(addUnitDto);
|
||||||
const unit = await this.unitService.addUnit(addUnitDto);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.CREATED,
|
||||||
statusCode: HttpStatus.CREATED,
|
success: true,
|
||||||
success: true,
|
message: 'Unit added successfully',
|
||||||
message: 'Unit added successfully',
|
data: unit,
|
||||||
data: unit,
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard, UnitPermissionGuard)
|
@UseGuards(JwtAuthGuard, UnitPermissionGuard)
|
||||||
@Get(':unitUuid')
|
@Get(':unitUuid')
|
||||||
async getUnitByUuid(@Param('unitUuid') unitUuid: string) {
|
async getUnitByUuid(@Param('unitUuid') unitUuid: string) {
|
||||||
try {
|
const unit = await this.unitService.getUnitByUuid(unitUuid);
|
||||||
const unit = await this.unitService.getUnitByUuid(unitUuid);
|
return unit;
|
||||||
return unit;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@ -74,95 +61,53 @@ export class UnitController {
|
|||||||
@Param('unitUuid') unitUuid: string,
|
@Param('unitUuid') unitUuid: string,
|
||||||
@Query() query: GetUnitChildDto,
|
@Query() query: GetUnitChildDto,
|
||||||
) {
|
) {
|
||||||
try {
|
const unit = await this.unitService.getUnitChildByUuid(unitUuid, query);
|
||||||
const unit = await this.unitService.getUnitChildByUuid(unitUuid, query);
|
return unit;
|
||||||
return unit;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard, UnitPermissionGuard)
|
@UseGuards(JwtAuthGuard, UnitPermissionGuard)
|
||||||
@Get('parent/:unitUuid')
|
@Get('parent/:unitUuid')
|
||||||
async getUnitParentByUuid(@Param('unitUuid') unitUuid: string) {
|
async getUnitParentByUuid(@Param('unitUuid') unitUuid: string) {
|
||||||
try {
|
const unit = await this.unitService.getUnitParentByUuid(unitUuid);
|
||||||
const unit = await this.unitService.getUnitParentByUuid(unitUuid);
|
return unit;
|
||||||
return unit;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard, CheckUserUnitGuard)
|
@UseGuards(JwtAuthGuard, CheckUserUnitGuard)
|
||||||
@Post('user')
|
@Post('user')
|
||||||
async addUserUnit(@Body() addUserUnitDto: AddUserUnitDto) {
|
async addUserUnit(@Body() addUserUnitDto: AddUserUnitDto) {
|
||||||
try {
|
await this.unitService.addUserUnit(addUserUnitDto);
|
||||||
await this.unitService.addUserUnit(addUserUnitDto);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.CREATED,
|
||||||
statusCode: HttpStatus.CREATED,
|
success: true,
|
||||||
success: true,
|
message: 'user unit added successfully',
|
||||||
message: 'user unit added successfully',
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Get('user/:userUuid')
|
@Get('user/:userUuid')
|
||||||
async getUnitsByUserId(@Param('userUuid') userUuid: string) {
|
async getUnitsByUserId(@Param('userUuid') userUuid: string) {
|
||||||
try {
|
return await this.unitService.getUnitsByUserId(userUuid);
|
||||||
return await this.unitService.getUnitsByUserId(userUuid);
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard, UnitPermissionGuard)
|
@UseGuards(JwtAuthGuard, UnitPermissionGuard)
|
||||||
@Put('rename/:unitUuid')
|
@Put(':unitUuid')
|
||||||
async renameUnitByUuid(
|
async renameUnitByUuid(
|
||||||
@Param('unitUuid') unitUuid: string,
|
@Param('unitUuid') unitUuid: string,
|
||||||
@Body() updateUnitNameDto: UpdateUnitNameDto,
|
@Body() updateUnitNameDto: UpdateUnitNameDto,
|
||||||
) {
|
) {
|
||||||
try {
|
const unit = await this.unitService.renameUnitByUuid(
|
||||||
const unit = await this.unitService.renameUnitByUuid(
|
unitUuid,
|
||||||
unitUuid,
|
updateUnitNameDto,
|
||||||
updateUnitNameDto,
|
);
|
||||||
);
|
return unit;
|
||||||
return unit;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard, UnitPermissionGuard)
|
@UseGuards(JwtAuthGuard, UnitPermissionGuard)
|
||||||
@Get(':unitUuid/invitation-code')
|
@Get(':unitUuid/invitation-code')
|
||||||
async getUnitInvitationCode(@Param('unitUuid') unitUuid: string) {
|
async getUnitInvitationCode(@Param('unitUuid') unitUuid: string) {
|
||||||
try {
|
const unit = await this.unitService.getUnitInvitationCode(unitUuid);
|
||||||
const unit = await this.unitService.getUnitInvitationCode(unitUuid);
|
return unit;
|
||||||
return unit;
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@ -171,18 +116,11 @@ export class UnitController {
|
|||||||
async verifyCodeAndAddUserUnit(
|
async verifyCodeAndAddUserUnit(
|
||||||
@Body() addUserUnitUsingCodeDto: AddUserUnitUsingCodeDto,
|
@Body() addUserUnitUsingCodeDto: AddUserUnitUsingCodeDto,
|
||||||
) {
|
) {
|
||||||
try {
|
await this.unitService.verifyCodeAndAddUserUnit(addUserUnitUsingCodeDto);
|
||||||
await this.unitService.verifyCodeAndAddUserUnit(addUserUnitUsingCodeDto);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.CREATED,
|
||||||
statusCode: HttpStatus.CREATED,
|
success: true,
|
||||||
success: true,
|
message: 'user unit added successfully',
|
||||||
message: 'user unit added successfully',
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,6 +24,8 @@ import { UserDevicePermissionService } from 'src/user-device-permission/services
|
|||||||
import { PermissionType } from '@app/common/constants/permission-type.enum';
|
import { PermissionType } from '@app/common/constants/permission-type.enum';
|
||||||
import { TuyaContext } from '@tuya/tuya-connector-nodejs';
|
import { TuyaContext } from '@tuya/tuya-connector-nodejs';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { SpaceType } from '@app/common/constants/space-type.enum';
|
||||||
|
import { CommonErrorCodes } from '@app/common/constants/error-codes.enum';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UnitService {
|
export class UnitService {
|
||||||
@ -50,7 +52,7 @@ export class UnitService {
|
|||||||
try {
|
try {
|
||||||
const spaceType = await this.spaceTypeRepository.findOne({
|
const spaceType = await this.spaceTypeRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
type: 'unit',
|
type: SpaceType.UNIT,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const tuyaUnit = await this.addUnitTuya(addUnitDto.unitName);
|
const tuyaUnit = await this.addUnitTuya(addUnitDto.unitName);
|
||||||
@ -95,12 +97,12 @@ export class UnitService {
|
|||||||
where: {
|
where: {
|
||||||
uuid: unitUuid,
|
uuid: unitUuid,
|
||||||
spaceType: {
|
spaceType: {
|
||||||
type: 'unit',
|
type: SpaceType.UNIT,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
relations: ['spaceType'],
|
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');
|
throw new BadRequestException('Invalid unit UUID');
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@ -131,7 +133,11 @@ export class UnitService {
|
|||||||
relations: ['children', 'spaceType'],
|
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');
|
throw new BadRequestException('Invalid unit UUID');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,10 +180,10 @@ export class UnitService {
|
|||||||
return children
|
return children
|
||||||
.filter(
|
.filter(
|
||||||
(child) =>
|
(child) =>
|
||||||
child.spaceType.type !== 'unit' &&
|
child.spaceType.type !== SpaceType.UNIT &&
|
||||||
child.spaceType.type !== 'floor' &&
|
child.spaceType.type !== SpaceType.FLOOR &&
|
||||||
child.spaceType.type !== 'community' &&
|
child.spaceType.type !== SpaceType.COMMUNITY &&
|
||||||
child.spaceType.type !== 'unit',
|
child.spaceType.type !== SpaceType.UNIT,
|
||||||
) // Filter remaining unit and floor and community and unit types
|
) // Filter remaining unit and floor and community and unit types
|
||||||
.map((child) => ({
|
.map((child) => ({
|
||||||
uuid: child.uuid,
|
uuid: child.uuid,
|
||||||
@ -190,10 +196,10 @@ export class UnitService {
|
|||||||
children
|
children
|
||||||
.filter(
|
.filter(
|
||||||
(child) =>
|
(child) =>
|
||||||
child.spaceType.type !== 'unit' &&
|
child.spaceType.type !== SpaceType.UNIT &&
|
||||||
child.spaceType.type !== 'floor' &&
|
child.spaceType.type !== SpaceType.FLOOR &&
|
||||||
child.spaceType.type !== 'community' &&
|
child.spaceType.type !== SpaceType.COMMUNITY &&
|
||||||
child.spaceType.type !== 'unit',
|
child.spaceType.type !== SpaceType.UNIT,
|
||||||
) // Filter remaining unit and floor and community and unit types
|
) // Filter remaining unit and floor and community and unit types
|
||||||
.map(async (child) => ({
|
.map(async (child) => ({
|
||||||
uuid: child.uuid,
|
uuid: child.uuid,
|
||||||
@ -212,12 +218,12 @@ export class UnitService {
|
|||||||
where: {
|
where: {
|
||||||
uuid: unitUuid,
|
uuid: unitUuid,
|
||||||
spaceType: {
|
spaceType: {
|
||||||
type: 'unit',
|
type: SpaceType.UNIT,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
relations: ['spaceType', 'parent', 'parent.spaceType'],
|
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');
|
throw new BadRequestException('Invalid unit UUID');
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@ -246,7 +252,7 @@ export class UnitService {
|
|||||||
relations: ['space', 'space.spaceType'],
|
relations: ['space', 'space.spaceType'],
|
||||||
where: {
|
where: {
|
||||||
user: { uuid: userUuid },
|
user: { uuid: userUuid },
|
||||||
space: { spaceType: { type: 'unit' } },
|
space: { spaceType: { type: SpaceType.UNIT } },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -276,7 +282,7 @@ export class UnitService {
|
|||||||
space: { uuid: addUserUnitDto.unitUuid },
|
space: { uuid: addUserUnitDto.unitUuid },
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.code === '23505') {
|
if (err.code === CommonErrorCodes.DUPLICATE_ENTITY) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
'User already belongs to this unit',
|
'User already belongs to this unit',
|
||||||
HttpStatus.BAD_REQUEST,
|
HttpStatus.BAD_REQUEST,
|
||||||
@ -298,7 +304,7 @@ export class UnitService {
|
|||||||
relations: ['spaceType'],
|
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');
|
throw new BadRequestException('Invalid unit UUID');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,7 +389,7 @@ export class UnitService {
|
|||||||
const unit = await this.spaceRepository.findOneOrFail({
|
const unit = await this.spaceRepository.findOneOrFail({
|
||||||
where: {
|
where: {
|
||||||
invitationCode: inviteCode,
|
invitationCode: inviteCode,
|
||||||
spaceType: { type: 'unit' },
|
spaceType: { type: SpaceType.UNIT },
|
||||||
},
|
},
|
||||||
relations: ['spaceType'],
|
relations: ['spaceType'],
|
||||||
});
|
});
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import {
|
|||||||
Controller,
|
Controller,
|
||||||
Delete,
|
Delete,
|
||||||
Get,
|
Get,
|
||||||
HttpException,
|
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
Param,
|
Param,
|
||||||
Post,
|
Post,
|
||||||
@ -15,10 +14,11 @@ import { UserDevicePermissionService } from '../services/user-device-permission.
|
|||||||
import { UserDevicePermissionAddDto } from '../dtos/user-device-permission.add.dto';
|
import { UserDevicePermissionAddDto } from '../dtos/user-device-permission.add.dto';
|
||||||
import { UserDevicePermissionEditDto } from '../dtos/user-device-permission.edit.dto';
|
import { UserDevicePermissionEditDto } from '../dtos/user-device-permission.edit.dto';
|
||||||
import { AdminRoleGuard } from 'src/guards/admin.role.guard';
|
import { AdminRoleGuard } from 'src/guards/admin.role.guard';
|
||||||
|
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||||
|
|
||||||
@ApiTags('Device Permission Module')
|
@ApiTags('Device Permission Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
version: '1',
|
version: EnableDisableStatusEnum.ENABLED,
|
||||||
path: 'device-permission',
|
path: 'device-permission',
|
||||||
})
|
})
|
||||||
export class UserDevicePermissionController {
|
export class UserDevicePermissionController {
|
||||||
@ -28,67 +28,48 @@ export class UserDevicePermissionController {
|
|||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(AdminRoleGuard)
|
@UseGuards(AdminRoleGuard)
|
||||||
@Post('add')
|
@Post()
|
||||||
async addDevicePermission(
|
async addDevicePermission(
|
||||||
@Body() userDevicePermissionDto: UserDevicePermissionAddDto,
|
@Body() userDevicePermissionDto: UserDevicePermissionAddDto,
|
||||||
) {
|
) {
|
||||||
try {
|
const addDetails = await this.userDevicePermissionService.addUserPermission(
|
||||||
const addDetails =
|
userDevicePermissionDto,
|
||||||
await this.userDevicePermissionService.addUserPermission(
|
);
|
||||||
userDevicePermissionDto,
|
return {
|
||||||
);
|
statusCode: HttpStatus.CREATED,
|
||||||
return {
|
message: 'User Permission for Devices Added Successfully',
|
||||||
statusCode: HttpStatus.CREATED,
|
data: addDetails,
|
||||||
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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(AdminRoleGuard)
|
@UseGuards(AdminRoleGuard)
|
||||||
@Put('edit/:devicePermissionUuid')
|
@Put(':devicePermissionUuid')
|
||||||
async editDevicePermission(
|
async editDevicePermission(
|
||||||
@Param('devicePermissionUuid') devicePermissionUuid: string,
|
@Param('devicePermissionUuid') devicePermissionUuid: string,
|
||||||
@Body() userDevicePermissionEditDto: UserDevicePermissionEditDto,
|
@Body() userDevicePermissionEditDto: UserDevicePermissionEditDto,
|
||||||
) {
|
) {
|
||||||
try {
|
await this.userDevicePermissionService.editUserPermission(
|
||||||
await this.userDevicePermissionService.editUserPermission(
|
devicePermissionUuid,
|
||||||
devicePermissionUuid,
|
userDevicePermissionEditDto,
|
||||||
userDevicePermissionEditDto,
|
);
|
||||||
);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.OK,
|
||||||
statusCode: HttpStatus.OK,
|
message: 'User Permission for Devices Updated Successfully',
|
||||||
message: 'User Permission for Devices Updated Successfully',
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(AdminRoleGuard)
|
@UseGuards(AdminRoleGuard)
|
||||||
@Get(':deviceUuid/list')
|
@Get(':deviceUuid')
|
||||||
async fetchDevicePermission(@Param('deviceUuid') deviceUuid: string) {
|
async fetchDevicePermission(@Param('deviceUuid') deviceUuid: string) {
|
||||||
try {
|
const deviceDetails =
|
||||||
const deviceDetails =
|
await this.userDevicePermissionService.fetchUserPermission(deviceUuid);
|
||||||
await this.userDevicePermissionService.fetchUserPermission(deviceUuid);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.OK,
|
||||||
statusCode: HttpStatus.OK,
|
message: 'Device Details fetched Successfully',
|
||||||
message: 'Device Details fetched Successfully',
|
data: deviceDetails,
|
||||||
data: deviceDetails,
|
};
|
||||||
};
|
|
||||||
} catch (err) {
|
|
||||||
throw new Error(err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(AdminRoleGuard)
|
@UseGuards(AdminRoleGuard)
|
||||||
@ -96,19 +77,12 @@ export class UserDevicePermissionController {
|
|||||||
async deleteDevicePermission(
|
async deleteDevicePermission(
|
||||||
@Param('devicePermissionUuid') devicePermissionUuid: string,
|
@Param('devicePermissionUuid') devicePermissionUuid: string,
|
||||||
) {
|
) {
|
||||||
try {
|
await this.userDevicePermissionService.deleteDevicePermission(
|
||||||
await this.userDevicePermissionService.deleteDevicePermission(
|
devicePermissionUuid,
|
||||||
devicePermissionUuid,
|
);
|
||||||
);
|
return {
|
||||||
return {
|
statusCode: HttpStatus.OK,
|
||||||
statusCode: HttpStatus.OK,
|
message: 'User Permission for Devices Deleted Successfully',
|
||||||
message: 'User Permission for Devices Deleted Successfully',
|
};
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
throw new HttpException(
|
|
||||||
error.message || 'Internal server error',
|
|
||||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user