diff --git a/ServicesApi/prisma/schema.prisma b/ServicesApi/prisma/schema.prisma index b178116..f320305 100644 --- a/ServicesApi/prisma/schema.prisma +++ b/ServicesApi/prisma/schema.prisma @@ -1932,6 +1932,20 @@ model build_ibans { @@index([updated_at], map: "ix_build_ibans_updated_at") } +model user_types { + id Int @id @default(autoincrement()) + uu_id String @unique(map: "ix_user_types_uu_id") @default(dbgenerated("gen_random_uuid()")) @db.Uuid + type String @db.VarChar + description String @default("") @db.VarChar + type_token String @default("") @db.VarChar + token String @default("") @db.VarChar + occupant_types occupant_types[] + staff staff[] + + @@index([type], map: "ix_user_types_type") + @@index([token], map: "ix_user_types_token") +} + /// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments model build_living_space { fix_value Decimal @default(0) @db.Decimal(20, 6) @@ -3081,6 +3095,8 @@ model occupant_types { occupant_category String @default("") @db.VarChar occupant_category_type String @default("") @db.VarChar function_retriever String @default("") @db.VarChar + user_type_id Int? + user_type_uu_id String? @db.VarChar occupant_is_unique Boolean @default(false) ref_id String? @db.VarChar(100) replication_id Int @default(0) @db.SmallInt @@ -3103,6 +3119,7 @@ model occupant_types { build_decision_book_person_occupants build_decision_book_person_occupants[] build_living_space build_living_space[] build_management build_management[] + user_types user_types? @relation(fields: [user_type_id], references: [id], onDelete: NoAction, onUpdate: NoAction) @@index([created_at], map: "ix_occupant_types_created_at") @@index([cryp_uu_id], map: "ix_occupant_types_cryp_uu_id") @@ -3475,7 +3492,9 @@ model staff { staff_code String @db.VarChar duties_id Int duties_uu_id String @db.VarChar - function_retriever String @default("") @db.VarChar + // function_retriever String @default("") @db.VarChar + user_type_id Int? + user_type_uu_id String? @db.VarChar ref_id String? @db.VarChar(100) replication_id Int @default(0) @db.SmallInt cryp_uu_id String? @db.VarChar @@ -3497,6 +3516,7 @@ model staff { employee_history employee_history[] employees employees[] duties duties @relation(fields: [duties_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + user_type user_types? @relation(fields: [user_type_id], references: [id], onDelete: NoAction, onUpdate: NoAction) @@index([created_at], map: "ix_staff_created_at") @@index([cryp_uu_id], map: "ix_staff_cryp_uu_id") diff --git a/ServicesApi/src/accounts/accounts.controller.ts b/ServicesApi/src/accounts/accounts.controller.ts index c4dc5bf..0def4c7 100644 --- a/ServicesApi/src/accounts/accounts.controller.ts +++ b/ServicesApi/src/accounts/accounts.controller.ts @@ -8,35 +8,44 @@ import { Body, HttpCode, UseGuards, + ForbiddenException, + Req, + Query, } from '@nestjs/common'; import { AccountsService } from './accounts.service'; import { AuthControlGuard, EndpointControlGuard } from '../middleware/access-control.guard'; @Controller('accounts') export class AccountsController { - constructor(private accountsService: AccountsService) {} + constructor(private accountsService: AccountsService) { } + + + @Get('events') + @HttpCode(200) + @UseGuards(AuthControlGuard, EndpointControlGuard) + async getEvents(@Query() query: any) { + const { url, func } = query; + const events = await this.accountsService.infoEvents(url, func); + return { + events, + message: "Events fetched successfully", + } + } + @Post('filter') @HttpCode(200) @UseGuards(AuthControlGuard, EndpointControlGuard) - async filterAccounts(@Body() query: any) { - const result = await this.accountsService.findWithPagination(query); - const { pagination, data } = result; - - if (data.length === 0) { - return { pagination, data: [] }; + async filterAccounts(@Body() query: any, @Req() req: any) { + const driveToken = req.driveToken + const redirectToService = await this.accountsService.getEvents(); + console.log('redirectToService', redirectToService); + try { + const functionToCall = redirectToService[driveToken]; + return await functionToCall(query); + } catch (error) { + console.error('Error redirecting to service:', error); + throw new ForbiddenException(`This user is not allowed to access this endpoint. Please contact your system administrator.`); } - - const resultRefined = data.map((rec: any) => ({ - ...rec, - build_decision_book_payments: rec.build_decision_book_payments?.map( - (pmt: any) => ({ - ...pmt, - ratePercent: - ((pmt.payment_amount / rec.currency_value) * 100).toFixed(2) + '%', - }), - ), - })); - return { pagination, data: resultRefined }; } } diff --git a/ServicesApi/src/accounts/accounts.module.ts b/ServicesApi/src/accounts/accounts.module.ts index 8380666..a2a1f17 100644 --- a/ServicesApi/src/accounts/accounts.module.ts +++ b/ServicesApi/src/accounts/accounts.module.ts @@ -8,6 +8,7 @@ import { AuthControlGuard, EndpointControlGuard, } from '@/src/middleware/access-control.guard'; +import { SuperUsersService } from './superusers/superusers.service'; @Module({ imports: [PrismaModule, UtilsModule], @@ -16,7 +17,17 @@ import { CacheService, AuthControlGuard, EndpointControlGuard, + SuperUsersService, ], controllers: [AccountsController], }) -export class AccountsModule {} +export class AccountsModule { + constructor( + private accountsService: AccountsService, + ) { } + + async onModuleInit() { + const accountEvents = await this.accountsService.infoEvents(); + console.dir(accountEvents, { depth: null }); + } +} diff --git a/ServicesApi/src/accounts/accounts.service.ts b/ServicesApi/src/accounts/accounts.service.ts index cdb898a..6b47d01 100644 --- a/ServicesApi/src/accounts/accounts.service.ts +++ b/ServicesApi/src/accounts/accounts.service.ts @@ -1,42 +1,80 @@ import { Injectable } from '@nestjs/common'; -import { PrismaService } from '@/src/prisma.service'; -import { Prisma, account_records } from '@prisma/client'; -import { CacheService } from '../cache.service'; -import { PaginationHelper, PaginationInfo } from '../utils/pagination-helper'; +import { PaginationInfo } from '../utils/pagination-helper'; +import { SuperUsersService } from './superusers/superusers.service'; +import crypto from 'crypto'; @Injectable() export class AccountsService { constructor( - private prisma: PrismaService, - private cacheService: CacheService, - private paginationHelper: PaginationHelper, - ) {} + private superUsersService: SuperUsersService, + ) { } + events = { + "/accounts/filter:GQKQshahQhGm8HYy4O4Tgx": [ + { + "key": "s8OnSnHoQfyfuDk7A1XRww", + "description": "Super Users Filter", + "isDefault": true, + "query": { "query": true, "page": false, "pageSize": false }, + "token": "GQKQshahQhGm8HYy4O4Tgx", + "pages": ["accounts"] + // "type": "EMP", + // "fr": "SuperUserEmployee", + } + ], + "/accounts/read:GQKQshahQhGm8HYy4O4Tgx": [ + { + "key": "s8OnSnHoQfyfuDk7A1XRww", + "description": "Super Users Read", + "isDefault": true, + "query": { "query": true, "page": false, "pageSize": false }, + "token": "GQKQshahQhGm8HYy4O4Tgx", + "pages": ["accounts"] + // "type": "EMP", + // "fr": "SuperUserEmployee", + } + ] + }; - async findAll(filter: any): Promise[]> { - return this.prisma.account_records.findMany({ - where: { ...filter }, - }); + createSecureKeyWithoutLib(url: string) { + const subString = crypto.createHash('sha256').update(url).digest().toString('base64').substring(0, 16) + return subString.replace(/=/g, 'E').replace(/-/g, 'M').replace(/_/g, 'N').replace(/\+/g, 'P').replace(/\//g, 'Q') } - async findDynamic( - query: Prisma.account_recordsFindManyArgs, - ): Promise<{ totalCount: number; result: Partial[] }> { - const totalCount = await this.prisma.account_records.count({ - where: query.where, - }); - const result = await this.prisma.account_records.findMany(query); - return { totalCount, result }; + async infoEvents(urlRetriever: string | null = null, functionRetriever: string | null = null) { + const events = this.events; + if (urlRetriever && !functionRetriever) { + if (events[urlRetriever]) { + return [[urlRetriever, events[urlRetriever]]]; + } + return []; + } else if (urlRetriever && functionRetriever) { + if (events[urlRetriever] && events[urlRetriever][functionRetriever]) { + return [[urlRetriever, { [functionRetriever]: events[urlRetriever][functionRetriever] }]]; + } + return []; + } else if (!urlRetriever && functionRetriever) { + const filteredEvents: [string, any][] = []; + Object.entries(events).forEach(([url, urlEvents]) => { + if (urlEvents[functionRetriever]) { + filteredEvents.push([url, { [functionRetriever]: urlEvents[functionRetriever] }]); + } + }); + return filteredEvents; + } else { + return Object.entries(events); + } } - async findWithPagination( - query: any & { page?: number; pageSize?: number }, - ): Promise<{ data: any[]; pagination: PaginationInfo }> { - return this.paginationHelper.paginate(this.prisma.account_records, query); + async getEvents() { + return { + "/accounts/filter:GQKQshahQhGm8HYy4O4Tgx:s8OnSnHoQfyfuDk7A1XRww": (query: any) => this.supersUserFilter(query), + "/accounts/read:a5b6d9c716f409a7004a:tcc116f409a7004a": (query: any) => this.supersUserFilter(query) + }; } - async findOne(uuid: string): Promise | null> { - return this.prisma.account_records.findUnique({ - where: { uu_id: uuid }, - }); + + async supersUserFilter(query: any & { page?: number; pageSize?: number }): Promise<{ pagination: PaginationInfo; data: any[] }> { + return this.superUsersService.filter(query); } + } diff --git a/ServicesApi/src/accounts/superusers/superusers.service.spec.ts b/ServicesApi/src/accounts/superusers/superusers.service.spec.ts new file mode 100644 index 0000000..ba2f59d --- /dev/null +++ b/ServicesApi/src/accounts/superusers/superusers.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { SuperusersService } from './superusers.service'; + +describe('SuperusersService', () => { + let service: SuperusersService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [SuperusersService], + }).compile(); + + service = module.get(SuperusersService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/ServicesApi/src/accounts/superusers/superusers.service.ts b/ServicesApi/src/accounts/superusers/superusers.service.ts new file mode 100644 index 0000000..f65071d --- /dev/null +++ b/ServicesApi/src/accounts/superusers/superusers.service.ts @@ -0,0 +1,30 @@ +import { PaginationHelper } from '@/src/utils/pagination-helper'; +import { Injectable } from '@nestjs/common'; +import { PaginationInfo } from '@/src/utils/pagination-helper'; +import { PrismaService } from '@/src/prisma.service'; + +@Injectable() +export class SuperUsersService { + constructor( + private paginationHelper: PaginationHelper, + private prisma: PrismaService, + ) { } + + async filter(query: any & { page?: number; pageSize?: number }): Promise<{ pagination: PaginationInfo; data: any[] }> { + console.log("supersServiceFilter query", query) + const result = await this.paginationHelper.findWithPagination(query, this.prisma.account_records); + const { pagination, data } = result; + + if (data.length === 0) { return { pagination, data: [] } } + const resultRefined = data.map((rec: any) => ({ + ...rec, + build_decision_book_payments: rec.build_decision_book_payments?.map( + (pmt: any) => ({ + ...pmt, + ratePercent: ((pmt.payment_amount / rec.currency_value) * 100).toFixed(2) + '%', + }), + ), + })); + return { pagination, data: resultRefined }; + } +} diff --git a/ServicesApi/src/middleware/access-control.guard.ts b/ServicesApi/src/middleware/access-control.guard.ts index 44ea175..61285f5 100644 --- a/ServicesApi/src/middleware/access-control.guard.ts +++ b/ServicesApi/src/middleware/access-control.guard.ts @@ -8,7 +8,7 @@ import { RedisHandlers } from '@/src/utils/auth/redis_handlers'; @Injectable() export class AuthControlGuard implements CanActivate { - constructor(private cacheService: RedisHandlers) {} + constructor(private cacheService: RedisHandlers) { } async canActivate(context: ExecutionContext): Promise { const req = context.switchToHttp().getRequest(); @@ -20,15 +20,18 @@ export class AuthControlGuard implements CanActivate { @Injectable() export class EndpointControlGuard implements CanActivate { - constructor(private cacheService: RedisHandlers) {} + constructor(private cacheService: RedisHandlers) { } async canActivate(context: ExecutionContext): Promise { const req = context.switchToHttp().getRequest(); // const selectToken = this.cacheService.mergeSelectKey(req); - // const method = req.method; - // const path = req.route?.path; - const accessObject = await this.cacheService.getSelectFromRedis(req); - console.log('EndpointControlGuard', accessObject); + const method = req.method; + const path = req.route?.path; + console.log('EndpointControlGuard', method, 'path', path); + // const accessObject = await this.cacheService.getSelectFromRedis(req); + // console.log('EndpointControlGuard', accessObject); + req.driveToken = "c5b6d9c7-9115-4825-bcc1-16f409a7004a" + // console.log('EndpointControlGuard', req.driveToken); return true; } } diff --git a/ServicesApi/src/utils/pagination-helper.ts b/ServicesApi/src/utils/pagination-helper.ts index 5e9b931..31c21d4 100644 --- a/ServicesApi/src/utils/pagination-helper.ts +++ b/ServicesApi/src/utils/pagination-helper.ts @@ -18,7 +18,7 @@ type ModelDelegate = { @Injectable() export class PaginationHelper { - constructor(private prisma: PrismaService) {} + constructor(private prisma: PrismaService) { } /** * Sayfalama destekli sorgu yapar @@ -55,4 +55,12 @@ export class PaginationHelper { }, }; } + + async findWithPagination( + query: any & { page?: number; pageSize?: number }, + service: ModelDelegate, + ): Promise<{ data: any[]; pagination: PaginationInfo }> { + console.log("findWithPagination query", query) + return this.paginate(service, query); + } } diff --git a/ServicesFrontEnd/frontend/src/app/api/backend/pages/route.ts b/ServicesFrontEnd/frontend/src/app/api/backend/pages/route.ts new file mode 100644 index 0000000..a887621 --- /dev/null +++ b/ServicesFrontEnd/frontend/src/app/api/backend/pages/route.ts @@ -0,0 +1,9 @@ +import { NextRequest, NextResponse } from "next/server"; + +export async function POST(req: NextRequest) { + const { type } = await req.json(); +} + +export async function GET(req: NextRequest, { params }: { params: Promise<{ type: string }> }) { + const { type } = await params; +} \ No newline at end of file