diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma index c1947b34..229b7290 100644 --- a/backend/prisma/schema.prisma +++ b/backend/prisma/schema.prisma @@ -1,15 +1,41 @@ generator client { - provider = "prisma-client-js" + provider = "prisma-client-js" previewFeatures = ["metrics"] } datasource db { provider = "postgresql" - url = env("DATABASE_URL") + url = env("POSTGRESQL_URL") } -model users { - id Decimal @id(map: "USER_PK") @default(dbgenerated("nextval('\"USER_SEQ\"'::regclass)")) @db.Decimal - name String @db.VarChar(200) - email String @db.VarChar(200) +/// 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 submission_status_code { + submission_status_code String @id(map: "submission_status_code_pk") @db.VarChar(20) + description String @db.VarChar(250) + display_order Int + active_ind Boolean @default(true) + create_user_id String @db.VarChar(200) + create_utc_timestamp DateTime @db.Timestamp(6) + update_user_id String @db.VarChar(200) + update_utc_timestamp DateTime @db.Timestamp(6) + file_submissions_file_submissions_submission_status_codeTosubmission_status_code file_submissions[] @relation("file_submissions_submission_status_codeTosubmission_status_code") +} + +model file_submissions { + submission_id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid + file_name String @db.VarChar(200) + submission_date DateTime @db.Timestamp(6) + submitter_user_id String @db.VarChar(200) + submission_status_code String @db.VarChar(10) + submitter_agency_name String @db.VarChar(200) + sample_count Int? + results_count Int? + active_ind Boolean @default(true) + error_log String? + organization_guid String? @db.Uuid + create_user_id String @db.VarChar(200) + create_utc_timestamp DateTime @db.Timestamp(6) + update_user_id String @db.VarChar(200) + update_utc_timestamp DateTime @db.Timestamp(6) + submission_status_code_file_submissions_submission_status_codeTosubmission_status_code submission_status_code @relation("file_submissions_submission_status_codeTosubmission_status_code", fields: [submission_status_code], references: [submission_status_code], onDelete: NoAction, onUpdate: NoAction, map: "submission_status_code_fk") } diff --git a/backend/src/app.module.ts b/backend/src/app.module.ts index 23a85011..0a7d94b1 100644 --- a/backend/src/app.module.ts +++ b/backend/src/app.module.ts @@ -15,6 +15,7 @@ import { TerminusModule } from "@nestjs/terminus"; import { HealthController } from "./health.controller"; import { JWTAuthModule } from "./auth/jwtauth.module"; import { AdminModule } from "./admin/admin.module"; +import { DryrunModule } from "./dryrun/dryrun.module"; const DB_HOST = process.env.POSTGRES_HOST || "localhost"; const DB_USER = process.env.POSTGRES_USER || "postgres"; @@ -52,6 +53,7 @@ function getMiddlewares() { middlewares: getMiddlewares(), }, }), + DryrunModule, JWTAuthModule, AdminModule, ], diff --git a/backend/src/dryrun/dryrun.controller.spec.ts b/backend/src/dryrun/dryrun.controller.spec.ts new file mode 100644 index 00000000..f8803df1 --- /dev/null +++ b/backend/src/dryrun/dryrun.controller.spec.ts @@ -0,0 +1,20 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { DryrunController } from './dryrun.controller'; +import { DryrunService } from './dryrun.service'; + +describe('DryrunController', () => { + let controller: DryrunController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [DryrunController], + providers: [DryrunService], + }).compile(); + + controller = module.get(DryrunController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/backend/src/dryrun/dryrun.controller.ts b/backend/src/dryrun/dryrun.controller.ts new file mode 100644 index 00000000..dfca2a46 --- /dev/null +++ b/backend/src/dryrun/dryrun.controller.ts @@ -0,0 +1,39 @@ +import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common'; +import { DryrunService } from './dryrun.service'; +import { CreateDryrunDto } from './dto/create-dryrun.dto'; +import { UpdateDryrunDto } from './dto/update-dryrun.dto'; +import { ApiTags } from '@nestjs/swagger'; +import { DryrunDto } from './dto/dryrun.dto'; + +@ApiTags("dryrun") +@Controller({path: "dryrun", version: "1"}) +export class DryrunController { + constructor(private readonly dryrunService: DryrunService) {} + + @Post() + create(@Body() createDryrunDto: CreateDryrunDto) { + console.log("I AM HERE!!!"); + return this.dryrunService.create(createDryrunDto); + } + + @Get() + findAll() { + console.log('FIND ALL HERE!!!') + return this.dryrunService.findAll(); + } + + @Get(':id') + findOne(@Param('id') id: string) { + return this.dryrunService.findOne(+id); + } + + @Patch(':id') + update(@Param('id') id: string, @Body() updateDryrunDto: UpdateDryrunDto) { + return this.dryrunService.update(+id, updateDryrunDto); + } + + @Delete(':id') + remove(@Param('id') id: string) { + return this.dryrunService.remove(+id); + } +} diff --git a/backend/src/dryrun/dryrun.module.ts b/backend/src/dryrun/dryrun.module.ts new file mode 100644 index 00000000..5bc6ffe8 --- /dev/null +++ b/backend/src/dryrun/dryrun.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { DryrunService } from './dryrun.service'; +import { DryrunController } from './dryrun.controller'; + +@Module({ + controllers: [DryrunController], + providers: [DryrunService], +}) +export class DryrunModule {} diff --git a/backend/src/dryrun/dryrun.service.spec.ts b/backend/src/dryrun/dryrun.service.spec.ts new file mode 100644 index 00000000..461b47c0 --- /dev/null +++ b/backend/src/dryrun/dryrun.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { DryrunService } from './dryrun.service'; + +describe('DryrunService', () => { + let service: DryrunService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [DryrunService], + }).compile(); + + service = module.get(DryrunService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/backend/src/dryrun/dryrun.service.ts b/backend/src/dryrun/dryrun.service.ts new file mode 100644 index 00000000..7a6abd23 --- /dev/null +++ b/backend/src/dryrun/dryrun.service.ts @@ -0,0 +1,36 @@ +import { Injectable } from '@nestjs/common'; +import { CreateDryrunDto } from './dto/create-dryrun.dto'; +import { UpdateDryrunDto } from './dto/update-dryrun.dto'; +import { PrismaService } from 'nestjs-prisma'; +import { Prisma } from "@prisma/client"; +import { DryrunDto } from './dto/dryrun.dto'; + +@Injectable() +export class DryrunService { + constructor( + private prisma: PrismaService + ) { + } + + create(createDryrunDto: CreateDryrunDto) { + console.log("I WILL SEND THE POST FROM HERE!!!"); + return 'This action adds a new dryrun'; + } + + async findAll() { + const files = await this.prisma.file_submissions.findMany(); + console.log(files) + } + + findOne(id: number) { + return `This action returns a #${id} dryrun`; + } + + update(id: number, updateDryrunDto: UpdateDryrunDto) { + return `This action updates a #${id} dryrun`; + } + + remove(id: number) { + return `This action removes a #${id} dryrun`; + } +} diff --git a/backend/src/dryrun/dto/create-dryrun.dto.ts b/backend/src/dryrun/dto/create-dryrun.dto.ts new file mode 100644 index 00000000..72b0f581 --- /dev/null +++ b/backend/src/dryrun/dto/create-dryrun.dto.ts @@ -0,0 +1,13 @@ +import { PickType } from "@nestjs/swagger"; +import { DryrunDto } from "./dryrun.dto"; + +export class CreateDryrunDto extends PickType(DryrunDto, [ + 'submission_status_code', + 'description', + 'display_order', + 'active_ind', + 'create_user_id', + 'create_utc_timestamp', + 'update_user_id', + 'update_utc_timestamp', +] as const) {} \ No newline at end of file diff --git a/backend/src/dryrun/dto/dryrun.dto.ts b/backend/src/dryrun/dto/dryrun.dto.ts new file mode 100644 index 00000000..f6b89273 --- /dev/null +++ b/backend/src/dryrun/dto/dryrun.dto.ts @@ -0,0 +1,46 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class DryrunDto { + @ApiProperty({ + description: 'Unique identifies for the submitted file', + // default: '9999', + }) + submission_status_code: string; + + @ApiProperty({ + description: 'Full name of the code', + // default: 'username', + }) + description: string; + + @ApiProperty({ + description: 'Order in which the code appears', + }) + display_order: number; + + @ApiProperty({ + description: 'True if active, false otherwise', + default: true, + }) + active_ind: boolean + + @ApiProperty({ + description: 'The id of the user that created the record', + }) + create_user_id: string; + + @ApiProperty({ + description: 'When the user created the record', + }) + create_utc_timestamp: Date; + + @ApiProperty({ + description: 'The id of the user that last updated the record', + }) + update_user_id: string; + + @ApiProperty({ + description: 'When the user last updated the record', + }) + update_utc_timestamp: Date; +} diff --git a/backend/src/dryrun/dto/update-dryrun.dto.ts b/backend/src/dryrun/dto/update-dryrun.dto.ts new file mode 100644 index 00000000..d8a0d416 --- /dev/null +++ b/backend/src/dryrun/dto/update-dryrun.dto.ts @@ -0,0 +1,3 @@ +import { CreateDryrunDto } from './create-dryrun.dto'; + +export class UpdateDryrunDto extends CreateDryrunDto {} diff --git a/backend/src/dryrun/entities/dryrun.entity.ts b/backend/src/dryrun/entities/dryrun.entity.ts new file mode 100644 index 00000000..2498479d --- /dev/null +++ b/backend/src/dryrun/entities/dryrun.entity.ts @@ -0,0 +1 @@ +export class Dryrun {} diff --git a/docker-compose.yml b/docker-compose.yml index d758cfac..c2538c55 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,12 +8,17 @@ x-var: default - &POSTGRES_DATABASE postgres + - &POSTGRES_HOST + localhost:5432 + - &POSTGRES_SCHEMA + ENMODS x-postgres-vars: &postgres-vars - POSTGRES_HOST: database + POSTGRES_HOST: *POSTGRES_HOST POSTGRES_USER: *POSTGRES_USER POSTGRES_PASSWORD: *POSTGRES_PASSWORD POSTGRES_DATABASE: *POSTGRES_DATABASE + POSTGRES_SCHEMA: *POSTGRES_SCHEMA services: database: @@ -35,7 +40,7 @@ services: FLYWAY_USER: *POSTGRES_USER FLYWAY_PASSWORD: *POSTGRES_PASSWORD FLYWAY_BASELINE_ON_MIGRATE: true - FLYWAY_DEFAULT_SCHEMA: USERS + FLYWAY_DEFAULT_SCHEMA: *POSTGRES_SCHEMA depends_on: database: condition: service_healthy diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 43a2d5e5..5d58edab 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -28,6 +28,7 @@ "react-drag-drop-files": "^2.3.10", "react-router": "^6.12.1", "react-router-dom": "^6.12.1", + "redux": "^5.0.1", "vite": "^5.0.0", "vite-tsconfig-paths": "^4.2.0" }, @@ -4343,6 +4344,14 @@ "redux": "^4.0.4" } }, + "node_modules/dnd-core/node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -8751,12 +8760,9 @@ } }, "node_modules/redux": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", - "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", - "dependencies": { - "@babel/runtime": "^7.9.2" - } + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" }, "node_modules/reflect.getprototypeof": { "version": "1.0.6", diff --git a/frontend/package.json b/frontend/package.json index 4b902bc6..0a42be1a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -34,6 +34,7 @@ "react-drag-drop-files": "^2.3.10", "react-router": "^6.12.1", "react-router-dom": "^6.12.1", + "redux": "^5.0.1", "vite": "^5.0.0", "vite-tsconfig-paths": "^4.2.0" }, diff --git a/migrations/sql/V1.0.0__init.sql b/migrations/sql/V1.0.0__init.sql deleted file mode 100644 index 2be16859..00000000 --- a/migrations/sql/V1.0.0__init.sql +++ /dev/null @@ -1,24 +0,0 @@ -CREATE SCHEMA IF NOT EXISTS USERS; - -CREATE SEQUENCE IF NOT EXISTS USERS."USER_SEQ" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 100; - -CREATE TABLE IF NOT EXISTS USERS.USERS -( - ID numeric not null - constraint "USER_PK" - primary key DEFAULT nextval('USERS."USER_SEQ"'), - NAME varchar(200) not null, - EMAIL varchar(200) not null -); -INSERT INTO USERS.USERS (NAME, EMAIL) -VALUES ('John', 'John.ipsum@test.com'), - ('Jane', 'Jane.ipsum@test.com'), - ('Jack', 'Jack.ipsum@test.com'), - ('Jill', 'Jill.ipsum@test.com'), - ('Joe', 'Joe.ipsum@test.com'); - diff --git a/migrations/sql/V1.0.0__submission_status_code.sql b/migrations/sql/V1.0.0__submission_status_code.sql new file mode 100644 index 00000000..73924bbc --- /dev/null +++ b/migrations/sql/V1.0.0__submission_status_code.sql @@ -0,0 +1,62 @@ +CREATE SCHEMA IF NOT EXISTS enmods; +CREATE TABLE IF NOT EXISTS enmods.submission_status_code ( + submission_status_code varchar(20) NOT NULL, + description varchar(250) NOT NULL, + display_order int4 NOT NULL, + active_ind boolean DEFAULT true NOT NULL, + create_user_id varchar(200) NOT NULL, + create_utc_timestamp timestamp NOT NULL, + update_user_id varchar(200) NOT NULL, + update_utc_timestamp timestamp NOT NULL, + CONSTRAINT submission_status_code_pk PRIMARY KEY (submission_status_code) +); +INSERT INTO enmods.submission_status_code( + submission_status_code, + description, + display_order, + active_ind, + create_user_id, + create_utc_timestamp, + update_user_id, + update_utc_timestamp + ) +values ( + 'SUBMITTED', + 'Submitted', + 0, + true, + 'VMANAWAT', + (now() at time zone 'utc'), + 'VMANAWAT', + (now() at time zone 'utc') + ), + ( + 'INPROGRESS', + 'In Progress', + 5, + true, + 'VMANAWAT', + (now() at time zone 'utc'), + 'VMANAWAT', + (now() at time zone 'utc') + ), + ( + 'VALIDATED', + 'Validated', + 10, + true, + 'VMANAWAT', + (now() at time zone 'utc'), + 'VMANAWAT', + (now() at time zone 'utc') + ), + ( + 'REJECTED', + 'Rejected', + 15, + true, + 'VMANAWAT', + (now() at time zone 'utc'), + 'VMANAWAT', + (now() at time zone 'utc') + ); \ No newline at end of file diff --git a/migrations/sql/V1.0.1__alter_user_seq.sql b/migrations/sql/V1.0.1__alter_user_seq.sql deleted file mode 100644 index 6be8cd5b..00000000 --- a/migrations/sql/V1.0.1__alter_user_seq.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER SEQUENCE USERS."USER_SEQ" RESTART WITH 6 CACHE 1; diff --git a/migrations/sql/V1.0.1__file_submission.sql b/migrations/sql/V1.0.1__file_submission.sql new file mode 100644 index 00000000..b8a691ce --- /dev/null +++ b/migrations/sql/V1.0.1__file_submission.sql @@ -0,0 +1,50 @@ +CREATE TABLE IF NOT EXISTS enmods.file_submissions ( + submission_id UUID PRIMARY KEY NOT NULL DEFAULT gen_random_uuid(), + file_name varchar(200) NOT NULL, + submission_date timestamp NOT NULL, + submitter_user_id varchar(200) NOT NULL, + submission_status_code varchar(10) NOT NULL, + submitter_agency_name varchar(200) NOT NULL, + sample_count int4 NULL, + results_count int4 NULL, + active_ind boolean NOT NULL DEFAULT true, + error_log text NULL, + organization_guid UUID NULL, + create_user_id varchar(200) NOT NULL, + create_utc_timestamp timestamp NOT NULL, + update_user_id varchar(200) NOT NULL, + update_utc_timestamp timestamp NOT NULL, + CONSTRAINT submission_status_code_fk FOREIGN KEY(submission_status_code) REFERENCES enmods.submission_status_code(submission_status_code) +); +INSERT INTO enmods.file_submissions ( + file_name, + submission_date, + submitter_user_id, + submission_status_code, + submitter_agency_name, + sample_count, + results_count, + active_ind, + error_log, + organization_guid, + create_user_id, + create_utc_timestamp, + update_user_id, + update_utc_timestamp + ) +VALUES ( + 'testFile1', + (now() at time zone 'utc'), + 'VMANAWAT', + 'SUBMITTED', + 'MANAWAT CORP', + 12, + 50, + true, + 'THIS IS TEST ERROR LOG', + gen_random_uuid(), + 'VMANAWAT', + (now() at time zone 'utc'), + 'VMANAWAT', + (now() at time zone 'utc') + ); \ No newline at end of file