user list api done

This commit is contained in:
Viraj Parmar
2024-02-16 17:34:29 +05:30
parent 117c42d034
commit 37e0effb07
22 changed files with 528 additions and 86 deletions
+11 -3
View File
@@ -1,10 +1,18 @@
import { Module } from '@nestjs/common';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { ConfigModule } from '@nestjs/config';
import config from './config';
import { AuthenticationModule } from './modules/authentication/authentication.module';
import { AuthenticationController } from './modules/authentication/controllers/authentication.controller';
@Module({
imports: [],
controllers: [AuthController],
imports: [
ConfigModule.forRoot({
load: config,
}),
AuthenticationModule,
],
controllers: [AuthController,AuthenticationController],
providers: [AuthService],
})
export class AuthModule {}
+10
View 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,
}),
);
+3
View File
@@ -0,0 +1,3 @@
import AuthConfig from './auth.config';
export default [AuthConfig];
@@ -0,0 +1,12 @@
import { Module } from '@nestjs/common';
import { AuthenticationController } from './controllers/authentication.controller';
import { AuthenticationService } from './services/authentication.service';
import { ConfigModule } from '@nestjs/config';
@Module({
imports: [ConfigModule],
controllers: [AuthenticationController],
providers: [AuthenticationService],
exports: [AuthenticationService],
})
export class AuthenticationModule {}
@@ -0,0 +1,14 @@
import { Controller, Post } from '@nestjs/common';
import { AuthenticationService } from '../services/authentication.service';
@Controller({
version: '1',
path: 'authentication',
})
export class AuthenticationController {
constructor(private readonly authenticationService: AuthenticationService) {}
@Post('auth')
async Authentication() {
return await this.authenticationService.main();
}
}
@@ -0,0 +1,121 @@
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,
headers: { [k: string]: 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,
};
}
}
-22
View File
@@ -1,22 +0,0 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AppController } from './app.controller';
import { AppService } from './app.service';
describe('AppController', () => {
let appController: AppController;
beforeEach(async () => {
const app: TestingModule = await Test.createTestingModule({
controllers: [AppController],
providers: [AppService],
}).compile();
appController = app.get<AppController>(AppController);
});
describe('root', () => {
it('should return "Hello World!"', () => {
expect(appController.getHello()).toBe('Hello World!');
});
});
});
-10
View File
@@ -1,10 +0,0 @@
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
@@ -1,12 +1,12 @@
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
import { AppService } from './backend.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
@Get('healthcheck')
getHello(): string {
return this.appService.getHello();
return this.appService.healthcheck();
}
}
+18
View File
@@ -0,0 +1,18 @@
import { Module } from '@nestjs/common';
import { AppController } from './backend.controller';
import { AppService } from './backend.service';
import { UserModule } from './modules/user/user.module';
import { ConfigModule } from '@nestjs/config';
import config from './config';
@Module({
imports: [
ConfigModule.forRoot({
load: config,
}),
UserModule,
],
controllers: [AppController],
providers: [AppService],
})
export class BackendModule {}
@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
healthcheck(): string {
return 'Healthcheck!';
}
}
+10
View 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,
}),
);
+3
View File
@@ -0,0 +1,3 @@
import AuthConfig from './auth.config';
export default [AuthConfig];
+2 -2
View File
@@ -1,8 +1,8 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { BackendModule } from './backend.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const app = await NestFactory.create(BackendModule);
await app.listen(6000);
}
bootstrap();
@@ -0,0 +1,21 @@
import { Controller, Get, Query } from '@nestjs/common';
import { UserService } from '../services/user.service';
import { UserListDto } from '../dtos/user.list.dto';
//@ApiTags('User Module')
@Controller({
version: '1',
path: 'user',
})
export class UserController {
constructor(private readonly userService: UserService) {}
@Get('list')
async userList(@Query() userListDto: UserListDto) {
try {
return await this.userService.userDetails(userListDto);
} catch (err) {
throw new Error(err);
}
}
}
@@ -0,0 +1,27 @@
import { IsNotEmpty, IsNumber, IsOptional, IsString } from 'class-validator';
export class UserListDto {
@IsString()
@IsOptional()
schema: string;
@IsNumber()
@IsNotEmpty()
page_no: number;
@IsNumber()
@IsNotEmpty()
page_size: number;
@IsString()
@IsOptional()
username: string;
@IsNumber()
@IsOptional()
start_time: number;
@IsNumber()
@IsOptional()
end_time: number;
}
@@ -0,0 +1,33 @@
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 accessKey: string;
private secretKey: string;
constructor(private readonly configService: ConfigService) {
(this.accessKey = this.configService.get<string>('auth-config.ACCESS_KEY')),
(this.secretKey = this.configService.get<string>(
'auth-config.SECRET_KEY',
));
}
async userDetails(userListDto: UserListDto) {
const url = `https://openapi.tuyaeu.com/v2.0/apps/${userListDto.schema}/users`;
const tuya = new TuyaContext({
baseUrl: 'https://openapi.tuyacn.com',
accessKey:this.secretKey,
secretKey:this.accessKey,
});
const data = await tuya.request({
method: 'GET',
path: url,
query: userListDto,
});
return data;
}
}
@@ -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 {}
-24
View File
@@ -1,24 +0,0 @@
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import * as request from 'supertest';
import { AppModule } from './../src/app.module';
describe('AppController (e2e)', () => {
let app: INestApplication;
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(200)
.expect('Hello World!');
});
});
-9
View File
@@ -1,9 +0,0 @@
{
"moduleFileExtensions": ["js", "json", "ts"],
"rootDir": ".",
"testEnvironment": "node",
"testRegex": ".e2e-spec.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
}
}