From bc0a8627c4c6fb75c9f625215f015790eb6dbdf8 Mon Sep 17 00:00:00 2001 From: yousef-alkhrissat Date: Sat, 24 Aug 2024 13:09:21 +0300 Subject: [PATCH 01/12] added google login --- libs/common/src/auth/services/auth.service.ts | 31 ++++++++++++++++++- src/auth/dtos/user-login.dto.ts | 4 +++ src/auth/services/user-auth.service.ts | 1 + 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/libs/common/src/auth/services/auth.service.ts b/libs/common/src/auth/services/auth.service.ts index af9d047..5808ce7 100644 --- a/libs/common/src/auth/services/auth.service.ts +++ b/libs/common/src/auth/services/auth.service.ts @@ -1,4 +1,4 @@ -import { BadRequestException, Injectable } from '@nestjs/common'; +import { BadRequestException, Injectable, UnauthorizedException } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import * as argon2 from 'argon2'; import { HelperHashService } from '../../helper/services'; @@ -6,6 +6,7 @@ import { UserRepository } from '../../../../common/src/modules/user/repositories import { UserSessionRepository } from '../../../../common/src/modules/session/repositories/session.repository'; import { UserSessionEntity } from '../../../../common/src/modules/session/entities'; import { ConfigService } from '@nestjs/config'; +import axios from 'axios'; @Injectable() export class AuthService { @@ -80,8 +81,18 @@ export class AuthService { type: user.type, sessionId: user.sessionId, roles: user?.roles, + googleCode: user.googleCode, }; + if (payload.googleCode) { + const profile = await this.getProfile(payload.googleCode); + user = await this.userRepository.findOne({ + where: { email: profile.data.email }, + }); + if (!user) { + throw new UnauthorizedException('wrong credentials'); + } + } const tokens = await this.getTokens(payload); await this.updateRefreshToken(user.uuid, tokens.refreshToken); return tokens; @@ -100,4 +111,22 @@ export class AuthService { hashData(data: string) { return argon2.hash(data); } + + async getProfile(googleCode: string) { + try { + const response = await axios.post('https://oauth2.googleapis.com/token', { + client_id: process.env.GOOGLE_CLIENT_ID, + client_secret: process.env.GOOGLE_CLIENT_SECRET, + code: googleCode, + grant_type: 'authorization_code', + redirect_uri: 'http://localhost:3000/auth/google/callback', + }); + return axios.get( + `https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=${response.data.access_token}`, + ); + } catch (error) { + console.error('Failed to get profile:', error); + throw new UnauthorizedException('google login failed'); + } + } } diff --git a/src/auth/dtos/user-login.dto.ts b/src/auth/dtos/user-login.dto.ts index 1f3662b..dedb08f 100644 --- a/src/auth/dtos/user-login.dto.ts +++ b/src/auth/dtos/user-login.dto.ts @@ -16,4 +16,8 @@ export class UserLoginDto { @IsString() @IsOptional() regionUuid?: string; + + @IsOptional() + @IsString() + googleCode?: string; } diff --git a/src/auth/services/user-auth.service.ts b/src/auth/services/user-auth.service.ts index 7b539e2..88e989e 100644 --- a/src/auth/services/user-auth.service.ts +++ b/src/auth/services/user-auth.service.ts @@ -122,6 +122,7 @@ export class UserAuthService { return { uuid: role.uuid, type: role.roleType.type }; }), sessionId: session[1].uuid, + googleCode: data.googleCode, }); } catch (error) { throw new BadRequestException('Invalid credentials'); From 20156568e23737eb9936c46dac79340c08f954d6 Mon Sep 17 00:00:00 2001 From: yousef-khriasat-uba Date: Sun, 25 Aug 2024 10:53:27 +0300 Subject: [PATCH 02/12] added env example --- .env.example | 3 +++ libs/common/src/auth/services/auth.service.ts | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 54773c4..8fb1460 100644 --- a/.env.example +++ b/.env.example @@ -90,3 +90,6 @@ FIREBASE_DATABASE_URL= OTP_LIMITER= +GOOGLE_CLIENT_ID= + +GOOGLE_CLIENT_SECRET= \ No newline at end of file diff --git a/libs/common/src/auth/services/auth.service.ts b/libs/common/src/auth/services/auth.service.ts index 5808ce7..3174b11 100644 --- a/libs/common/src/auth/services/auth.service.ts +++ b/libs/common/src/auth/services/auth.service.ts @@ -115,8 +115,8 @@ export class AuthService { async getProfile(googleCode: string) { try { const response = await axios.post('https://oauth2.googleapis.com/token', { - client_id: process.env.GOOGLE_CLIENT_ID, - client_secret: process.env.GOOGLE_CLIENT_SECRET, + client_id: this.configService('GOOGLE_CLIENT_ID'), + client_secret: this.configService('GOOGLE_CLIENT_SECRET'), code: googleCode, grant_type: 'authorization_code', redirect_uri: 'http://localhost:3000/auth/google/callback', From c0c41cf91d0986dff0754aba923a57e54a3b77eb Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 1 Oct 2024 16:52:42 +0300 Subject: [PATCH 03/12] google login done --- libs/common/src/auth/services/auth.service.ts | 36 +- package-lock.json | 346 +++++++++--------- package.json | 3 +- src/auth/dtos/user-auth.dto.ts | 2 +- src/auth/dtos/user-login.dto.ts | 8 +- src/auth/services/user-auth.service.ts | 44 ++- 6 files changed, 227 insertions(+), 212 deletions(-) diff --git a/libs/common/src/auth/services/auth.service.ts b/libs/common/src/auth/services/auth.service.ts index 3174b11..86bb826 100644 --- a/libs/common/src/auth/services/auth.service.ts +++ b/libs/common/src/auth/services/auth.service.ts @@ -1,4 +1,8 @@ -import { BadRequestException, Injectable, UnauthorizedException } from '@nestjs/common'; +import { + BadRequestException, + Injectable, + UnauthorizedException, +} from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import * as argon2 from 'argon2'; import { HelperHashService } from '../../helper/services'; @@ -7,16 +11,20 @@ import { UserSessionRepository } from '../../../../common/src/modules/session/re import { UserSessionEntity } from '../../../../common/src/modules/session/entities'; import { ConfigService } from '@nestjs/config'; import axios from 'axios'; +import { OAuth2Client } from 'google-auth-library'; @Injectable() export class AuthService { + private client: OAuth2Client; constructor( private jwtService: JwtService, private readonly userRepository: UserRepository, private readonly sessionRepository: UserSessionRepository, private readonly helperHashService: HelperHashService, private readonly configService: ConfigService, - ) {} + ) { + this.client = new OAuth2Client(this.configService.get('GOOGLE_CLIENT_ID')); + } async validateUser( email: string, @@ -83,14 +91,13 @@ export class AuthService { roles: user?.roles, googleCode: user.googleCode, }; - if (payload.googleCode) { const profile = await this.getProfile(payload.googleCode); user = await this.userRepository.findOne({ - where: { email: profile.data.email }, + where: { email: profile.email }, }); if (!user) { - throw new UnauthorizedException('wrong credentials'); + return { profile }; } } const tokens = await this.getTokens(payload); @@ -114,19 +121,16 @@ export class AuthService { async getProfile(googleCode: string) { try { - const response = await axios.post('https://oauth2.googleapis.com/token', { - client_id: this.configService('GOOGLE_CLIENT_ID'), - client_secret: this.configService('GOOGLE_CLIENT_SECRET'), - code: googleCode, - grant_type: 'authorization_code', - redirect_uri: 'http://localhost:3000/auth/google/callback', + const ticket = await this.client.verifyIdToken({ + idToken: googleCode, + audience: this.configService.get('GOOGLE_CLIENT_ID'), }); - return axios.get( - `https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=${response.data.access_token}`, - ); + const payload = ticket.getPayload(); + return { + ...payload, + }; } catch (error) { - console.error('Failed to get profile:', error); - throw new UnauthorizedException('google login failed'); + throw new UnauthorizedException('Google login failed'); } } } diff --git a/package-lock.json b/package-lock.json index db7b28d..9a92384 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,13 +20,14 @@ "@nestjs/websockets": "^10.3.8", "@tuya/tuya-connector-nodejs": "^2.1.2", "argon2": "^0.40.1", - "axios": "^1.6.7", + "axios": "^1.7.7", "bcryptjs": "^2.4.3", "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "crypto-js": "^4.2.0", "express-rate-limit": "^7.1.5", "firebase": "^10.12.5", + "google-auth-library": "^9.14.1", "helmet": "^7.1.0", "ioredis": "^5.3.2", "morgan": "^1.10.0", @@ -2258,6 +2259,8 @@ "version": "1.1.8", "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.8.tgz", "integrity": "sha512-qKwC/M/nNNaKUBMQ0nuzm47b7ZYWQHN3pcXq4IIcoSBc2hOIrflAxJduIvvqmhoz3gR2TacTAs8vlsCVPkiEdQ==", + "optional": true, + "peer": true, "dependencies": { "sparse-bitfield": "^3.0.3" } @@ -2490,17 +2493,6 @@ } } }, - "node_modules/@nestjs/mongoose": { - "version": "10.0.10", - "resolved": "https://registry.npmjs.org/@nestjs/mongoose/-/mongoose-10.0.10.tgz", - "integrity": "sha512-3Ff60ock8nwlAJC823TG91Qy+Qc6av+ddIb6n6wlFsTK0akDF/aTcagX8cF8uI8mWxCWjEwEsgv99vo6p0yJ+w==", - "peerDependencies": { - "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", - "@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0", - "mongoose": "^6.0.2 || ^7.0.0 || ^8.0.0", - "rxjs": "^7.0.0" - } - }, "node_modules/@nestjs/passport": { "version": "10.0.3", "resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-10.0.3.tgz", @@ -3138,7 +3130,9 @@ "node_modules/@types/webidl-conversions": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", - "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "optional": true, + "peer": true }, "node_modules/@types/whatwg-url": { "version": "8.2.2", @@ -3571,6 +3565,18 @@ "node": ">=0.4.0" } }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/ajv": { "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", @@ -3791,11 +3797,12 @@ "integrity": "sha512-3AungXC4I8kKsS9PuS4JH2nc+0bVY/mjgrephHTIi8fpEeGsTHBUJeosp0Wc1myYMElmD0B3Oc4XL/HVJ4PV2g==" }, "node_modules/axios": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", - "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.4", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -3969,6 +3976,15 @@ "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" }, + "node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -4131,14 +4147,6 @@ "node-int64": "^0.4.0" } }, - "node_modules/bson": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz", - "integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==", - "engines": { - "node": ">=16.20.1" - } - }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -5902,15 +5910,16 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", "funding": [ { "type": "individual", "url": "https://github.com/sponsors/RubenVerborgh" } ], + "license": "MIT", "engines": { "node": ">=4.0" }, @@ -6071,6 +6080,35 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gaxios": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz", + "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^6.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -6209,6 +6247,44 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/google-auth-library": { + "version": "9.14.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.14.1.tgz", + "integrity": "sha512-Rj+PMjoNFGFTmtItH7gHfbHpGVSb3vmnGK3nwNBqxQF9NoBpttSZI/rc0WiM63ma2uGDQtYEkMHkK9U6937NiA==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/google-auth-library/node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/google-auth-library/node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -6232,6 +6308,40 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "node_modules/gtoken": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "license": "MIT", + "dependencies": { + "gaxios": "^6.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/gtoken/node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/gtoken/node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "node_modules/har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -6399,6 +6509,19 @@ "npm": ">=1.3.7" } }, + "node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -6704,7 +6827,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, "engines": { "node": ">=8" }, @@ -7548,6 +7670,15 @@ "node": ">=4" } }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -7666,14 +7797,6 @@ "safe-buffer": "^5.0.1" } }, - "node_modules/kareem": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz", - "integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==", - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -7911,7 +8034,9 @@ "node_modules/memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true, + "peer": true }, "node_modules/merge-descriptors": { "version": "1.0.1", @@ -8146,125 +8271,6 @@ "node": ">=14.20.1" } }, - "node_modules/mongoose": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.5.1.tgz", - "integrity": "sha512-OhVcwVl91A1G6+XpjDcpkGP7l7ikZkxa0DylX7NT/lcEqAjggzSdqDxb48A+xsDxqNAr0ntSJ1yiE3+KJTOd5Q==", - "dependencies": { - "bson": "^6.7.0", - "kareem": "2.6.3", - "mongodb": "6.7.0", - "mpath": "0.9.0", - "mquery": "5.0.0", - "ms": "2.1.3", - "sift": "17.1.3" - }, - "engines": { - "node": ">=16.20.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mongoose" - } - }, - "node_modules/mongoose/node_modules/@types/whatwg-url": { - "version": "11.0.5", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", - "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", - "dependencies": { - "@types/webidl-conversions": "*" - } - }, - "node_modules/mongoose/node_modules/mongodb": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.7.0.tgz", - "integrity": "sha512-TMKyHdtMcO0fYBNORiYdmM25ijsHs+Njs963r4Tro4OQZzqYigAzYQouwWRg4OIaiLRUEGUh/1UAcH5lxdSLIA==", - "dependencies": { - "@mongodb-js/saslprep": "^1.1.5", - "bson": "^6.7.0", - "mongodb-connection-string-url": "^3.0.0" - }, - "engines": { - "node": ">=16.20.1" - }, - "peerDependencies": { - "@aws-sdk/credential-providers": "^3.188.0", - "@mongodb-js/zstd": "^1.1.0", - "gcp-metadata": "^5.2.0", - "kerberos": "^2.0.1", - "mongodb-client-encryption": ">=6.0.0 <7", - "snappy": "^7.2.2", - "socks": "^2.7.1" - }, - "peerDependenciesMeta": { - "@aws-sdk/credential-providers": { - "optional": true - }, - "@mongodb-js/zstd": { - "optional": true - }, - "gcp-metadata": { - "optional": true - }, - "kerberos": { - "optional": true - }, - "mongodb-client-encryption": { - "optional": true - }, - "snappy": { - "optional": true - }, - "socks": { - "optional": true - } - } - }, - "node_modules/mongoose/node_modules/mongodb-connection-string-url": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", - "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", - "dependencies": { - "@types/whatwg-url": "^11.0.2", - "whatwg-url": "^13.0.0" - } - }, - "node_modules/mongoose/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/mongoose/node_modules/tr46": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", - "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", - "dependencies": { - "punycode": "^2.3.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/mongoose/node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "engines": { - "node": ">=12" - } - }, - "node_modules/mongoose/node_modules/whatwg-url": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", - "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", - "dependencies": { - "tr46": "^4.1.1", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=16" - } - }, "node_modules/morgan": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", @@ -8304,25 +8310,6 @@ "node": ">= 0.8" } }, - "node_modules/mpath": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", - "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mquery": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", - "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", - "dependencies": { - "debug": "4.x" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -9956,11 +9943,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sift": { - "version": "17.1.3", - "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz", - "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==" - }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -10045,6 +10027,8 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "optional": true, + "peer": true, "dependencies": { "memory-pager": "^1.0.2" } diff --git a/package.json b/package.json index 4883516..d3c90e0 100644 --- a/package.json +++ b/package.json @@ -31,13 +31,14 @@ "@nestjs/websockets": "^10.3.8", "@tuya/tuya-connector-nodejs": "^2.1.2", "argon2": "^0.40.1", - "axios": "^1.6.7", + "axios": "^1.7.7", "bcryptjs": "^2.4.3", "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "crypto-js": "^4.2.0", "express-rate-limit": "^7.1.5", "firebase": "^10.12.5", + "google-auth-library": "^9.14.1", "helmet": "^7.1.0", "ioredis": "^5.3.2", "morgan": "^1.10.0", diff --git a/src/auth/dtos/user-auth.dto.ts b/src/auth/dtos/user-auth.dto.ts index b934c4c..dad1e07 100644 --- a/src/auth/dtos/user-auth.dto.ts +++ b/src/auth/dtos/user-auth.dto.ts @@ -41,5 +41,5 @@ export class UserSignUpDto { @IsString() @IsOptional() - public regionUuid: string; + public regionUuid?: string; } diff --git a/src/auth/dtos/user-login.dto.ts b/src/auth/dtos/user-login.dto.ts index dedb08f..198ae12 100644 --- a/src/auth/dtos/user-login.dto.ts +++ b/src/auth/dtos/user-login.dto.ts @@ -1,16 +1,16 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator'; +import { IsEmail, IsOptional, IsString } from 'class-validator'; export class UserLoginDto { @ApiProperty() @IsEmail() - @IsNotEmpty() - email: string; + @IsOptional() + email?: string; @ApiProperty() @IsString() @IsOptional() - password: string; + password?: string; @ApiProperty() @IsString() diff --git a/src/auth/services/user-auth.service.ts b/src/auth/services/user-auth.service.ts index 88e989e..6289e9e 100644 --- a/src/auth/services/user-auth.service.ts +++ b/src/auth/services/user-auth.service.ts @@ -21,6 +21,7 @@ import * as argon2 from 'argon2'; import { differenceInSeconds } from '@app/common/helper/differenceInSeconds'; import { LessThan, MoreThan } from 'typeorm'; import { ConfigService } from '@nestjs/config'; +import { UUID } from 'typeorm/driver/mongodb/bson.typings'; @Injectable() export class UserAuthService { @@ -93,13 +94,38 @@ export class UserAuthService { async userLogin(data: UserLoginDto) { try { - const user = await this.authService.validateUser( - data.email, - data.password, - data.regionUuid, - ); - if (!user) { - throw new UnauthorizedException('Invalid login credentials.'); + let user; + if (data.googleCode) { + const googleUserData = await this.authService.login({ + googleCode: data.googleCode, + }); + const userExists = await this.userRepository.exists({ + where: { + email: googleUserData['email'], + }, + }); + user = await this.userRepository.findOne({ + where: { + email: googleUserData['email'], + }, + }); + if (!userExists) { + await this.signUp({ + email: googleUserData['email'], + firstName: googleUserData['given_name'], + lastName: googleUserData['family_name'], + password: googleUserData['email'], + }); + } + data.email = googleUserData['email']; + data.password = googleUserData['password']; + } + if (!data.googleCode) { + user = await this.authService.validateUser( + data.email, + data.password, + data.regionUuid, + ); } const session = await Promise.all([ await this.sessionRepository.update( @@ -114,7 +140,7 @@ export class UserAuthService { isLoggedOut: false, }), ]); - return await this.authService.login({ + const res = await this.authService.login({ email: user.email, userId: user.uuid, uuid: user.uuid, @@ -122,8 +148,8 @@ export class UserAuthService { return { uuid: role.uuid, type: role.roleType.type }; }), sessionId: session[1].uuid, - googleCode: data.googleCode, }); + return res; } catch (error) { throw new BadRequestException('Invalid credentials'); } From 553f08641e7c07a397c972d897e75e11e9bda762 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 4 Oct 2024 22:04:19 +0300 Subject: [PATCH 04/12] added a dedicated error handler service --- libs/common/src/auth/services/auth.service.ts | 1 + libs/common/src/common.module.ts | 12 ++++-- .../http-exception.filter.spec.ts | 7 ++++ .../http-exception/http-exception.filter.ts | 38 ++++++++++++++++++ .../error-message.service.spec.ts | 18 +++++++++ src/error-message/error-message.service.ts | 40 +++++++++++++++++++ src/main.ts | 2 + src/region/region.module.ts | 3 +- src/region/services/region.service.ts | 16 ++++++-- 9 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 src/common/filters/http-exception/http-exception.filter.spec.ts create mode 100644 src/common/filters/http-exception/http-exception.filter.ts create mode 100644 src/error-message/error-message.service.spec.ts create mode 100644 src/error-message/error-message.service.ts diff --git a/libs/common/src/auth/services/auth.service.ts b/libs/common/src/auth/services/auth.service.ts index af9d047..28940f9 100644 --- a/libs/common/src/auth/services/auth.service.ts +++ b/libs/common/src/auth/services/auth.service.ts @@ -6,6 +6,7 @@ import { UserRepository } from '../../../../common/src/modules/user/repositories import { UserSessionRepository } from '../../../../common/src/modules/session/repositories/session.repository'; import { UserSessionEntity } from '../../../../common/src/modules/session/entities'; import { ConfigService } from '@nestjs/config'; +import { OAuth2Client } from 'google-auth-library'; @Injectable() export class AuthService { diff --git a/libs/common/src/common.module.ts b/libs/common/src/common.module.ts index 8c3e78c..d156de3 100644 --- a/libs/common/src/common.module.ts +++ b/libs/common/src/common.module.ts @@ -6,10 +6,16 @@ import { AuthModule } from './auth/auth.module'; import { ConfigModule } from '@nestjs/config'; import config from './config'; import { EmailService } from './util/email.service'; - +import { ErrorMessageService } from 'src/error-message/error-message.service'; @Module({ - providers: [CommonService, EmailService], - exports: [CommonService, HelperModule, AuthModule, EmailService], + providers: [CommonService, EmailService, ErrorMessageService], + exports: [ + CommonService, + HelperModule, + AuthModule, + EmailService, + ErrorMessageService, + ], imports: [ ConfigModule.forRoot({ load: config, diff --git a/src/common/filters/http-exception/http-exception.filter.spec.ts b/src/common/filters/http-exception/http-exception.filter.spec.ts new file mode 100644 index 0000000..8f016dd --- /dev/null +++ b/src/common/filters/http-exception/http-exception.filter.spec.ts @@ -0,0 +1,7 @@ +import { HttpExceptionFilter } from './http-exception.filter'; + +describe('HttpExceptionFilter', () => { + it('should be defined', () => { + expect(new HttpExceptionFilter()).toBeDefined(); + }); +}); diff --git a/src/common/filters/http-exception/http-exception.filter.ts b/src/common/filters/http-exception/http-exception.filter.ts new file mode 100644 index 0000000..c587769 --- /dev/null +++ b/src/common/filters/http-exception/http-exception.filter.ts @@ -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(); + const request = ctx.getRequest(); + 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); + } +} diff --git a/src/error-message/error-message.service.spec.ts b/src/error-message/error-message.service.spec.ts new file mode 100644 index 0000000..ae9c353 --- /dev/null +++ b/src/error-message/error-message.service.spec.ts @@ -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); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/error-message/error-message.service.ts b/src/error-message/error-message.service.ts new file mode 100644 index 0000000..83f7497 --- /dev/null +++ b/src/error-message/error-message.service.ts @@ -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 { + 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; + } +} diff --git a/src/main.ts b/src/main.ts index 894ecd1..6dbfc45 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,6 +6,7 @@ import { setupSwaggerAuthentication } from '../libs/common/src/util/user-auth.sw import { ValidationPipe } from '@nestjs/common'; import { json, urlencoded } from 'body-parser'; import { SeederService } from '@app/common/seed/services/seeder.service'; +import { HttpExceptionFilter } from './common/filters/http-exception/http-exception.filter'; async function bootstrap() { const app = await NestFactory.create(AppModule); @@ -15,6 +16,7 @@ async function bootstrap() { // Set the body parser limit to 1 MB app.use(json({ limit: '1mb' })); app.use(urlencoded({ limit: '1mb', extended: true })); + app.useGlobalFilters(new HttpExceptionFilter()); app.use( rateLimit({ diff --git a/src/region/region.module.ts b/src/region/region.module.ts index c0da5ab..22eaa2d 100644 --- a/src/region/region.module.ts +++ b/src/region/region.module.ts @@ -3,9 +3,10 @@ import { RegionService } from './services/region.service'; import { RegionController } from './controllers/region.controller'; import { ConfigModule } from '@nestjs/config'; import { RegionRepository } from '@app/common/modules/region/repositories'; +import { CommonModule } from '@app/common'; @Module({ - imports: [ConfigModule], + imports: [ConfigModule, CommonModule], controllers: [RegionController], providers: [RegionService, RegionRepository], exports: [RegionService], diff --git a/src/region/services/region.service.ts b/src/region/services/region.service.ts index 580f285..9061e0a 100644 --- a/src/region/services/region.service.ts +++ b/src/region/services/region.service.ts @@ -2,23 +2,33 @@ import { BadRequestException, HttpException, HttpStatus, + Inject, Injectable, } from '@nestjs/common'; import { RegionRepository } from '@app/common/modules/region/repositories'; +import { ErrorMessageService } from 'src/error-message/error-message.service'; @Injectable() export class RegionService { - constructor(private readonly regionRepository: RegionRepository) {} + constructor( + private readonly regionRepository: RegionRepository, + @Inject(ErrorMessageService) + private readonly errorMessageService: ErrorMessageService, + ) {} async getAllRegions() { try { const regions = await this.regionRepository.find(); - return regions; } catch (err) { if (err instanceof BadRequestException) { throw err; // Re-throw BadRequestException } else { - throw new HttpException('Regions found', HttpStatus.NOT_FOUND); + throw new HttpException( + this.errorMessageService.getMessage('NOT_FOUND', { + entity: 'Regions', + }), + HttpStatus.NOT_FOUND, + ); } } } From b16f6ceaa78c29deafa0fe6a324de380d55688f3 Mon Sep 17 00:00:00 2001 From: faris Aljohari <83524184+farisaljohari@users.noreply.github.com> Date: Sun, 6 Oct 2024 14:14:22 -0500 Subject: [PATCH 05/12] finish add garage door --- libs/common/src/constants/product-type.enum.ts | 1 + src/schedule/services/schedule.service.ts | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/libs/common/src/constants/product-type.enum.ts b/libs/common/src/constants/product-type.enum.ts index 7ef741c..4f72a25 100644 --- a/libs/common/src/constants/product-type.enum.ts +++ b/libs/common/src/constants/product-type.enum.ts @@ -13,4 +13,5 @@ export enum ProductType { TWO_2TG = '2GT', ONE_1TG = '1GT', WL = 'WL', + GD = 'GD', } diff --git a/src/schedule/services/schedule.service.ts b/src/schedule/services/schedule.service.ts index d2bb1f5..6af6a76 100644 --- a/src/schedule/services/schedule.service.ts +++ b/src/schedule/services/schedule.service.ts @@ -56,7 +56,8 @@ export class ScheduleService { 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.THREE_3TG && + deviceDetails.productDevice.prodType !== ProductType.GD ) { throw new HttpException( 'This device is not supported for schedule', @@ -113,7 +114,8 @@ export class ScheduleService { 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.THREE_3TG && + deviceDetails.productDevice.prodType !== ProductType.GD ) { throw new HttpException( 'This device is not supported for schedule', @@ -166,7 +168,8 @@ export class ScheduleService { 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.THREE_3TG && + deviceDetails.productDevice.prodType !== ProductType.GD ) { throw new HttpException( 'This device is not supported for schedule', @@ -233,7 +236,8 @@ export class ScheduleService { 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.THREE_3TG && + deviceDetails.productDevice.prodType !== ProductType.GD ) { throw new HttpException( 'This device is not supported for schedule', @@ -317,7 +321,8 @@ export class ScheduleService { 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.THREE_3TG && + deviceDetails.productDevice.prodType !== ProductType.GD ) { throw new HttpException( 'This device is not supported for schedule', From b3b83f838c4b17e38be94fb0bbf1d50be68cfac0 Mon Sep 17 00:00:00 2001 From: faris Aljohari <83524184+farisaljohari@users.noreply.github.com> Date: Mon, 7 Oct 2024 14:58:50 -0500 Subject: [PATCH 06/12] fix gateway issue --- src/device/services/device.service.ts | 30 ++++++++++++++++----------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/device/services/device.service.ts b/src/device/services/device.service.ts index 1020614..e45152b 100644 --- a/src/device/services/device.service.ts +++ b/src/device/services/device.service.ts @@ -667,19 +667,25 @@ export class DeviceService { const devices = await Promise.all( response.map(async (device: any) => { - const deviceDetails = await this.getDeviceByDeviceTuyaUuid(device.id); - if (deviceDetails.deviceTuyaUuid) { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { id, ...rest } = device; - return { - ...rest, - tuyaUuid: deviceDetails.deviceTuyaUuid, - uuid: deviceDetails.uuid, - productUuid: deviceDetails.productDevice.uuid, - productType: deviceDetails.productDevice.prodType, - }; + try { + const deviceDetails = await this.getDeviceByDeviceTuyaUuid( + device.id, + ); + if (deviceDetails.deviceTuyaUuid) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { id, ...rest } = device; + return { + ...rest, + tuyaUuid: deviceDetails.deviceTuyaUuid, + uuid: deviceDetails.uuid, + productUuid: deviceDetails.productDevice.uuid, + productType: deviceDetails.productDevice.prodType, + }; + } + return null; + } catch (error) { + return null; } - return null; }), ); From 69d2aece43241417be4aed0104560abbc6072646 Mon Sep 17 00:00:00 2001 From: faris Aljohari <83524184+farisaljohari@users.noreply.github.com> Date: Mon, 7 Oct 2024 18:28:06 -0500 Subject: [PATCH 07/12] remove unused imports --- libs/common/src/auth/services/auth.service.ts | 1 - src/auth/services/user-auth.service.ts | 2 -- src/community/controllers/community.controller.ts | 2 -- 3 files changed, 5 deletions(-) diff --git a/libs/common/src/auth/services/auth.service.ts b/libs/common/src/auth/services/auth.service.ts index 86bb826..5792eb0 100644 --- a/libs/common/src/auth/services/auth.service.ts +++ b/libs/common/src/auth/services/auth.service.ts @@ -10,7 +10,6 @@ import { UserRepository } from '../../../../common/src/modules/user/repositories import { UserSessionRepository } from '../../../../common/src/modules/session/repositories/session.repository'; import { UserSessionEntity } from '../../../../common/src/modules/session/entities'; import { ConfigService } from '@nestjs/config'; -import axios from 'axios'; import { OAuth2Client } from 'google-auth-library'; @Injectable() diff --git a/src/auth/services/user-auth.service.ts b/src/auth/services/user-auth.service.ts index 7191e3b..c924658 100644 --- a/src/auth/services/user-auth.service.ts +++ b/src/auth/services/user-auth.service.ts @@ -3,7 +3,6 @@ import { BadRequestException, ForbiddenException, Injectable, - UnauthorizedException, } from '@nestjs/common'; import { UserSignUpDto } from '../dtos/user-auth.dto'; import { HelperHashService } from '../../../libs/common/src/helper/services'; @@ -19,7 +18,6 @@ import * as argon2 from 'argon2'; import { differenceInSeconds } from '@app/common/helper/differenceInSeconds'; import { LessThan, MoreThan } from 'typeorm'; import { ConfigService } from '@nestjs/config'; -import { UUID } from 'typeorm/driver/mongodb/bson.typings'; @Injectable() export class UserAuthService { diff --git a/src/community/controllers/community.controller.ts b/src/community/controllers/community.controller.ts index af8d137..3c9a313 100644 --- a/src/community/controllers/community.controller.ts +++ b/src/community/controllers/community.controller.ts @@ -18,10 +18,8 @@ import { } from '../dtos/add.community.dto'; import { GetCommunityChildDto } from '../dtos/get.community.dto'; import { UpdateCommunityNameDto } from '../dtos/update.community.dto'; -// import { CheckUserCommunityGuard } from 'src/guards/user.community.guard'; import { AdminRoleGuard } from 'src/guards/admin.role.guard'; import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard'; -// import { CommunityPermissionGuard } from 'src/guards/community.permission.guard'; @ApiTags('Community Module') @Controller({ From f5dcdc0ed526f0b3d12f70130fb50951b7cc0441 Mon Sep 17 00:00:00 2001 From: faris Aljohari <83524184+farisaljohari@users.noreply.github.com> Date: Mon, 7 Oct 2024 22:41:31 -0500 Subject: [PATCH 08/12] add filter to get groups api --- .../common/src/constants/product-type.enum.ts | 1 + src/group/services/group.service.ts | 21 +++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/libs/common/src/constants/product-type.enum.ts b/libs/common/src/constants/product-type.enum.ts index 4f72a25..6442f87 100644 --- a/libs/common/src/constants/product-type.enum.ts +++ b/libs/common/src/constants/product-type.enum.ts @@ -14,4 +14,5 @@ export enum ProductType { ONE_1TG = '1GT', WL = 'WL', GD = 'GD', + CUR = 'CUR', } diff --git a/src/group/services/group.service.ts b/src/group/services/group.service.ts index 4f1a1f7..f549afc 100644 --- a/src/group/services/group.service.ts +++ b/src/group/services/group.service.ts @@ -7,6 +7,7 @@ import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter'; import { ProductRepository } from '@app/common/modules/product/repositories'; import { PermissionType } from '@app/common/constants/permission-type.enum'; import { In } from 'typeorm'; +import { ProductType } from '@app/common/constants/product-type.enum'; @Injectable() export class GroupService { @@ -44,8 +45,24 @@ export class GroupService { }); const uniqueGroupNames = [...new Set(groupNames)]; - - return uniqueGroupNames.map((groupName) => ({ groupName })); + const groups = uniqueGroupNames.map((groupName) => ({ + groupName: groupName as ProductType, + })); + const allowedProductTypes = [ + ProductType.ONE_1TG, + ProductType.TWO_2TG, + ProductType.THREE_3TG, + ProductType.THREE_G, + ProductType.TWO_G, + ProductType.ONE_G, + ProductType.GD, + ProductType.WH, + ProductType.AC, + ProductType.CUR, + ]; + return groups.filter((group) => + allowedProductTypes.includes(group.groupName), + ); } catch (error) { throw new HttpException( 'This unit does not have any groups', From 6bfb64370a665e9583179a5b600c2c237de45124 Mon Sep 17 00:00:00 2001 From: faris Aljohari <83524184+farisaljohari@users.noreply.github.com> Date: Mon, 7 Oct 2024 23:11:16 -0500 Subject: [PATCH 09/12] finished soft delete devices --- .../services/devices-status.service.ts | 2 ++ .../modules/device/entities/device.entity.ts | 3 ++- src/device/services/device.service.ts | 19 +++++++++++++++++-- src/door-lock/services/door.lock.service.ts | 1 + src/guards/device.product.guard.ts | 4 ++-- src/guards/room.guard.ts | 1 + ...er.device.controllable.permission.guard.ts | 6 +++++- src/guards/user.device.permission.guard.ts | 6 +++++- src/schedule/services/schedule.service.ts | 1 + .../services/visitor-password.service.ts | 3 +++ 10 files changed, 39 insertions(+), 7 deletions(-) diff --git a/libs/common/src/firebase/devices-status/services/devices-status.service.ts b/libs/common/src/firebase/devices-status/services/devices-status.service.ts index 267d6b6..f075f34 100644 --- a/libs/common/src/firebase/devices-status/services/devices-status.service.ts +++ b/libs/common/src/firebase/devices-status/services/devices-status.service.ts @@ -85,6 +85,7 @@ export class DeviceStatusFirebaseService { return await this.deviceRepository.findOne({ where: { deviceTuyaUuid, + isActive: true, }, relations: ['productDevice'], }); @@ -139,6 +140,7 @@ export class DeviceStatusFirebaseService { return await this.deviceRepository.findOne({ where: { uuid: deviceUuid, + isActive: true, }, ...(withProductDevice && { relations: ['productDevice'] }), }); diff --git a/libs/common/src/modules/device/entities/device.entity.ts b/libs/common/src/modules/device/entities/device.entity.ts index c02f8a1..5a96255 100644 --- a/libs/common/src/modules/device/entities/device.entity.ts +++ b/libs/common/src/modules/device/entities/device.entity.ts @@ -18,8 +18,9 @@ export class DeviceEntity extends AbstractEntity { @Column({ nullable: true, default: true, + type: 'boolean', }) - isActive: true; + isActive: boolean; @ManyToOne(() => UserEntity, (user) => user.userSpaces, { nullable: false }) user: UserEntity; diff --git a/src/device/services/device.service.ts b/src/device/services/device.service.ts index e45152b..68e11b5 100644 --- a/src/device/services/device.service.ts +++ b/src/device/services/device.service.ts @@ -62,6 +62,7 @@ export class DeviceService { return await this.deviceRepository.findOne({ where: { uuid: deviceUuid, + isActive: true, }, ...(withProductDevice && { relations: ['productDevice'] }), }); @@ -70,6 +71,7 @@ export class DeviceService { return await this.deviceRepository.findOne({ where: { deviceTuyaUuid, + isActive: true, }, relations: ['productDevice'], }); @@ -126,6 +128,7 @@ export class DeviceService { const devices = await this.deviceRepository.find({ where: { user: { uuid: userUuid }, + isActive: true, permission: { userUuid, permissionType: { @@ -172,6 +175,7 @@ export class DeviceService { const devices = await this.deviceRepository.find({ where: { spaceDevice: { uuid: getDeviceByRoomUuidDto.roomUuid }, + isActive: true, permission: { userUuid, permissionType: { @@ -221,6 +225,7 @@ export class DeviceService { const device = await this.deviceRepository.findOne({ where: { uuid: updateDeviceInRoomDto.deviceUuid, + isActive: true, }, relations: ['spaceDevice', 'spaceDevice.parent'], }); @@ -407,7 +412,7 @@ export class DeviceService { } async checkAllDevicesHaveSameProductUuid(deviceUuids: string[]) { const firstDevice = await this.deviceRepository.findOne({ - where: { uuid: deviceUuids[0] }, + where: { uuid: deviceUuids[0], isActive: true }, relations: ['productDevice'], }); @@ -419,7 +424,7 @@ export class DeviceService { for (let i = 1; i < deviceUuids.length; i++) { const device = await this.deviceRepository.findOne({ - where: { uuid: deviceUuids[i] }, + where: { uuid: deviceUuids[i], isActive: true }, relations: ['productDevice'], }); @@ -463,6 +468,11 @@ export class DeviceService { 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 }); @@ -643,6 +653,7 @@ export class DeviceService { const device = await this.deviceRepository.findOne({ where: { uuid: deviceUuid, + isActive: true, permission: { userUuid: userUuid, }, @@ -774,6 +785,9 @@ export class DeviceService { parent: { uuid: unitUuid, }, + devicesSpaceEntity: { + isActive: true, + }, }, relations: ['devicesSpaceEntity', 'devicesSpaceEntity.productDevice'], }); @@ -808,6 +822,7 @@ export class DeviceService { async getAllDevices(): Promise { try { const devices = await this.deviceRepository.find({ + where: { isActive: true }, relations: [ 'spaceDevice.parent', 'productDevice', diff --git a/src/door-lock/services/door.lock.service.ts b/src/door-lock/services/door.lock.service.ts index 5864c5d..4007cea 100644 --- a/src/door-lock/services/door.lock.service.ts +++ b/src/door-lock/services/door.lock.service.ts @@ -826,6 +826,7 @@ export class DoorLockService { return await this.deviceRepository.findOne({ where: { uuid: deviceUuid, + isActive: true, }, ...(withProductDevice && { relations: ['productDevice'] }), }); diff --git a/src/guards/device.product.guard.ts b/src/guards/device.product.guard.ts index 108307a..6bf84cc 100644 --- a/src/guards/device.product.guard.ts +++ b/src/guards/device.product.guard.ts @@ -28,7 +28,7 @@ export class CheckProductUuidForAllDevicesGuard implements CanActivate { async checkAllDevicesHaveSameProductUuid(deviceUuids: string[]) { const firstDevice = await this.deviceRepository.findOne({ - where: { uuid: deviceUuids[0] }, + where: { uuid: deviceUuids[0], isActive: true }, relations: ['productDevice'], }); @@ -40,7 +40,7 @@ export class CheckProductUuidForAllDevicesGuard implements CanActivate { for (let i = 1; i < deviceUuids.length; i++) { const device = await this.deviceRepository.findOne({ - where: { uuid: deviceUuids[i] }, + where: { uuid: deviceUuids[i], isActive: true }, relations: ['productDevice'], }); diff --git a/src/guards/room.guard.ts b/src/guards/room.guard.ts index c5ed514..97fb992 100644 --- a/src/guards/room.guard.ts +++ b/src/guards/room.guard.ts @@ -55,6 +55,7 @@ export class CheckRoomGuard implements CanActivate { const response = await this.deviceRepository.findOne({ where: { uuid: deviceUuid, + isActive: true, }, }); diff --git a/src/guards/user.device.controllable.permission.guard.ts b/src/guards/user.device.controllable.permission.guard.ts index 2684c8d..3736368 100644 --- a/src/guards/user.device.controllable.permission.guard.ts +++ b/src/guards/user.device.controllable.permission.guard.ts @@ -58,7 +58,11 @@ export class CheckUserHaveControllablePermission implements CanActivate { deviceUuid: string, ): Promise { const device = await this.deviceRepository.findOne({ - where: { uuid: deviceUuid, permission: { userUuid: userUuid } }, + where: { + uuid: deviceUuid, + isActive: true, + permission: { userUuid: userUuid }, + }, relations: ['permission', 'permission.permissionType'], }); diff --git a/src/guards/user.device.permission.guard.ts b/src/guards/user.device.permission.guard.ts index e63a08e..adf78e4 100644 --- a/src/guards/user.device.permission.guard.ts +++ b/src/guards/user.device.permission.guard.ts @@ -59,7 +59,11 @@ export class CheckUserHavePermission implements CanActivate { deviceUuid: string, ): Promise { const device = await this.deviceRepository.findOne({ - where: { uuid: deviceUuid, permission: { userUuid: userUuid } }, + where: { + uuid: deviceUuid, + permission: { userUuid: userUuid }, + isActive: true, + }, relations: ['permission', 'permission.permissionType'], }); diff --git a/src/schedule/services/schedule.service.ts b/src/schedule/services/schedule.service.ts index 6af6a76..ee029cf 100644 --- a/src/schedule/services/schedule.service.ts +++ b/src/schedule/services/schedule.service.ts @@ -298,6 +298,7 @@ export class ScheduleService { return await this.deviceRepository.findOne({ where: { uuid: deviceUuid, + isActive: true, }, ...(withProductDevice && { relations: ['productDevice'] }), }); diff --git a/src/vistor-password/services/visitor-password.service.ts b/src/vistor-password/services/visitor-password.service.ts index f15b8e4..f03d370 100644 --- a/src/vistor-password/services/visitor-password.service.ts +++ b/src/vistor-password/services/visitor-password.service.ts @@ -440,6 +440,7 @@ export class VisitorPasswordService { productDevice: { prodType: ProductType.DL, }, + isActive: true, }, }); const data = []; @@ -482,6 +483,7 @@ export class VisitorPasswordService { productDevice: { prodType: ProductType.DL, }, + isActive: true, }, relations: ['productDevice'], }); @@ -823,6 +825,7 @@ export class VisitorPasswordService { return await this.deviceRepository.findOne({ where: { uuid: deviceUuid, + isActive: true, }, ...(withProductDevice && { relations: ['productDevice'] }), }); From bd3945f2ee944865ff38903d0305e8a674377c96 Mon Sep 17 00:00:00 2001 From: faris Aljohari <83524184+farisaljohari@users.noreply.github.com> Date: Tue, 8 Oct 2024 01:09:21 -0500 Subject: [PATCH 10/12] remove tuya auth --- src/app.module.ts | 2 - src/auth/auth.module.ts | 7 +- .../controllers/authentication.controller.ts | 16 --- src/auth/controllers/index.ts | 1 - src/auth/services/authentication.service.ts | 120 ------------------ src/auth/services/index.ts | 1 - 6 files changed, 2 insertions(+), 145 deletions(-) delete mode 100644 src/auth/controllers/authentication.controller.ts delete mode 100644 src/auth/services/authentication.service.ts diff --git a/src/app.module.ts b/src/app.module.ts index 29d07ac..5c3a52c 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -2,7 +2,6 @@ import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import config from './config'; import { AuthenticationModule } from './auth/auth.module'; -import { AuthenticationController } from './auth/controllers/authentication.controller'; import { UserModule } from './users/user.module'; import { RoomModule } from './room/room.module'; import { GroupModule } from './group/group.module'; @@ -53,7 +52,6 @@ import { ScheduleModule } from './schedule/schedule.module'; VisitorPasswordModule, ScheduleModule, ], - controllers: [AuthenticationController], providers: [ { provide: APP_INTERCEPTOR, diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts index 012312d..66d335d 100644 --- a/src/auth/auth.module.ts +++ b/src/auth/auth.module.ts @@ -1,6 +1,4 @@ import { Module } from '@nestjs/common'; -import { AuthenticationController } from './controllers/authentication.controller'; -import { AuthenticationService } from './services/authentication.service'; import { ConfigModule } from '@nestjs/config'; import { UserRepositoryModule } from '@app/common/modules/user/user.repository.module'; import { CommonModule } from '../../libs/common/src'; @@ -16,9 +14,8 @@ import { RoleTypeRepository } from '@app/common/modules/role-type/repositories'; @Module({ imports: [ConfigModule, UserRepositoryModule, CommonModule], - controllers: [AuthenticationController, UserAuthController], + controllers: [UserAuthController], providers: [ - AuthenticationService, UserAuthService, UserRepository, UserSessionRepository, @@ -26,6 +23,6 @@ import { RoleTypeRepository } from '@app/common/modules/role-type/repositories'; UserRoleRepository, RoleTypeRepository, ], - exports: [AuthenticationService, UserAuthService], + exports: [UserAuthService], }) export class AuthenticationModule {} diff --git a/src/auth/controllers/authentication.controller.ts b/src/auth/controllers/authentication.controller.ts deleted file mode 100644 index ace6525..0000000 --- a/src/auth/controllers/authentication.controller.ts +++ /dev/null @@ -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(); - } -} diff --git a/src/auth/controllers/index.ts b/src/auth/controllers/index.ts index 2ce466d..f63ac56 100644 --- a/src/auth/controllers/index.ts +++ b/src/auth/controllers/index.ts @@ -1,2 +1 @@ -export * from './authentication.controller'; export * from './user-auth.controller'; diff --git a/src/auth/services/authentication.service.ts b/src/auth/services/authentication.service.ts deleted file mode 100644 index 1d5d580..0000000 --- a/src/auth/services/authentication.service.ts +++ /dev/null @@ -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('auth-config.DEVICE_ID')), - (this.accessKey = this.configService.get( - 'auth-config.ACCESS_KEY', - )), - (this.secretKey = this.configService.get( - '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 { - 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, - }; - } -} diff --git a/src/auth/services/index.ts b/src/auth/services/index.ts index ac532d6..aa322a1 100644 --- a/src/auth/services/index.ts +++ b/src/auth/services/index.ts @@ -1,2 +1 @@ -export * from './authentication.service'; export * from './user-auth.service'; From 898791ae93b10e111572a65281114e0a07b1e521 Mon Sep 17 00:00:00 2001 From: faris Aljohari <83524184+farisaljohari@users.noreply.github.com> Date: Tue, 8 Oct 2024 01:13:00 -0500 Subject: [PATCH 11/12] remove rename from apis url --- src/building/controllers/building.controller.ts | 2 +- src/community/controllers/community.controller.ts | 2 +- src/floor/controllers/floor.controller.ts | 2 +- src/room/controllers/room.controller.ts | 2 +- src/unit/controllers/unit.controller.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/building/controllers/building.controller.ts b/src/building/controllers/building.controller.ts index a76d620..ad61cb3 100644 --- a/src/building/controllers/building.controller.ts +++ b/src/building/controllers/building.controller.ts @@ -134,7 +134,7 @@ export class BuildingController { @ApiBearerAuth() @UseGuards(JwtAuthGuard, BuildingPermissionGuard) - @Put('rename/:buildingUuid') + @Put(':buildingUuid') async renameBuildingByUuid( @Param('buildingUuid') buildingUuid: string, @Body() updateBuildingDto: UpdateBuildingNameDto, diff --git a/src/community/controllers/community.controller.ts b/src/community/controllers/community.controller.ts index 3c9a313..adc38b7 100644 --- a/src/community/controllers/community.controller.ts +++ b/src/community/controllers/community.controller.ts @@ -133,7 +133,7 @@ export class CommunityController { } @ApiBearerAuth() @UseGuards(JwtAuthGuard) - @Put('rename/:communityUuid') + @Put(':communityUuid') async renameCommunityByUuid( @Param('communityUuid') communityUuid: string, @Body() updateCommunityDto: UpdateCommunityNameDto, diff --git a/src/floor/controllers/floor.controller.ts b/src/floor/controllers/floor.controller.ts index b4940fe..be7d921 100644 --- a/src/floor/controllers/floor.controller.ts +++ b/src/floor/controllers/floor.controller.ts @@ -134,7 +134,7 @@ export class FloorController { @ApiBearerAuth() @UseGuards(JwtAuthGuard, FloorPermissionGuard) - @Put('rename/:floorUuid') + @Put(':floorUuid') async renameFloorByUuid( @Param('floorUuid') floorUuid: string, @Body() updateFloorNameDto: UpdateFloorNameDto, diff --git a/src/room/controllers/room.controller.ts b/src/room/controllers/room.controller.ts index 0a92e57..8564b0e 100644 --- a/src/room/controllers/room.controller.ts +++ b/src/room/controllers/room.controller.ts @@ -110,7 +110,7 @@ export class RoomController { @ApiBearerAuth() @UseGuards(JwtAuthGuard, RoomPermissionGuard) - @Put('rename/:roomUuid') + @Put(':roomUuid') async renameRoomByUuid( @Param('roomUuid') roomUuid: string, @Body() updateRoomNameDto: UpdateRoomNameDto, diff --git a/src/unit/controllers/unit.controller.ts b/src/unit/controllers/unit.controller.ts index 1d5cbd3..9f3e50b 100644 --- a/src/unit/controllers/unit.controller.ts +++ b/src/unit/controllers/unit.controller.ts @@ -132,7 +132,7 @@ export class UnitController { @ApiBearerAuth() @UseGuards(JwtAuthGuard, UnitPermissionGuard) - @Put('rename/:unitUuid') + @Put(':unitUuid') async renameUnitByUuid( @Param('unitUuid') unitUuid: string, @Body() updateUnitNameDto: UpdateUnitNameDto, From 88f35585898249432bb48ba0e4e95514b110a831 Mon Sep 17 00:00:00 2001 From: faris Aljohari <83524184+farisaljohari@users.noreply.github.com> Date: Tue, 8 Oct 2024 01:17:31 -0500 Subject: [PATCH 12/12] enhance the urls name --- src/auth/controllers/user-auth.controller.ts | 2 +- .../controllers/user-device-permission.controller.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/auth/controllers/user-auth.controller.ts b/src/auth/controllers/user-auth.controller.ts index 1eee19e..b83a016 100644 --- a/src/auth/controllers/user-auth.controller.ts +++ b/src/auth/controllers/user-auth.controller.ts @@ -83,7 +83,7 @@ export class UserAuthController { @ApiBearerAuth() @UseGuards(SuperAdminRoleGuard) - @Get('user/list') + @Get('user') async userList() { const userList = await this.userAuthService.userList(); return { diff --git a/src/user-device-permission/controllers/user-device-permission.controller.ts b/src/user-device-permission/controllers/user-device-permission.controller.ts index 2f68708..d54637e 100644 --- a/src/user-device-permission/controllers/user-device-permission.controller.ts +++ b/src/user-device-permission/controllers/user-device-permission.controller.ts @@ -28,7 +28,7 @@ export class UserDevicePermissionController { @ApiBearerAuth() @UseGuards(AdminRoleGuard) - @Post('add') + @Post() async addDevicePermission( @Body() userDevicePermissionDto: UserDevicePermissionAddDto, ) { @@ -52,7 +52,7 @@ export class UserDevicePermissionController { @ApiBearerAuth() @UseGuards(AdminRoleGuard) - @Put('edit/:devicePermissionUuid') + @Put(':devicePermissionUuid') async editDevicePermission( @Param('devicePermissionUuid') devicePermissionUuid: string, @Body() userDevicePermissionEditDto: UserDevicePermissionEditDto, @@ -76,7 +76,7 @@ export class UserDevicePermissionController { @ApiBearerAuth() @UseGuards(AdminRoleGuard) - @Get(':deviceUuid/list') + @Get(':deviceUuid') async fetchDevicePermission(@Param('deviceUuid') deviceUuid: string) { try { const deviceDetails =