mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-11-26 07:34:54 +00:00
convert project from microservices to rest apis
This commit is contained in:
17
src/app.module.ts
Normal file
17
src/app.module.ts
Normal file
@ -0,0 +1,17 @@
|
||||
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';
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
load: config,
|
||||
}),
|
||||
AuthenticationModule,
|
||||
UserModule,
|
||||
],
|
||||
controllers: [AuthenticationController],
|
||||
})
|
||||
export class AuthModule {}
|
||||
25
src/auth/auth.module.ts
Normal file
25
src/auth/auth.module.ts
Normal file
@ -0,0 +1,25 @@
|
||||
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 '../../libs/common/src/modules/user/user.repository.module';
|
||||
import { CommonModule } from '../../libs/common/src';
|
||||
import { UserAuthController } from './controllers';
|
||||
import { UserAuthService } from './services';
|
||||
import { UserRepository } from '../../libs/common/src/modules/user/repositories';
|
||||
import { UserSessionRepository } from '../../libs/common/src/modules/session/repositories/session.repository';
|
||||
import { UserOtpRepository } from '../../libs/common/src/modules/user-otp/repositories/user-otp.repository';
|
||||
|
||||
@Module({
|
||||
imports: [ConfigModule, UserRepositoryModule, CommonModule],
|
||||
controllers: [AuthenticationController, UserAuthController],
|
||||
providers: [
|
||||
AuthenticationService,
|
||||
UserAuthService,
|
||||
UserRepository,
|
||||
UserSessionRepository,
|
||||
UserOtpRepository,
|
||||
],
|
||||
exports: [AuthenticationService, UserAuthService],
|
||||
})
|
||||
export class AuthenticationModule {}
|
||||
3
src/auth/constants/login.response.constant.ts
Normal file
3
src/auth/constants/login.response.constant.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export interface ILoginResponse {
|
||||
access_token: string;
|
||||
}
|
||||
16
src/auth/controllers/authentication.controller.ts
Normal file
16
src/auth/controllers/authentication.controller.ts
Normal file
@ -0,0 +1,16 @@
|
||||
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('auth')
|
||||
async Authentication() {
|
||||
return await this.authenticationService.main();
|
||||
}
|
||||
}
|
||||
2
src/auth/controllers/index.ts
Normal file
2
src/auth/controllers/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './authentication.controller';
|
||||
export * from './user-auth.controller';
|
||||
96
src/auth/controllers/user-auth.controller.ts
Normal file
96
src/auth/controllers/user-auth.controller.ts
Normal file
@ -0,0 +1,96 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Post,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { UserAuthService } from '../services/user-auth.service';
|
||||
import { UserSignUpDto } from '../dtos/user-auth.dto';
|
||||
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
||||
import { ResponseMessage } from '../../../libs/common/src/response/response.decorator';
|
||||
import { UserLoginDto } from '../dtos/user-login.dto';
|
||||
import { JwtAuthGuard } from '../../../libs/common/src/guards/jwt.auth.guard';
|
||||
import { ForgetPasswordDto, UserOtpDto, VerifyOtpDto } from '../dtos';
|
||||
|
||||
@Controller({
|
||||
version: '1',
|
||||
path: 'authentication',
|
||||
})
|
||||
@ApiTags('Auth')
|
||||
export class UserAuthController {
|
||||
constructor(private readonly userAuthService: UserAuthService) {}
|
||||
|
||||
@ResponseMessage('User Registered Successfully')
|
||||
@Post('user/signup')
|
||||
async signUp(@Body() userSignUpDto: UserSignUpDto) {
|
||||
const signupUser = await this.userAuthService.signUp(userSignUpDto);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
data: {
|
||||
id: signupUser.uuid,
|
||||
default: () => 'gen_random_uuid()', // this is a default value for the uuid column
|
||||
},
|
||||
message: 'User Registered Successfully',
|
||||
};
|
||||
}
|
||||
|
||||
@ResponseMessage('user logged in successfully')
|
||||
@Post('user/login')
|
||||
async userLogin(@Body() data: UserLoginDto) {
|
||||
const accessToken = await this.userAuthService.userLogin(data);
|
||||
return {
|
||||
statusCode: HttpStatus.CREATED,
|
||||
data: accessToken,
|
||||
message: 'User Loggedin Successfully',
|
||||
};
|
||||
}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Delete('user/delete/:id')
|
||||
async userDelete(@Param('id') id: string) {
|
||||
await this.userAuthService.deleteUser(id);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
data: {
|
||||
id,
|
||||
},
|
||||
message: 'User Deleted Successfully',
|
||||
};
|
||||
}
|
||||
|
||||
@Post('user/send-otp')
|
||||
async sendOtp(@Body() otpDto: UserOtpDto) {
|
||||
const otpCode = await this.userAuthService.generateOTP(otpDto);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
data: {
|
||||
otp: otpCode,
|
||||
},
|
||||
message: 'Otp Send Successfully',
|
||||
};
|
||||
}
|
||||
|
||||
@Post('user/verify-otp')
|
||||
async verifyOtp(@Body() verifyOtpDto: VerifyOtpDto) {
|
||||
await this.userAuthService.verifyOTP(verifyOtpDto);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
data: {},
|
||||
message: 'Otp Verified Successfully',
|
||||
};
|
||||
}
|
||||
|
||||
@Post('user/forget-password')
|
||||
async forgetPassword(@Body() forgetPasswordDto: ForgetPasswordDto) {
|
||||
await this.userAuthService.forgetPassword(forgetPasswordDto);
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
data: {},
|
||||
message: 'Password changed successfully',
|
||||
};
|
||||
}
|
||||
}
|
||||
4
src/auth/dtos/index.ts
Normal file
4
src/auth/dtos/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './user-auth.dto';
|
||||
export * from './user-login.dto';
|
||||
export * from './user-otp.dto';
|
||||
export * from './user-password.dto';
|
||||
36
src/auth/dtos/user-auth.dto.ts
Normal file
36
src/auth/dtos/user-auth.dto.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsEmail, IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class UserSignUpDto {
|
||||
@ApiProperty({
|
||||
description: 'email',
|
||||
required: true,
|
||||
})
|
||||
@IsEmail()
|
||||
@IsNotEmpty()
|
||||
public email: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'password',
|
||||
required: true,
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public password: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'first name',
|
||||
required: true,
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public firstName: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'last name',
|
||||
required: true,
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public lastName: string;
|
||||
}
|
||||
14
src/auth/dtos/user-login.dto.ts
Normal file
14
src/auth/dtos/user-login.dto.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||
|
||||
export class UserLoginDto {
|
||||
@ApiProperty()
|
||||
@IsEmail()
|
||||
@IsNotEmpty()
|
||||
email: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
password: string;
|
||||
}
|
||||
22
src/auth/dtos/user-otp.dto.ts
Normal file
22
src/auth/dtos/user-otp.dto.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { OtpType } from '../../../libs/common/src/constants/otp-type.enum';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsEmail, IsEnum, IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class UserOtpDto {
|
||||
@ApiProperty()
|
||||
@IsEmail()
|
||||
@IsNotEmpty()
|
||||
email: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsEnum(OtpType)
|
||||
@IsNotEmpty()
|
||||
type: OtpType;
|
||||
}
|
||||
|
||||
export class VerifyOtpDto extends UserOtpDto {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
otpCode: string;
|
||||
}
|
||||
14
src/auth/dtos/user-password.dto.ts
Normal file
14
src/auth/dtos/user-password.dto.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsEmail, IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class ForgetPasswordDto {
|
||||
@ApiProperty()
|
||||
@IsEmail()
|
||||
@IsNotEmpty()
|
||||
email: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
password: string;
|
||||
}
|
||||
120
src/auth/services/authentication.service.ts
Normal file
120
src/auth/services/authentication.service.ts
Normal file
@ -0,0 +1,120 @@
|
||||
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,
|
||||
};
|
||||
}
|
||||
}
|
||||
2
src/auth/services/index.ts
Normal file
2
src/auth/services/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './authentication.service';
|
||||
export * from './user-auth.service';
|
||||
151
src/auth/services/user-auth.service.ts
Normal file
151
src/auth/services/user-auth.service.ts
Normal file
@ -0,0 +1,151 @@
|
||||
import { UserRepository } from '../../../libs/common/src/modules/user/repositories';
|
||||
import {
|
||||
BadRequestException,
|
||||
Injectable,
|
||||
UnauthorizedException,
|
||||
} from '@nestjs/common';
|
||||
import { UserSignUpDto } from '../dtos/user-auth.dto';
|
||||
import { HelperHashService } from '../../../libs/common/src/helper/services';
|
||||
import { UserLoginDto } from '../dtos/user-login.dto';
|
||||
import { AuthService } from '../../../libs/common/src/auth/services/auth.service';
|
||||
import { UserSessionRepository } from '../../../libs/common/src/modules/session/repositories/session.repository';
|
||||
import { UserOtpRepository } from '../../../libs/common/src/modules/user-otp/repositories/user-otp.repository';
|
||||
import { ForgetPasswordDto, UserOtpDto, VerifyOtpDto } from '../dtos';
|
||||
import { EmailService } from '../../../libs/common/src/util/email.service';
|
||||
import { OtpType } from '../../../libs/common/src/constants/otp-type.enum';
|
||||
import { UserEntity } from '../../../libs/common/src/modules/user/entities/user.entity';
|
||||
import { ILoginResponse } from '../constants/login.response.constant';
|
||||
|
||||
@Injectable()
|
||||
export class UserAuthService {
|
||||
constructor(
|
||||
private readonly userRepository: UserRepository,
|
||||
private readonly sessionRepository: UserSessionRepository,
|
||||
private readonly otpRepository: UserOtpRepository,
|
||||
private readonly helperHashService: HelperHashService,
|
||||
private readonly authService: AuthService,
|
||||
private readonly emailService: EmailService,
|
||||
) {}
|
||||
|
||||
async signUp(userSignUpDto: UserSignUpDto): Promise<UserEntity> {
|
||||
const findUser = await this.findUser(userSignUpDto.email);
|
||||
if (findUser) {
|
||||
throw new BadRequestException('User already registered with given email');
|
||||
}
|
||||
const salt = this.helperHashService.randomSalt(10);
|
||||
const password = this.helperHashService.bcrypt(
|
||||
userSignUpDto.password,
|
||||
salt,
|
||||
);
|
||||
return await this.userRepository.save({ ...userSignUpDto, password });
|
||||
}
|
||||
|
||||
async findUser(email: string) {
|
||||
return await this.userRepository.findOne({
|
||||
where: {
|
||||
email,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async forgetPassword(forgetPasswordDto: ForgetPasswordDto) {
|
||||
const findUser = await this.findUser(forgetPasswordDto.email);
|
||||
if (!findUser) {
|
||||
throw new BadRequestException('User not found');
|
||||
}
|
||||
const salt = this.helperHashService.randomSalt(10);
|
||||
const password = this.helperHashService.bcrypt(
|
||||
forgetPasswordDto.password,
|
||||
salt,
|
||||
);
|
||||
return await this.userRepository.update(
|
||||
{ uuid: findUser.uuid },
|
||||
{ password },
|
||||
);
|
||||
}
|
||||
|
||||
async userLogin(data: UserLoginDto): Promise<ILoginResponse> {
|
||||
const user = await this.authService.validateUser(data.email, data.password);
|
||||
if (!user) {
|
||||
throw new UnauthorizedException('Invalid login credentials.');
|
||||
}
|
||||
|
||||
const session = await Promise.all([
|
||||
await this.sessionRepository.update(
|
||||
{ userId: user.id },
|
||||
{
|
||||
isLoggedOut: true,
|
||||
},
|
||||
),
|
||||
await this.authService.createSession({
|
||||
userId: user.uuid,
|
||||
loginTime: new Date(),
|
||||
isLoggedOut: false,
|
||||
}),
|
||||
]);
|
||||
|
||||
return await this.authService.login({
|
||||
email: user.email,
|
||||
userId: user.id,
|
||||
uuid: user.uuid,
|
||||
sessionId: session[1].uuid,
|
||||
});
|
||||
}
|
||||
|
||||
async deleteUser(uuid: string) {
|
||||
const user = await this.findOneById(uuid);
|
||||
if (!user) {
|
||||
throw new BadRequestException('User does not found');
|
||||
}
|
||||
return await this.userRepository.delete({ uuid });
|
||||
}
|
||||
|
||||
async findOneById(id: string): Promise<UserEntity> {
|
||||
return await this.userRepository.findOne({ where: { uuid: id } });
|
||||
}
|
||||
|
||||
async generateOTP(data: UserOtpDto): Promise<string> {
|
||||
await this.otpRepository.delete({ email: data.email, type: data.type });
|
||||
const otpCode = Math.floor(100000 + Math.random() * 900000).toString();
|
||||
const expiryTime = new Date();
|
||||
expiryTime.setMinutes(expiryTime.getMinutes() + 1);
|
||||
await this.otpRepository.save({
|
||||
email: data.email,
|
||||
otpCode,
|
||||
expiryTime,
|
||||
type: data.type,
|
||||
});
|
||||
const subject = 'OTP send successfully';
|
||||
const message = `Your OTP code is ${otpCode}`;
|
||||
this.emailService.sendOTPEmail(data.email, subject, message);
|
||||
return otpCode;
|
||||
}
|
||||
|
||||
async verifyOTP(data: VerifyOtpDto): Promise<boolean> {
|
||||
const otp = await this.otpRepository.findOne({
|
||||
where: { email: data.email, type: data.type },
|
||||
});
|
||||
|
||||
if (!otp) {
|
||||
throw new BadRequestException('this email is not registered');
|
||||
}
|
||||
|
||||
if (otp.otpCode !== data.otpCode) {
|
||||
throw new BadRequestException('You entered wrong otp');
|
||||
}
|
||||
|
||||
if (otp.expiryTime < new Date()) {
|
||||
await this.otpRepository.delete(otp.id);
|
||||
throw new BadRequestException('OTP expired');
|
||||
}
|
||||
|
||||
if (data.type == OtpType.VERIFICATION) {
|
||||
await this.userRepository.update(
|
||||
{ email: data.email },
|
||||
{ isUserVerified: true },
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
9
src/config/app.config.ts
Normal file
9
src/config/app.config.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export default () => ({
|
||||
DB_HOST: process.env.AZURE_POSTGRESQL_HOST,
|
||||
DB_PORT: process.env.AZURE_POSTGRESQL_PORT,
|
||||
DB_USER: process.env.AZURE_POSTGRESQL_USER,
|
||||
DB_PASSWORD: process.env.AZURE_POSTGRESQL_PASSWORD,
|
||||
DB_NAME: process.env.AZURE_POSTGRESQL_DATABASE,
|
||||
DB_SYNC: process.env.AZURE_POSTGRESQL_SYNC,
|
||||
DB_SSL: process.env.AZURE_POSTGRESQL_SSL,
|
||||
});
|
||||
10
src/config/auth.config.ts
Normal file
10
src/config/auth.config.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs(
|
||||
'auth-config',
|
||||
(): Record<string, any> => ({
|
||||
DEVICE_ID: process.env.DEVICE_ID,
|
||||
ACCESS_KEY: process.env.ACCESS_KEY,
|
||||
SECRET_KEY: process.env.SECRET_KEY,
|
||||
}),
|
||||
);
|
||||
4
src/config/index.ts
Normal file
4
src/config/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import AuthConfig from './auth.config';
|
||||
import AppConfig from './app.config';
|
||||
|
||||
export default [AuthConfig, AppConfig];
|
||||
11
src/config/jwt.config.ts
Normal file
11
src/config/jwt.config.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs(
|
||||
'jwt',
|
||||
(): Record<string, any> => ({
|
||||
secret: process.env.JWT_SECRET,
|
||||
expire_time: process.env.JWT_EXPIRE_TIME,
|
||||
secret_refresh: process.env.JWT_SECRET_REFRESH,
|
||||
expire_refresh: process.env.JWT_EXPIRE_TIME_REFRESH,
|
||||
}),
|
||||
);
|
||||
39
src/main.ts
Normal file
39
src/main.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AuthModule } from './app.module';
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import helmet from 'helmet';
|
||||
import { setupSwaggerAuthentication } from '../libs/common/src/util/user-auth.swagger.utils';
|
||||
import { ValidationPipe } from '@nestjs/common';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AuthModule);
|
||||
|
||||
// Enable 'trust proxy' setting
|
||||
app.use((req, res, next) => {
|
||||
app.getHttpAdapter().getInstance().set('trust proxy', 1);
|
||||
next();
|
||||
});
|
||||
|
||||
app.enableCors();
|
||||
|
||||
app.use(
|
||||
rateLimit({
|
||||
windowMs: 5 * 60 * 1000,
|
||||
max: 500,
|
||||
}),
|
||||
);
|
||||
|
||||
app.use(
|
||||
helmet({
|
||||
contentSecurityPolicy: false,
|
||||
}),
|
||||
);
|
||||
|
||||
setupSwaggerAuthentication(app);
|
||||
|
||||
app.useGlobalPipes(new ValidationPipe());
|
||||
|
||||
await app.listen(4001);
|
||||
}
|
||||
console.log('Starting auth at port 4001...');
|
||||
bootstrap();
|
||||
1
src/users/controllers/index.ts
Normal file
1
src/users/controllers/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './user.controller';
|
||||
25
src/users/controllers/user.controller.ts
Normal file
25
src/users/controllers/user.controller.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { Controller, Get, Query, UseGuards } from '@nestjs/common';
|
||||
import { UserService } from '../services/user.service';
|
||||
import { UserListDto } from '../dtos/user.list.dto';
|
||||
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { JwtAuthGuard } from '../../../libs/common/src/guards/jwt.auth.guard';
|
||||
|
||||
@ApiTags('User Module')
|
||||
@Controller({
|
||||
version: '1',
|
||||
path: 'user',
|
||||
})
|
||||
export class UserController {
|
||||
constructor(private readonly userService: UserService) {}
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('list')
|
||||
async userList(@Query() userListDto: UserListDto) {
|
||||
try {
|
||||
return await this.userService.userDetails(userListDto);
|
||||
} catch (err) {
|
||||
throw new Error(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
1
src/users/dtos/index.ts
Normal file
1
src/users/dtos/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './user.list.dto';
|
||||
32
src/users/dtos/user.list.dto.ts
Normal file
32
src/users/dtos/user.list.dto.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import {
|
||||
IsNotEmpty,
|
||||
IsNumberString,
|
||||
IsOptional,
|
||||
IsString,
|
||||
} from 'class-validator';
|
||||
|
||||
export class UserListDto {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
schema: string;
|
||||
|
||||
@IsNumberString()
|
||||
@IsNotEmpty()
|
||||
page_no: number;
|
||||
|
||||
@IsNumberString()
|
||||
@IsNotEmpty()
|
||||
page_size: number;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
username: string;
|
||||
|
||||
@IsNumberString()
|
||||
@IsOptional()
|
||||
start_time: number;
|
||||
|
||||
@IsNumberString()
|
||||
@IsOptional()
|
||||
end_time: number;
|
||||
}
|
||||
1
src/users/services/index.ts
Normal file
1
src/users/services/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './user.service';
|
||||
28
src/users/services/user.service.ts
Normal file
28
src/users/services/user.service.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { TuyaContext } from '@tuya/tuya-connector-nodejs';
|
||||
import { UserListDto } from '../dtos/user.list.dto';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
@Injectable()
|
||||
export class UserService {
|
||||
private tuya: TuyaContext;
|
||||
constructor(private readonly configService: ConfigService) {
|
||||
const accessKey = this.configService.get<string>('auth-config.ACCESS_KEY');
|
||||
const secretKey = this.configService.get<string>('auth-config.SECRET_KEY');
|
||||
// const clientId = this.configService.get<string>('auth-config.CLIENT_ID');
|
||||
this.tuya = new TuyaContext({
|
||||
baseUrl: 'https://openapi.tuyaeu.com',
|
||||
accessKey,
|
||||
secretKey,
|
||||
});
|
||||
}
|
||||
async userDetails(userListDto: UserListDto) {
|
||||
const path = `/v2.0/apps/${userListDto.schema}/users`;
|
||||
const data = await this.tuya.request({
|
||||
method: 'GET',
|
||||
path,
|
||||
query: userListDto,
|
||||
});
|
||||
return data;
|
||||
}
|
||||
}
|
||||
12
src/users/user.module.ts
Normal file
12
src/users/user.module.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { UserService } from './services/user.service';
|
||||
import { UserController } from './controllers/user.controller';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
|
||||
@Module({
|
||||
imports: [ConfigModule],
|
||||
controllers: [UserController],
|
||||
providers: [UserService],
|
||||
exports: [UserService],
|
||||
})
|
||||
export class UserModule {}
|
||||
Reference in New Issue
Block a user