From 1cf3b7fa6049b5d20d74220e8ae7780fe9aaa71b Mon Sep 17 00:00:00 2001 From: mit-27 Date: Mon, 20 May 2024 15:47:05 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=97=83=EF=B8=8F=20Add=20backend=20for=20d?= =?UTF-8?q?ynamic-catalog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/api/prisma/schema.prisma | 16 ++- packages/api/scripts/init.sql | 14 +++ .../catalog-options.controller.ts | 69 +++++++++++ .../catalog-options/catalog-options.module.ts | 11 ++ .../catalog-options.service.ts | 107 ++++++++++++++++++ .../dto/catalog-options.dto.ts | 8 ++ packages/api/src/@core/core.module.ts | 5 +- packages/api/swagger/swagger-spec.json | 64 +++++++++++ 8 files changed, 289 insertions(+), 5 deletions(-) create mode 100644 packages/api/src/@core/catalog-options/catalog-options.controller.ts create mode 100644 packages/api/src/@core/catalog-options/catalog-options.module.ts create mode 100644 packages/api/src/@core/catalog-options/catalog-options.service.ts create mode 100644 packages/api/src/@core/catalog-options/dto/catalog-options.dto.ts diff --git a/packages/api/prisma/schema.prisma b/packages/api/prisma/schema.prisma index 36d9d8311..4fc74f331 100644 --- a/packages/api/prisma/schema.prisma +++ b/packages/api/prisma/schema.prisma @@ -64,16 +64,17 @@ model tcg_users { /// 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 users { - id_user String @id(map: "pk_users") @db.Uuid + id_user String @id(map: "pk_users") @db.Uuid identification_strategy String email String? password_hash String? first_name String last_name String - id_stytch String? @unique(map: "force_stytch_id_unique") - created_at DateTime @default(now()) @db.Timestamp(6) - modified_at DateTime @default(now()) @db.Timestamp(6) + id_stytch String? @unique(map: "force_stytch_id_unique") + created_at DateTime @default(now()) @db.Timestamp(6) + modified_at DateTime @default(now()) @db.Timestamp(6) api_keys api_keys[] + catalog_options catalog_options[] projects projects[] } @@ -639,3 +640,10 @@ model webhook_delivery_attempts { @@index([id_event], map: "fk_webhook_delivery_attempt_eventid") @@index([id_webhooks_reponse], map: "fk_webhook_delivery_attempt_webhook_responseid") } + +model catalog_options { + id_catalog_option String @id(map: "pk_catalog_options") @db.Uuid + id_user String @db.Uuid + selected_catalog String + users users @relation(fields: [id_user], references: [id_user], onDelete: NoAction, onUpdate: NoAction, map: "fk_catalog_option_user") +} diff --git a/packages/api/scripts/init.sql b/packages/api/scripts/init.sql index 8f5d2e92c..a075a0778 100644 --- a/packages/api/scripts/init.sql +++ b/packages/api/scripts/init.sql @@ -1,4 +1,6 @@ + + -- ************************************** webhooks_reponses CREATE TABLE webhooks_reponses @@ -88,6 +90,18 @@ COMMENT ON COLUMN users.created_at IS 'DEFAULT NOW() to automatically insert a v COMMENT ON CONSTRAINT force_stytch_id_unique ON users IS 'force unique on stytch id'; +-- ************************************** catalog_options + +CREATE TABLE catalog_options +( + id_catalog_option uuid NOT NULL, + id_user uuid NOT NULL, + selected_catalog text NOT NULL, + CONSTRAINT PK_catalog_options PRIMARY KEY ( id_catalog_option ), + CONSTRAINT FK_catalog_option_user FOREIGN KEY ( id_user ) REFERENCES users ( id_user ) +); + + diff --git a/packages/api/src/@core/catalog-options/catalog-options.controller.ts b/packages/api/src/@core/catalog-options/catalog-options.controller.ts new file mode 100644 index 000000000..1af723a38 --- /dev/null +++ b/packages/api/src/@core/catalog-options/catalog-options.controller.ts @@ -0,0 +1,69 @@ +import { + Body, + Controller, + Get, + Post, + Query, + UseGuards, + Request, +} from '@nestjs/common'; +import { LoggerService } from '../logger/logger.service'; +import { + ApiBody, + ApiOperation, + ApiQuery, + ApiResponse, + ApiTags, +} from '@nestjs/swagger'; +import { CatalogOptionsService } from './catalog-options.service'; +import { CreateCatalogOptionsDto } from './dto/catalog-options.dto'; +import { JwtAuthGuard } from '@@core/auth/guards/jwt-auth.guard'; + + +@ApiTags('catalog-options') +@Controller('catalog-options') +export class CatalogOptionsController { + constructor( + private readonly catalogOptionsService: CatalogOptionsService, + private logger: LoggerService, + ) { + this.logger.setContext(CatalogOptionsController.name); + } + + @ApiOperation({ operationId: 'CreateCatalogOptions', summary: 'Add or Update Catalog' }) + @ApiBody({ type: CreateCatalogOptionsDto }) + @ApiResponse({ status: 201 }) + @UseGuards(JwtAuthGuard) + @Post() + addCatalogOptions(@Body() catalogOptionsDto: CreateCatalogOptionsDto) { + return this.catalogOptionsService.createCatalogOptions(catalogOptionsDto); + } + + + // It should be public API and don't have to add AuthGuard + @ApiOperation({ + operationId: 'getCatalog', + summary: 'Retrieve a Catalog Options by Project ID', + }) + @ApiQuery({ name: 'projectID', required: true, type: String }) + @ApiResponse({ status: 200 }) + @Get('single') + getLinkedUser(@Query('projectID') id: string) { + // validate project_id against user + return this.catalogOptionsService.getCatalogByProjectId(id); + } + + @ApiOperation({ + operationId: 'getCatalog', + summary: 'Retrieve a Catalog Options by User ID', + }) + @ApiQuery({ name: 'userID', required: true, type: String }) + @ApiResponse({ status: 200 }) + @UseGuards(JwtAuthGuard) + @Get('single') + getLinkedUserV2(@Query('userID') id: string) { + // validate project_id against user + return this.catalogOptionsService.getCatalogByUserId(id); + } + +} \ No newline at end of file diff --git a/packages/api/src/@core/catalog-options/catalog-options.module.ts b/packages/api/src/@core/catalog-options/catalog-options.module.ts new file mode 100644 index 000000000..a43f34472 --- /dev/null +++ b/packages/api/src/@core/catalog-options/catalog-options.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { CatalogOptionsService } from './catalog-options.service'; +import { CatalogOptionsController } from './catalog-options.controller'; +import { LoggerService } from '../logger/logger.service'; +import { PrismaService } from '../prisma/prisma.service'; + +@Module({ + providers: [CatalogOptionsService, LoggerService, PrismaService], + controllers: [CatalogOptionsController], +}) +export class CatalogOptionsModule { } diff --git a/packages/api/src/@core/catalog-options/catalog-options.service.ts b/packages/api/src/@core/catalog-options/catalog-options.service.ts new file mode 100644 index 000000000..8447844f1 --- /dev/null +++ b/packages/api/src/@core/catalog-options/catalog-options.service.ts @@ -0,0 +1,107 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { PrismaService } from '../prisma/prisma.service'; +import { LoggerService } from '../logger/logger.service'; +import { v4 as uuidv4 } from 'uuid'; +import { handleServiceError } from '@@core/utils/errors'; +import { CreateCatalogOptionsDto } from './dto/catalog-options.dto'; + +@Injectable() +export class CatalogOptionsService { + constructor(private prisma: PrismaService, private logger: LoggerService) { + this.logger.setContext(CatalogOptionsService.name); + } + + async createCatalogOptions(data: CreateCatalogOptionsDto) { + try { + const { id_user, selected_catalog } = data; + const existingCatalogOptions = await this.prisma.catalog_options.findFirst({ + where: { + id_user + } + }); + + if (!existingCatalogOptions) { + const res = await this.prisma.catalog_options.create({ + data: { + id_catalog_option: uuidv4(), + selected_catalog: selected_catalog, + id_user: id_user + } + }); + + return res; + } + const res = await this.prisma.catalog_options.update({ + where: { + id_catalog_option: existingCatalogOptions.id_catalog_option + }, + data: { + selected_catalog: selected_catalog + } + }); + + return res; + + } catch (error) { + handleServiceError(error, this.logger); + } + } + + async getCatalogByProjectId(id_project: string) { + try { + const user = await this.prisma.projects.findFirst({ + where: { + id_project + }, + select: { + id_user: true + } + }); + + if (!user) { + throw new NotFoundException("Project Id does not exist!") + } + + const res = await this.prisma.catalog_options.findFirst({ + where: { + id_user: user.id_user + } + }); + if (!res) { + throw new NotFoundException("Catalog Options not found for current User!") + } + + return res + + + } catch (error) { + handleServiceError(error, this.logger); + } + } + + + async getCatalogByUserId(id_user: string) { + + try { + + const res = await this.prisma.catalog_options.findFirst({ + where: { + id_user: id_user + } + }); + if (!res) { + throw new NotFoundException("Catalog Options not found for current User!") + } + + return res; + + + } catch (error) { + handleServiceError(error, this.logger); + } + + } + + + +} diff --git a/packages/api/src/@core/catalog-options/dto/catalog-options.dto.ts b/packages/api/src/@core/catalog-options/dto/catalog-options.dto.ts new file mode 100644 index 000000000..f178af5a2 --- /dev/null +++ b/packages/api/src/@core/catalog-options/dto/catalog-options.dto.ts @@ -0,0 +1,8 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class CreateCatalogOptionsDto { + @ApiProperty() + id_user: string; + @ApiProperty() + selected_catalog: string; +} diff --git a/packages/api/src/@core/core.module.ts b/packages/api/src/@core/core.module.ts index cb2233734..a0420cc90 100644 --- a/packages/api/src/@core/core.module.ts +++ b/packages/api/src/@core/core.module.ts @@ -13,6 +13,7 @@ import { EnvironmentModule } from './environment/environment.module'; import { EncryptionService } from './encryption/encryption.service'; import { ConnectionsStrategiesModule } from './connections-strategies/connections-strategies.module'; import { SyncModule } from './sync/sync.module'; +import { CatalogOptionsModule } from './catalog-options/catalog-options.module'; @Module({ imports: [ @@ -29,6 +30,7 @@ import { SyncModule } from './sync/sync.module'; EnvironmentModule, ConnectionsStrategiesModule, SyncModule, + CatalogOptionsModule ], exports: [ AuthModule, @@ -44,7 +46,8 @@ import { SyncModule } from './sync/sync.module'; EnvironmentModule, ConnectionsStrategiesModule, SyncModule, + CatalogOptionsModule ], providers: [EncryptionService], }) -export class CoreModule {} +export class CoreModule { } diff --git a/packages/api/swagger/swagger-spec.json b/packages/api/swagger/swagger-spec.json index 44f7aa6ab..dc6054299 100644 --- a/packages/api/swagger/swagger-spec.json +++ b/packages/api/swagger/swagger-spec.json @@ -4172,6 +4172,55 @@ ] } }, + "/catalog-options": { + "post": { + "operationId": "CreateCatalogOptions", + "summary": "Add or Update Catalog", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateCatalogOptionsDto" + } + } + } + }, + "responses": { + "201": { + "description": "" + } + }, + "tags": [ + "catalog-options" + ] + } + }, + "/catalog-options/single": { + "get": { + "operationId": "getCatalog", + "summary": "Retrieve a Catalog Options by User ID", + "parameters": [ + { + "name": "userID", + "required": true, + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "" + } + }, + "tags": [ + "catalog-options" + ] + } + }, "/ticketing/attachments": { "get": { "operationId": "getAttachments", @@ -6122,6 +6171,21 @@ "field_mappings" ] }, + "CreateCatalogOptionsDto": { + "type": "object", + "properties": { + "id_user": { + "type": "string" + }, + "selected_catalog": { + "type": "string" + } + }, + "required": [ + "id_user", + "selected_catalog" + ] + }, "UnifiedAttachmentInput": { "type": "object", "properties": {