auth module controllers carried
This commit is contained in:
parent
2e10de9758
commit
f39dc541e1
|
|
@ -20,7 +20,8 @@
|
|||
"redis": "^5.6.1",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rxjs": "^7.8.1",
|
||||
"uuid": "^11.1.0"
|
||||
"uuid": "^11.1.0",
|
||||
"zod": "^4.0.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.2.0",
|
||||
|
|
@ -11655,6 +11656,15 @@
|
|||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "4.0.10",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.0.10.tgz",
|
||||
"integrity": "sha512-3vB+UU3/VmLL2lvwcY/4RV2i9z/YU0DTV/tDuYjrwmx5WeJ7hwy+rGEEx8glHp6Yxw7ibRbKSaIFBgReRPe5KA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@
|
|||
"redis": "^5.6.1",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rxjs": "^7.8.1",
|
||||
"uuid": "^11.1.0"
|
||||
"uuid": "^11.1.0",
|
||||
"zod": "^4.0.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.2.0",
|
||||
|
|
|
|||
|
|
@ -3080,6 +3080,7 @@ model occupant_types {
|
|||
occupant_code String @default("") @db.VarChar
|
||||
occupant_category String @default("") @db.VarChar
|
||||
occupant_category_type String @default("") @db.VarChar
|
||||
function_retriever String @default("") @db.VarChar
|
||||
occupant_is_unique Boolean @default(false)
|
||||
ref_id String? @db.VarChar(100)
|
||||
replication_id Int @default(0) @db.SmallInt
|
||||
|
|
@ -3474,6 +3475,7 @@ model staff {
|
|||
staff_code String @db.VarChar
|
||||
duties_id Int
|
||||
duties_uu_id String @db.VarChar
|
||||
function_retriever String @default("") @db.VarChar
|
||||
ref_id String? @db.VarChar(100)
|
||||
replication_id Int @default(0) @db.SmallInt
|
||||
cryp_uu_id String? @db.VarChar
|
||||
|
|
|
|||
|
|
@ -7,8 +7,10 @@ import {
|
|||
Param,
|
||||
Body,
|
||||
HttpCode,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { AccountsService } from './accounts.service';
|
||||
import { AuthControlGuard, EndpointControlGuard } from '../middleware/access-control.guard';
|
||||
|
||||
@Controller('accounts')
|
||||
export class AccountsController {
|
||||
|
|
@ -16,6 +18,7 @@ export class AccountsController {
|
|||
|
||||
@Post('filter')
|
||||
@HttpCode(200)
|
||||
@UseGuards(AuthControlGuard, EndpointControlGuard)
|
||||
async filterAccounts(@Body() query: any) {
|
||||
const result = await this.accountsService.findWithPagination(query);
|
||||
const { pagination, data } = result;
|
||||
|
|
|
|||
|
|
@ -4,10 +4,19 @@ import { AccountsController } from './accounts.controller';
|
|||
import { PrismaModule } from '@/prisma/prisma.module';
|
||||
import { CacheService } from '../cache.service';
|
||||
import { UtilsModule } from '../utils/utils.module';
|
||||
import {
|
||||
AuthControlGuard,
|
||||
EndpointControlGuard,
|
||||
} from '@/src/middleware/access-control.guard';
|
||||
|
||||
@Module({
|
||||
imports: [PrismaModule, UtilsModule],
|
||||
providers: [AccountsService, CacheService],
|
||||
providers: [
|
||||
AccountsService,
|
||||
CacheService,
|
||||
AuthControlGuard,
|
||||
EndpointControlGuard,
|
||||
],
|
||||
controllers: [AccountsController],
|
||||
})
|
||||
export class AccountsModule {}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { AuthModule } from './auth/auth.module';
|
|||
import { RedisModule } from '@liaoliaots/nestjs-redis';
|
||||
import { CacheService } from './cache.service';
|
||||
import { LoggerMiddleware } from '@/src/middleware/logger.middleware';
|
||||
import { DiscoveryModule } from '@nestjs/core';
|
||||
|
||||
const redisConfig = {
|
||||
host: '10.10.2.15',
|
||||
|
|
@ -26,13 +27,14 @@ const serviceModuleList = [
|
|||
RedisModule.forRoot({
|
||||
config: redisConfig,
|
||||
}),
|
||||
DiscoveryModule,
|
||||
];
|
||||
const controllersList = [AppController];
|
||||
const providersList = [AppService, CacheService];
|
||||
const exportsList = [CacheService];
|
||||
|
||||
@Module({
|
||||
imports: [...modulesList, ...serviceModuleList],
|
||||
imports: [...serviceModuleList, ...modulesList],
|
||||
controllers: controllersList,
|
||||
providers: providersList,
|
||||
exports: exportsList,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Put,
|
||||
Delete,
|
||||
Param,
|
||||
Body,
|
||||
HttpCode,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { AuthService } from './auth.service';
|
||||
import { userLoginValidator } from './login/dtoValidator';
|
||||
import { userSelectValidator } from './select/dtoValidator';
|
||||
import { userLogoutValidator } from './logout/dtoValidator';
|
||||
import { AuthControlGuard } from '../middleware/access-control.guard';
|
||||
|
||||
@Controller('auth')
|
||||
export class AuthController {
|
||||
constructor(private readonly authService: AuthService) {}
|
||||
|
||||
@Post('login')
|
||||
@HttpCode(200)
|
||||
async login(@Body() query: userLoginValidator) {
|
||||
return await this.authService.login(query);
|
||||
}
|
||||
|
||||
@Post('select')
|
||||
@HttpCode(200)
|
||||
@UseGuards(AuthControlGuard)
|
||||
async select(@Body() query: userSelectValidator) {
|
||||
return { message: 'Logout successful' };
|
||||
}
|
||||
|
||||
@Post('/password/create')
|
||||
@HttpCode(200)
|
||||
async createPassword() {
|
||||
return { message: 'Password created successfully' };
|
||||
}
|
||||
|
||||
@Post('/password/change')
|
||||
@HttpCode(200)
|
||||
@UseGuards(AuthControlGuard)
|
||||
async changePassword() {
|
||||
return { message: 'Password changed successfully' };
|
||||
}
|
||||
|
||||
@Post('/password/reset')
|
||||
@HttpCode(200)
|
||||
async resetPassword() {
|
||||
return { message: 'Password reset successfully' };
|
||||
}
|
||||
|
||||
@Post('/password/verify-otp')
|
||||
@HttpCode(200)
|
||||
@UseGuards(AuthControlGuard)
|
||||
async verifyOtp() {
|
||||
return { message: 'Password verified successfully' };
|
||||
}
|
||||
|
||||
@Post('logout')
|
||||
@HttpCode(200)
|
||||
@UseGuards(AuthControlGuard)
|
||||
async logout(@Body() query: userLogoutValidator) {
|
||||
return { message: 'Logout successful' };
|
||||
}
|
||||
|
||||
@Post('disconnect')
|
||||
@HttpCode(200)
|
||||
@UseGuards(AuthControlGuard)
|
||||
async disconnect() {
|
||||
return { message: 'Disconnect successful' };
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +1,32 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { LoginModule } from '@/src/auth/login/login.module';
|
||||
import { SelectModule } from '@/src/auth/select/select.module';
|
||||
import { PasswordService } from '@/src/auth/password/password.service';
|
||||
import { PasswordModule } from '@/src/auth/password/password.module';
|
||||
import { LogoutModule } from '@/src/auth/logout/logout.module';
|
||||
import { DisconnectModule } from '@/src/auth/disconnect/disconnect.module';
|
||||
import { TokenModule } from '@/src/auth/token/token.module';
|
||||
import { AuthController } from '@/src/auth/auth.controller';
|
||||
import { LoginService } from '@/src/auth/login/login.service';
|
||||
import { LogoutService } from '@/src/auth/logout/logout.service';
|
||||
import { AuthService } from '@/src/auth/auth.service';
|
||||
import { SelectService } from '@/src/auth/select/select.service';
|
||||
import { UtilsModule } from '@/src/utils/utils.module';
|
||||
import { PrismaService } from '../prisma.service';
|
||||
import { CreatePasswordService } from './password/create/create.service';
|
||||
import { ResetPasswordService } from './password/reset/reset.service';
|
||||
import { ChangePasswordService } from './password/change/change.service';
|
||||
import { VerifyOtpService } from './password/verify-otp/verify-otp.service';
|
||||
import { DisconnectService } from './disconnect/disconnect.service';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
LoginModule,
|
||||
LogoutModule,
|
||||
SelectModule,
|
||||
PasswordModule,
|
||||
DisconnectModule,
|
||||
TokenModule,
|
||||
imports: [UtilsModule],
|
||||
controllers: [AuthController],
|
||||
providers: [
|
||||
AuthService,
|
||||
LoginService,
|
||||
LogoutService,
|
||||
SelectService,
|
||||
CreatePasswordService,
|
||||
ResetPasswordService,
|
||||
ChangePasswordService,
|
||||
VerifyOtpService,
|
||||
DisconnectService,
|
||||
PrismaService,
|
||||
],
|
||||
providers: [PasswordService],
|
||||
exports: [AuthService],
|
||||
})
|
||||
export class AuthModule {}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { LoginService } from './login/login.service';
|
||||
import { LogoutService } from './logout/logout.service';
|
||||
import { SelectService } from './select/select.service';
|
||||
import { userLoginValidator } from '@/src/auth/login/dtoValidator';
|
||||
import { userSelectValidator } from './select/dtoValidator';
|
||||
import { userLogoutValidator } from './logout/dtoValidator';
|
||||
import { CreatePasswordService } from './password/create/create.service';
|
||||
import { ResetPasswordService } from './password/reset/reset.service';
|
||||
import { ChangePasswordService } from './password/change/change.service';
|
||||
import { VerifyOtpService } from './password/verify-otp/verify-otp.service';
|
||||
import { DisconnectService } from './disconnect/disconnect.service';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
constructor(
|
||||
private loginService: LoginService,
|
||||
private logoutService: LogoutService,
|
||||
private selectService: SelectService,
|
||||
private createPasswordService: CreatePasswordService,
|
||||
private changePasswordService: ChangePasswordService,
|
||||
private resetPasswordService: ResetPasswordService,
|
||||
private verifyOtpService: VerifyOtpService,
|
||||
private disconnectService: DisconnectService,
|
||||
) {}
|
||||
|
||||
async login(dto: userLoginValidator) {
|
||||
return await this.loginService.run(dto);
|
||||
}
|
||||
|
||||
async logout(dto: userLogoutValidator) {
|
||||
return await this.logoutService.run(dto);
|
||||
}
|
||||
|
||||
async select(dto: userSelectValidator) {
|
||||
return await this.selectService.run(dto);
|
||||
}
|
||||
|
||||
async createPassword(dto: any) {
|
||||
return await this.createPasswordService.run(dto);
|
||||
}
|
||||
|
||||
async changePassword(dto: any) {
|
||||
return await this.changePasswordService.run(dto);
|
||||
}
|
||||
|
||||
async resetPassword(dto: any) {
|
||||
return await this.resetPasswordService.run(dto);
|
||||
}
|
||||
|
||||
async verifyOtp(dto: any) {
|
||||
return await this.verifyOtpService.run(dto);
|
||||
}
|
||||
async disconnect() {
|
||||
return await this.disconnectService.run();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { DisconnectController } from './disconnect.controller';
|
||||
|
||||
describe('DisconnectController', () => {
|
||||
let controller: DisconnectController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [DisconnectController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<DisconnectController>(DisconnectController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import { Controller } from '@nestjs/common';
|
||||
|
||||
@Controller('disconnect')
|
||||
export class DisconnectController {}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { DisconnectService } from './disconnect.service';
|
||||
import { DisconnectController } from './disconnect.controller';
|
||||
|
||||
@Module({
|
||||
providers: [DisconnectService],
|
||||
controllers: [DisconnectController]
|
||||
})
|
||||
export class DisconnectModule {}
|
||||
|
|
@ -1,4 +1,8 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class DisconnectService {}
|
||||
export class DisconnectService {
|
||||
async run() {
|
||||
return { message: 'Disconnect successful' };
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
import { IsObject, IsOptional, IsString, IsBoolean } from 'class-validator';
|
||||
|
||||
export class userLoginValidator {
|
||||
@IsString()
|
||||
accessKey: string;
|
||||
|
||||
@IsString()
|
||||
password: string;
|
||||
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
rememberMe?: boolean;
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { LoginController } from './login.controller';
|
||||
|
||||
describe('LoginController', () => {
|
||||
let controller: LoginController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [LoginController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<LoginController>(LoginController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import { Controller } from '@nestjs/common';
|
||||
|
||||
@Controller('login')
|
||||
export class LoginController {}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { LoginController } from './login.controller';
|
||||
import { LoginService } from './login.service';
|
||||
|
||||
@Module({
|
||||
controllers: [LoginController],
|
||||
providers: [LoginService]
|
||||
})
|
||||
export class LoginModule {}
|
||||
|
|
@ -1,4 +1,57 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { userLoginValidator } from '@/src/auth/login/dtoValidator';
|
||||
import { RedisHandlers } from '@/src/utils/auth/redis_handlers';
|
||||
import { PasswordHandlers } from '@/src/utils/auth/login_handler';
|
||||
import { PrismaService } from '@/src/prisma.service';
|
||||
import { AuthTokenSchema } from '@/src/types/auth/token';
|
||||
|
||||
@Injectable()
|
||||
export class LoginService {}
|
||||
export class LoginService {
|
||||
constructor(
|
||||
private readonly redis: RedisHandlers,
|
||||
private readonly passHandlers: PasswordHandlers,
|
||||
private readonly prisma: PrismaService,
|
||||
) {}
|
||||
|
||||
async run(dto: userLoginValidator) {
|
||||
const foundUser = await this.prisma.users.findFirstOrThrow({
|
||||
where: { email: dto.accessKey },
|
||||
});
|
||||
|
||||
// if (foundUser.password_token) {
|
||||
// throw new Error('Password need to be set first');
|
||||
// }
|
||||
|
||||
const isPasswordValid = this.passHandlers.check_password(
|
||||
foundUser.uu_id,
|
||||
dto.password,
|
||||
foundUser.hash_password,
|
||||
);
|
||||
|
||||
// if (!isPasswordValid) {
|
||||
// throw new Error('Invalid password');
|
||||
// }
|
||||
|
||||
const foundPerson = await this.prisma.people.findFirstOrThrow({
|
||||
where: { id: foundUser.id },
|
||||
});
|
||||
|
||||
const redisData = AuthTokenSchema.parse({
|
||||
people: foundPerson,
|
||||
users: foundUser,
|
||||
credentials: {
|
||||
person_id: foundPerson.id,
|
||||
person_name: foundPerson.firstname,
|
||||
},
|
||||
});
|
||||
|
||||
const accessToken = await this.redis.setLoginToRedis(
|
||||
redisData,
|
||||
foundUser.uu_id,
|
||||
);
|
||||
return {
|
||||
accessToken,
|
||||
message: 'Login successful',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
import { IsString } from 'class-validator';
|
||||
|
||||
export class userLogoutValidator {
|
||||
@IsString()
|
||||
selected_uu_id: string;
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { LogoutController } from './logout.controller';
|
||||
|
||||
describe('LogoutController', () => {
|
||||
let controller: LogoutController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [LogoutController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<LogoutController>(LogoutController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import { Controller } from '@nestjs/common';
|
||||
|
||||
@Controller('logout')
|
||||
export class LogoutController {}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { LogoutService } from './logout.service';
|
||||
import { LogoutController } from './logout.controller';
|
||||
|
||||
@Module({
|
||||
providers: [LogoutService],
|
||||
controllers: [LogoutController]
|
||||
})
|
||||
export class LogoutModule {}
|
||||
|
|
@ -1,4 +1,9 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { userLogoutValidator } from '@/src/auth/logout/dtoValidator';
|
||||
|
||||
@Injectable()
|
||||
export class LogoutService {}
|
||||
export class LogoutService {
|
||||
async run(dto: userLogoutValidator) {
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { ChangeController } from './change.controller';
|
||||
|
||||
describe('ChangeController', () => {
|
||||
let controller: ChangeController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [ChangeController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<ChangeController>(ChangeController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import { Controller } from '@nestjs/common';
|
||||
|
||||
@Controller('change')
|
||||
export class ChangeController {}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { ChangeService } from './change.service';
|
||||
import { ChangeController } from './change.controller';
|
||||
|
||||
@Module({
|
||||
providers: [ChangeService],
|
||||
controllers: [ChangeController]
|
||||
})
|
||||
export class ChangeModule {}
|
||||
|
|
@ -1,4 +1,8 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class ChangeService {}
|
||||
export class ChangePasswordService {
|
||||
async run(dto: any) {
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { CreateController } from './create.controller';
|
||||
|
||||
describe('CreateController', () => {
|
||||
let controller: CreateController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [CreateController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<CreateController>(CreateController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import { Controller } from '@nestjs/common';
|
||||
|
||||
@Controller('create')
|
||||
export class CreateController {}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { CreateService } from './create.service';
|
||||
import { CreateController } from './create.controller';
|
||||
|
||||
@Module({
|
||||
providers: [CreateService],
|
||||
controllers: [CreateController]
|
||||
})
|
||||
export class CreateModule {}
|
||||
|
|
@ -1,4 +1,8 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class CreateService {}
|
||||
export class CreatePasswordService {
|
||||
async run(dto: any) {
|
||||
return { message: 'Password created successfully' };
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { PasswordController } from './password.controller';
|
||||
|
||||
describe('PasswordController', () => {
|
||||
let controller: PasswordController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [PasswordController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<PasswordController>(PasswordController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import { Controller } from '@nestjs/common';
|
||||
|
||||
@Controller('password')
|
||||
export class PasswordController {}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { PasswordController } from './password.controller';
|
||||
import { CreateModule } from './create/create.module';
|
||||
import { ChangeModule } from './change/change.module';
|
||||
import { ResetModule } from './reset/reset.module';
|
||||
import { VerifyOtpModule } from './verify-otp/verify-otp.module';
|
||||
|
||||
@Module({
|
||||
controllers: [PasswordController],
|
||||
imports: [CreateModule, ChangeModule, ResetModule, VerifyOtpModule]
|
||||
})
|
||||
export class PasswordModule {}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { PasswordService } from './password.service';
|
||||
|
||||
describe('PasswordService', () => {
|
||||
let service: PasswordService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [PasswordService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<PasswordService>(PasswordService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class PasswordService {}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { ResetController } from './reset.controller';
|
||||
|
||||
describe('ResetController', () => {
|
||||
let controller: ResetController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [ResetController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<ResetController>(ResetController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import { Controller } from '@nestjs/common';
|
||||
|
||||
@Controller('reset')
|
||||
export class ResetController {}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { ResetService } from './reset.service';
|
||||
import { ResetController } from './reset.controller';
|
||||
|
||||
@Module({
|
||||
providers: [ResetService],
|
||||
controllers: [ResetController]
|
||||
})
|
||||
export class ResetModule {}
|
||||
|
|
@ -1,4 +1,8 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class ResetService {}
|
||||
export class ResetPasswordService {
|
||||
async run(dto: any) {
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { VerifyOtpController } from './verify-otp.controller';
|
||||
|
||||
describe('VerifyOtpController', () => {
|
||||
let controller: VerifyOtpController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [VerifyOtpController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<VerifyOtpController>(VerifyOtpController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import { Controller } from '@nestjs/common';
|
||||
|
||||
@Controller('verify-otp')
|
||||
export class VerifyOtpController {}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { VerifyOtpService } from './verify-otp.service';
|
||||
import { VerifyOtpController } from './verify-otp.controller';
|
||||
|
||||
@Module({
|
||||
providers: [VerifyOtpService],
|
||||
controllers: [VerifyOtpController]
|
||||
})
|
||||
export class VerifyOtpModule {}
|
||||
|
|
@ -1,4 +1,8 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class VerifyOtpService {}
|
||||
export class VerifyOtpService {
|
||||
async run(dto: any) {
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
import { IsString } from 'class-validator';
|
||||
|
||||
export class userSelectValidator {
|
||||
@IsString()
|
||||
selected_uu_id: string;
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { SelectController } from './select.controller';
|
||||
|
||||
describe('SelectController', () => {
|
||||
let controller: SelectController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [SelectController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<SelectController>(SelectController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import { Controller } from '@nestjs/common';
|
||||
|
||||
@Controller('select')
|
||||
export class SelectController {}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { SelectController } from './select.controller';
|
||||
import { SelectService } from './select.service';
|
||||
|
||||
@Module({
|
||||
controllers: [SelectController],
|
||||
providers: [SelectService]
|
||||
})
|
||||
export class SelectModule {}
|
||||
|
|
@ -1,4 +1,9 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { userSelectValidator } from '@/src/auth/select/dtoValidator';
|
||||
|
||||
@Injectable()
|
||||
export class SelectService {}
|
||||
export class SelectService {
|
||||
async run(dto: userSelectValidator) {
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import { extractAndPersistRoutes } from '@/src/utils/extract-routes';
|
||||
import { PrismaService } from './prisma.service';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
await app.listen(process.env.PORT ?? 3000);
|
||||
|
||||
console.log(`🚀 Uygulama çalışıyor: ${await app.getUrl()}`);
|
||||
extractAndPersistRoutes(app, app.get(PrismaService));
|
||||
}
|
||||
bootstrap();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
import {
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
Injectable,
|
||||
ForbiddenException,
|
||||
} from '@nestjs/common';
|
||||
import { RedisHandlers } from '@/src/utils/auth/redis_handlers';
|
||||
|
||||
const getAccessTokenFromHeader = (req: Request): string => {
|
||||
console.log(req.headers);
|
||||
const token = req.headers['acs'];
|
||||
if (!token) {
|
||||
throw new ForbiddenException('Access token header is missing');
|
||||
}
|
||||
return token;
|
||||
};
|
||||
|
||||
const getSelectTokenFromHeader = (req: Request): string => {
|
||||
const token = req.headers['slc'];
|
||||
if (!token) {
|
||||
throw new ForbiddenException('Select token header is missing');
|
||||
}
|
||||
return token;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class AuthControlGuard implements CanActivate {
|
||||
constructor(private cacheService: RedisHandlers) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const req = context.switchToHttp().getRequest();
|
||||
const accessToken = getAccessTokenFromHeader(req);
|
||||
console.log('AuthControlGuard', accessToken);
|
||||
// const hasAccess = accessObject.permissions?.some(
|
||||
// (p: any) => p.method === method && p.url === path,
|
||||
// );
|
||||
|
||||
// if (!hasAccess) {
|
||||
// throw new ForbiddenException('Access denied to this route');
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class EndpointControlGuard implements CanActivate {
|
||||
constructor(private cacheService: RedisHandlers) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const req = context.switchToHttp().getRequest();
|
||||
const selectToken = getSelectTokenFromHeader(req);
|
||||
const method = req.method;
|
||||
const path = req.route?.path;
|
||||
console.log('EndpointControlGuard', selectToken, method, path);
|
||||
// const hasAccess = accessObject.permissions?.some(
|
||||
// (p: any) => p.method === method && p.url === path,
|
||||
// );
|
||||
|
||||
// if (!hasAccess) {
|
||||
// throw new ForbiddenException('Access denied to this route');
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
// Token type redis base TOKEN object
|
||||
|
||||
enum UserType {
|
||||
employee = 1,
|
||||
occupant = 2,
|
||||
}
|
||||
|
||||
interface Credentials {
|
||||
person_id: number;
|
||||
person_name: string;
|
||||
}
|
||||
|
||||
interface ApplicationToken {
|
||||
// Application Token Object -> is the main object for the user
|
||||
user_type: number;
|
||||
credential_token: string;
|
||||
user_uu_id: string;
|
||||
user_id: number;
|
||||
person_id: number;
|
||||
person_uu_id: string;
|
||||
request?: Record<string, any>; // Request Info of Client
|
||||
expires_at?: number; // Expiry timestamp
|
||||
reachable_event_codes?: Record<string, any>; // ID list of reachable event codes as "endpoint_code": ["UUID", "UUID"]
|
||||
reachable_app_codes?: Record<string, any>; // ID list of reachable applications as "page_url": ["UUID", "UUID"]
|
||||
}
|
||||
|
||||
interface OccupantToken {
|
||||
// Selection of the occupant type for a build part is made by the user
|
||||
living_space_id: number; // Internal use
|
||||
living_space_uu_id: string; // Outer use
|
||||
occupant_type_id: number;
|
||||
occupant_type_uu_id: string;
|
||||
occupant_type: string;
|
||||
build_id: number;
|
||||
build_uuid: string;
|
||||
build_part_id: number;
|
||||
build_part_uuid: string;
|
||||
responsible_company_id?: number;
|
||||
responsible_company_uuid?: string;
|
||||
responsible_employee_id?: number;
|
||||
responsible_employee_uuid?: string;
|
||||
}
|
||||
|
||||
interface CompanyToken {
|
||||
// Selection of the company for an employee is made by the user
|
||||
company_id: number;
|
||||
company_uu_id: string;
|
||||
department_id: number; // ID list of departments
|
||||
department_uu_id: string; // UUID list of departments
|
||||
duty_id: number;
|
||||
duty_uu_id: string;
|
||||
staff_id: number;
|
||||
staff_uu_id: string;
|
||||
employee_id: number;
|
||||
employee_uu_id: string;
|
||||
bulk_duties_id: number;
|
||||
}
|
||||
|
||||
interface OccupantTokenObject extends ApplicationToken {
|
||||
// Occupant Token Object -> Requires selection of the occupant type for a specific build part
|
||||
available_occupants: Record<string, any> | null;
|
||||
selected?: Record<string, any>; // Selected Occupant Type
|
||||
is_employee: boolean; // Always false
|
||||
is_occupant: boolean; // Always true
|
||||
}
|
||||
|
||||
interface EmployeeTokenObject extends ApplicationToken {
|
||||
// Full hierarchy Employee[staff_id] -> Staff -> Duty -> Department -> Company
|
||||
companies_id_list: number[]; // List of company objects
|
||||
companies_uu_id_list: string[]; // UUID list of company objects
|
||||
duty_id_list: number[]; // List of duty objects
|
||||
duty_uu_id_list: string[]; // UUID list of duty objects
|
||||
selected?: Record<string, any>; // Selected Company Object
|
||||
is_employee: boolean; // Always true
|
||||
is_occupant: boolean; // Always false
|
||||
}
|
||||
|
||||
// Union type for token objects
|
||||
type TokenDictType = EmployeeTokenObject | OccupantTokenObject;
|
||||
|
||||
export {
|
||||
UserType,
|
||||
Credentials,
|
||||
ApplicationToken,
|
||||
OccupantToken,
|
||||
CompanyToken,
|
||||
OccupantTokenObject,
|
||||
EmployeeTokenObject,
|
||||
TokenDictType,
|
||||
};
|
||||
|
|
@ -1,90 +1,122 @@
|
|||
// Token type redis base TOKEN object
|
||||
import { z } from 'zod';
|
||||
|
||||
enum UserType {
|
||||
employee = 1,
|
||||
occupant = 2,
|
||||
}
|
||||
// ENUM
|
||||
export const UserType = {
|
||||
employee: 1,
|
||||
occupant: 2,
|
||||
} as const;
|
||||
export type UserType = (typeof UserType)[keyof typeof UserType];
|
||||
|
||||
interface Credentials {
|
||||
person_id: number;
|
||||
person_name: string;
|
||||
}
|
||||
// Credentials
|
||||
export const CredentialsSchema = z.object({
|
||||
person_id: z.number(),
|
||||
person_name: z.string(),
|
||||
});
|
||||
export type Credentials = z.infer<typeof CredentialsSchema>;
|
||||
|
||||
interface ApplicationToken {
|
||||
// Application Token Object -> is the main object for the user
|
||||
user_type: number;
|
||||
credential_token: string;
|
||||
user_uu_id: string;
|
||||
user_id: number;
|
||||
person_id: number;
|
||||
person_uu_id: string;
|
||||
request?: Record<string, any>; // Request Info of Client
|
||||
expires_at?: number; // Expiry timestamp
|
||||
reachable_event_codes?: Record<string, any>; // ID list of reachable event codes as "endpoint_code": ["UUID", "UUID"]
|
||||
reachable_app_codes?: Record<string, any>; // ID list of reachable applications as "page_url": ["UUID", "UUID"]
|
||||
}
|
||||
export const AuthTokenSchema = z.object({
|
||||
people: z.object({
|
||||
firstname: z.string(),
|
||||
surname: z.string(),
|
||||
middle_name: z.string(),
|
||||
birthname: z.string().nullable(),
|
||||
sex_code: z.string(),
|
||||
person_ref: z.string().nullable(),
|
||||
person_tag: z.string(),
|
||||
father_name: z.string(),
|
||||
mother_name: z.string(),
|
||||
country_code: z.string(),
|
||||
national_identity_id: z.string(),
|
||||
birth_place: z.string(),
|
||||
birth_date: z.date(),
|
||||
tax_no: z.string(),
|
||||
ref_id: z.string().nullable(),
|
||||
replication_id: z.number().nullable(),
|
||||
cryp_uu_id: z.string().nullable(),
|
||||
created_credentials_token: z.string().nullable(),
|
||||
updated_credentials_token: z.string().nullable(),
|
||||
confirmed_credentials_token: z.string().nullable(),
|
||||
ref_int: z.number().nullable(),
|
||||
is_confirmed: z.boolean(),
|
||||
deleted: z.boolean(),
|
||||
active: z.boolean(),
|
||||
is_notification_send: z.boolean(),
|
||||
is_email_send: z.boolean(),
|
||||
id: z.number(),
|
||||
uu_id: z.string(),
|
||||
expiry_starts: z.date(),
|
||||
expiry_ends: z.date(),
|
||||
created_at: z.date(),
|
||||
updated_at: z.date(),
|
||||
}),
|
||||
users: z.object({
|
||||
user_tag: z.string(),
|
||||
email: z.string(),
|
||||
phone_number: z.string(),
|
||||
via: z.string(),
|
||||
avatar: z.string(),
|
||||
hash_password: z.string(),
|
||||
password_token: z.string(),
|
||||
remember_me: z.boolean(),
|
||||
password_expires_day: z.number(),
|
||||
password_expiry_begins: z.date(),
|
||||
related_company: z.string(),
|
||||
person_id: z.number(),
|
||||
person_uu_id: z.string(),
|
||||
local_timezone: z.string(),
|
||||
ref_id: z.string().nullable(),
|
||||
ref_int: z.number().nullable(),
|
||||
replication_id: z.number().nullable(),
|
||||
cryp_uu_id: z.string().nullable(),
|
||||
created_credentials_token: z.string().nullable(),
|
||||
updated_credentials_token: z.string().nullable(),
|
||||
confirmed_credentials_token: z.string().nullable(),
|
||||
is_confirmed: z.boolean(),
|
||||
deleted: z.boolean(),
|
||||
active: z.boolean(),
|
||||
is_notification_send: z.boolean(),
|
||||
is_email_send: z.boolean(),
|
||||
id: z.number(),
|
||||
uu_id: z.string(),
|
||||
expiry_starts: z.date(),
|
||||
expiry_ends: z.date(),
|
||||
created_at: z.date(),
|
||||
updated_at: z.date(),
|
||||
default_language: z.string(),
|
||||
}),
|
||||
credentials: CredentialsSchema,
|
||||
});
|
||||
|
||||
interface OccupantToken {
|
||||
// Selection of the occupant type for a build part is made by the user
|
||||
living_space_id: number; // Internal use
|
||||
living_space_uu_id: string; // Outer use
|
||||
occupant_type_id: number;
|
||||
occupant_type_uu_id: string;
|
||||
occupant_type: string;
|
||||
build_id: number;
|
||||
build_uuid: string;
|
||||
build_part_id: number;
|
||||
build_part_uuid: string;
|
||||
responsible_company_id?: number;
|
||||
responsible_company_uuid?: string;
|
||||
responsible_employee_id?: number;
|
||||
responsible_employee_uuid?: string;
|
||||
}
|
||||
export type AuthToken = z.infer<typeof AuthTokenSchema>;
|
||||
|
||||
interface CompanyToken {
|
||||
// Selection of the company for an employee is made by the user
|
||||
company_id: number;
|
||||
company_uu_id: string;
|
||||
department_id: number; // ID list of departments
|
||||
department_uu_id: string; // UUID list of departments
|
||||
duty_id: number;
|
||||
duty_uu_id: string;
|
||||
staff_id: number;
|
||||
staff_uu_id: string;
|
||||
employee_id: number;
|
||||
employee_uu_id: string;
|
||||
bulk_duties_id: number;
|
||||
}
|
||||
export const EmployeeTokenSchema = z.object({
|
||||
functionsRetriever: z.string(),
|
||||
companies: z.object({}),
|
||||
department: z.object({}),
|
||||
duties: z.object({}),
|
||||
employee: z.object({}),
|
||||
staffs: z.object({}),
|
||||
reachable_event_codes: z.array(z.object({})),
|
||||
reachable_app_codes: z.array(z.object({})),
|
||||
kind: z.literal(UserType.employee),
|
||||
});
|
||||
|
||||
interface OccupantTokenObject extends ApplicationToken {
|
||||
// Occupant Token Object -> Requires selection of the occupant type for a specific build part
|
||||
available_occupants: Record<string, any> | null;
|
||||
selected?: Record<string, any>; // Selected Occupant Type
|
||||
is_employee: boolean; // Always false
|
||||
is_occupant: boolean; // Always true
|
||||
}
|
||||
export const OccupantTokenSchema = z.object({
|
||||
functionsRetriever: z.string(),
|
||||
livingSpace: z.object({}),
|
||||
occupantType: z.object({}),
|
||||
build: z.object({}),
|
||||
buildPart: z.object({}),
|
||||
responsibleCompany: z.object({}).optional(),
|
||||
responsibleEmployee: z.object({}).optional(),
|
||||
kind: z.literal(UserType.occupant),
|
||||
reachable_event_codes: z.array(z.object({})),
|
||||
reachable_app_codes: z.array(z.object({})),
|
||||
});
|
||||
|
||||
interface EmployeeTokenObject extends ApplicationToken {
|
||||
// Full hierarchy Employee[staff_id] -> Staff -> Duty -> Department -> Company
|
||||
companies_id_list: number[]; // List of company objects
|
||||
companies_uu_id_list: string[]; // UUID list of company objects
|
||||
duty_id_list: number[]; // List of duty objects
|
||||
duty_uu_id_list: string[]; // UUID list of duty objects
|
||||
selected?: Record<string, any>; // Selected Company Object
|
||||
is_employee: boolean; // Always true
|
||||
is_occupant: boolean; // Always false
|
||||
}
|
||||
export const TokenDictTypes = z.discriminatedUnion('kind', [
|
||||
EmployeeTokenSchema,
|
||||
OccupantTokenSchema,
|
||||
]);
|
||||
|
||||
// Union type for token objects
|
||||
type TokenDictType = EmployeeTokenObject | OccupantTokenObject;
|
||||
|
||||
export {
|
||||
UserType,
|
||||
Credentials,
|
||||
ApplicationToken,
|
||||
OccupantToken,
|
||||
CompanyToken,
|
||||
OccupantTokenObject,
|
||||
EmployeeTokenObject,
|
||||
TokenDictType,
|
||||
};
|
||||
export type TokenDictInterface = z.infer<typeof TokenDictTypes>;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,13 @@ import {
|
|||
} from '@nestjs/common';
|
||||
import { UsersService } from './users.service';
|
||||
|
||||
/**
|
||||
* USER TYPE CODE = BM BLD OCC ...
|
||||
* class Func
|
||||
* code = "uuid4"
|
||||
* TYPE = "build_manager"
|
||||
*/
|
||||
|
||||
@Controller('users')
|
||||
export class UsersController {
|
||||
constructor(private usersService: UsersService) {}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import crypto from 'crypto';
|
||||
import * as crypto from 'crypto';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
interface TokenConfig {
|
||||
|
|
@ -12,28 +12,29 @@ const tokenConfig: TokenConfig = {
|
|||
};
|
||||
|
||||
class PasswordHandlers {
|
||||
generate_random_uu_id(is_string: boolean = true): string {
|
||||
generateRandomUUID(is_string: boolean = true): string {
|
||||
return is_string ? uuidv4().toString() : uuidv4();
|
||||
}
|
||||
|
||||
create_hashed_password(
|
||||
domain: string,
|
||||
uuid: string,
|
||||
password: string,
|
||||
): string {
|
||||
const data = `${domain}:${uuid}:${password}`;
|
||||
create_hashed_password(uuid: string, password: string): string {
|
||||
const data = `${uuid}:${password}`;
|
||||
console.log(crypto.createHash('sha256').update(data).digest('hex'));
|
||||
return crypto.createHash('sha256').update(data).digest('hex');
|
||||
}
|
||||
|
||||
createSelectToken(accessToken: string, userUUID: string) {
|
||||
const data = `${accessToken}:${userUUID}`;
|
||||
return crypto.createHash('sha256').update(data).digest('hex');
|
||||
}
|
||||
|
||||
check_password(
|
||||
domain: string,
|
||||
uuid: string,
|
||||
password: string,
|
||||
hashed_password: string,
|
||||
): boolean {
|
||||
return (
|
||||
this.create_hashed_password(domain, uuid, password) === hashed_password
|
||||
);
|
||||
const created_hashed_password = this.create_hashed_password(uuid, password);
|
||||
console.log('created_hashed_password', created_hashed_password);
|
||||
return created_hashed_password === hashed_password;
|
||||
}
|
||||
|
||||
generateAccessToken(): string {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import {
|
||||
TokenDictType,
|
||||
OccupantTokenObject,
|
||||
EmployeeTokenObject,
|
||||
TokenDictTypes,
|
||||
TokenDictInterface,
|
||||
AuthToken,
|
||||
UserType,
|
||||
} from '@/src/types/auth/token';
|
||||
import { CacheService } from '@/src/cache.service';
|
||||
|
|
@ -15,110 +15,50 @@ export class RedisHandlers {
|
|||
constructor(
|
||||
private readonly cacheService: CacheService,
|
||||
private readonly passwordService: PasswordHandlers,
|
||||
) {
|
||||
this.cacheService = cacheService;
|
||||
this.passwordService = passwordService;
|
||||
) {}
|
||||
|
||||
generateSelectToken(accessToken: string, userUUID: string) {
|
||||
return this.passwordService.createSelectToken(accessToken, userUUID);
|
||||
}
|
||||
|
||||
async process_redis_object(redis_object: any): Promise<TokenDictType> {
|
||||
if (!redis_object) {
|
||||
throw new Error('Invalid Redis object: Object is null or undefined');
|
||||
}
|
||||
if (redis_object.user_type === UserType.employee) {
|
||||
const validateEmployeeToken = (obj: any): obj is EmployeeTokenObject => {
|
||||
return (
|
||||
typeof obj === 'object' &&
|
||||
obj !== null &&
|
||||
typeof obj.user_type === 'number' &&
|
||||
typeof obj.user_uu_id === 'string' &&
|
||||
typeof obj.user_id === 'number' &&
|
||||
typeof obj.person_id === 'number' &&
|
||||
typeof obj.person_uu_id === 'string' &&
|
||||
Array.isArray(obj.companies_id_list) &&
|
||||
Array.isArray(obj.companies_uu_id_list) &&
|
||||
Array.isArray(obj.duty_id_list) &&
|
||||
Array.isArray(obj.duty_uu_id_list)
|
||||
);
|
||||
};
|
||||
const empToken: EmployeeTokenObject = {
|
||||
...redis_object,
|
||||
is_employee: true,
|
||||
is_occupant: false,
|
||||
user_type: UserType.employee,
|
||||
credential_token: redis_object.credential_token || '',
|
||||
};
|
||||
if (!validateEmployeeToken(empToken)) {
|
||||
throw new Error(
|
||||
'Invalid Redis object: Does not match EmployeeTokenObject interface',
|
||||
);
|
||||
}
|
||||
return empToken;
|
||||
}
|
||||
|
||||
if (redis_object.user_type === UserType.occupant) {
|
||||
const validateOccupantToken = (obj: any): obj is OccupantTokenObject => {
|
||||
return (
|
||||
typeof obj === 'object' &&
|
||||
obj !== null &&
|
||||
typeof obj.user_type === 'number' &&
|
||||
typeof obj.user_uu_id === 'string' &&
|
||||
typeof obj.user_id === 'number' &&
|
||||
typeof obj.person_id === 'number' &&
|
||||
typeof obj.person_uu_id === 'string'
|
||||
);
|
||||
};
|
||||
const occToken: OccupantTokenObject = {
|
||||
...redis_object,
|
||||
is_employee: false,
|
||||
is_occupant: true,
|
||||
user_type: UserType.occupant,
|
||||
credential_token: redis_object.credential_token || '',
|
||||
available_occupants: redis_object.available_occupants || null,
|
||||
};
|
||||
if (!validateOccupantToken(occToken)) {
|
||||
throw new Error(
|
||||
'Invalid Redis object: Does not match OccupantTokenObject interface',
|
||||
);
|
||||
}
|
||||
return occToken;
|
||||
}
|
||||
throw new Error(`Invalid user_type: ${redis_object.user_type}`);
|
||||
generateAccessToken() {
|
||||
return this.passwordService.generateAccessToken();
|
||||
}
|
||||
|
||||
async get_object_from_redis(access_token: string): Promise<TokenDictType> {
|
||||
const token = await this.cacheService.get(access_token);
|
||||
return this.process_redis_object(token);
|
||||
async getLoginFromRedis(redisKey: string): Promise<AuthToken> {
|
||||
return this.cacheService.get(redisKey);
|
||||
}
|
||||
|
||||
async set_login_to_redis(user: users, token: TokenDictType): Promise<any> {
|
||||
const generated_token = this.passwordService.generateAccessToken();
|
||||
const listKeys = [this.AUTH_TOKEN, generated_token, user.uu_id];
|
||||
await this.cacheService.set_with_ttl(
|
||||
this.cacheService.createRegexPattern(listKeys),
|
||||
token,
|
||||
60 * 60 * 24,
|
||||
);
|
||||
return generated_token;
|
||||
async getSelectFromRedis(redisKey: string): Promise<TokenDictInterface> {
|
||||
return this.cacheService.get(redisKey);
|
||||
}
|
||||
|
||||
async update_token_via_token(token: string, additional: any): Promise<any> {
|
||||
const listKeys = [this.AUTH_TOKEN, token, '*'];
|
||||
const accessObject = await this.cacheService.get_with_keys(listKeys);
|
||||
if (!accessObject) throw new Error('Token not found');
|
||||
const processedObject: TokenDictType =
|
||||
await this.process_redis_object(accessObject);
|
||||
if (processedObject.is_employee) {
|
||||
processedObject.selected = additional;
|
||||
}
|
||||
if (processedObject.is_occupant) {
|
||||
processedObject.selected = additional;
|
||||
}
|
||||
const listKeysNew = [this.AUTH_TOKEN, token, processedObject.user_uu_id];
|
||||
await this.cacheService.set_with_ttl(
|
||||
this.cacheService.createRegexPattern(listKeysNew),
|
||||
processedObject,
|
||||
60 * 60 * 24,
|
||||
);
|
||||
return token;
|
||||
async renewTtlLoginFromRedis(redisKey: string): Promise<any> {
|
||||
const token = await this.getLoginFromRedis(redisKey);
|
||||
return this.cacheService.set_with_ttl(redisKey, token, 60 * 30);
|
||||
}
|
||||
|
||||
async renewTtlSelectFromRedis(redisKey: string): Promise<any> {
|
||||
const token = await this.getSelectFromRedis(redisKey);
|
||||
return this.cacheService.set_with_ttl(redisKey, token, 60 * 30);
|
||||
}
|
||||
|
||||
async setLoginToRedis(token: AuthToken, userUUID: string): Promise<any> {
|
||||
const accessToken = this.generateAccessToken();
|
||||
const redisKey = `${this.AUTH_TOKEN}:${accessToken}:${accessToken}:${userUUID}:${userUUID}`;
|
||||
await this.cacheService.set_with_ttl(redisKey, token, 60 * 30);
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
async setSelectToRedis(
|
||||
accessToken: string,
|
||||
token: TokenDictInterface,
|
||||
userUUID: string,
|
||||
livingUUID: string,
|
||||
): Promise<any> {
|
||||
const selectToken = this.generateSelectToken(accessToken, userUUID);
|
||||
const redisKey = `${this.AUTH_TOKEN}:${accessToken}:${selectToken}:${userUUID}:${livingUUID}`;
|
||||
await this.cacheService.set_with_ttl(redisKey, token, 60 * 30);
|
||||
return selectToken;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
import { INestApplication, RequestMethod } from '@nestjs/common';
|
||||
import { ModulesContainer, Reflector } from '@nestjs/core';
|
||||
import { PATH_METADATA, METHOD_METADATA } from '@nestjs/common/constants';
|
||||
import { PrismaService } from '@/src/prisma.service';
|
||||
|
||||
/**
|
||||
* Helper: Method string'i döndür
|
||||
*/
|
||||
function getMethodString(requestMethod: RequestMethod): string {
|
||||
return RequestMethod[requestMethod];
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: Path'leri normalize et (iki tane slash varsa düzelt)
|
||||
*/
|
||||
function normalizePath(...paths: string[]): string {
|
||||
const normalized =
|
||||
'/' +
|
||||
paths
|
||||
.filter(Boolean)
|
||||
.map((p) => p.replace(/^\/|\/$/g, ''))
|
||||
.filter((p) => p.length > 0)
|
||||
.join('/');
|
||||
|
||||
return normalized === '/' ? '' : normalized; // Home route'ı dışla
|
||||
}
|
||||
|
||||
export async function extractAndPersistRoutes(
|
||||
app: INestApplication,
|
||||
prisma: PrismaService,
|
||||
): Promise<{ method: string; url: string }[]> {
|
||||
const modulesContainer = app.get(ModulesContainer);
|
||||
const reflector = app.get(Reflector);
|
||||
const routes: { method: string; url: string }[] = [];
|
||||
|
||||
modulesContainer.forEach((moduleRef) => {
|
||||
const controllers = [...moduleRef.controllers.values()];
|
||||
controllers.forEach(({ metatype }) => {
|
||||
if (!metatype || typeof metatype !== 'function') return;
|
||||
|
||||
const controllerPath =
|
||||
reflector.get<string>(PATH_METADATA, metatype) ?? '';
|
||||
const prototype = metatype.prototype;
|
||||
|
||||
const methodNames = Object.getOwnPropertyNames(prototype).filter(
|
||||
(m) => m !== 'constructor',
|
||||
);
|
||||
|
||||
methodNames.forEach((methodName) => {
|
||||
const methodRef = prototype[methodName];
|
||||
const routePath = reflector.get<string>(PATH_METADATA, methodRef);
|
||||
const requestMethod = reflector.get<RequestMethod>(
|
||||
METHOD_METADATA,
|
||||
methodRef,
|
||||
);
|
||||
|
||||
if (routePath !== undefined && requestMethod !== undefined) {
|
||||
const method = getMethodString(requestMethod);
|
||||
const fullPath = normalizePath(controllerPath, routePath);
|
||||
if (fullPath !== '') {
|
||||
routes.push({ method, url: fullPath });
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const existing = await prisma.endpoint_restriction.findMany({
|
||||
select: { endpoint_name: true, endpoint_method: true },
|
||||
});
|
||||
|
||||
const existingSet = new Set(
|
||||
existing.map((r) => `${r.endpoint_method}_${r.endpoint_name}`),
|
||||
);
|
||||
|
||||
const newOnes = routes.filter(
|
||||
(r) => !existingSet.has(`${r.method}_${r.url}`),
|
||||
);
|
||||
|
||||
// İsteğe bağlı: veritabanına kaydet
|
||||
// for (const route of newOnes) {
|
||||
// await prisma.endpoint_restriction.create({
|
||||
// data: {
|
||||
// endpoint_method: route.method,
|
||||
// endpoint_name: route.url,
|
||||
// is_active: true,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
console.log('🧭 Route JSON Listesi:');
|
||||
console.dir(routes, { depth: null });
|
||||
|
||||
return routes;
|
||||
}
|
||||
|
|
@ -1,9 +1,18 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { PaginationHelper } from './pagination-helper';
|
||||
import { PrismaService } from '@/src/prisma.service';
|
||||
import { RedisHandlers } from './auth/redis_handlers';
|
||||
import { PasswordHandlers } from './auth/login_handler';
|
||||
import { CacheService } from '@/src/cache.service';
|
||||
|
||||
@Module({
|
||||
providers: [PaginationHelper, PrismaService],
|
||||
exports: [PaginationHelper],
|
||||
providers: [
|
||||
PaginationHelper,
|
||||
PrismaService,
|
||||
RedisHandlers,
|
||||
PasswordHandlers,
|
||||
CacheService,
|
||||
],
|
||||
exports: [PaginationHelper, RedisHandlers, PasswordHandlers, CacheService],
|
||||
})
|
||||
export class UtilsModule {}
|
||||
|
|
|
|||
Loading…
Reference in New Issue