diff --git a/src/db/migrations/0000_noisy_metal_master.sql b/src/db/migrations/0000_noisy_metal_master.sql new file mode 100644 index 0000000000000000000000000000000000000000..2b749249c52d35747d182b52bf0b0aa9b38153a0 --- /dev/null +++ b/src/db/migrations/0000_noisy_metal_master.sql @@ -0,0 +1,122 @@ +CREATE TABLE IF NOT EXISTS "collection_stats" ( + "id" serial PRIMARY KEY NOT NULL, + "collection_id" bigint NOT NULL, + "views" bigint DEFAULT 0, + "downloads" bigint DEFAULT 0, + "likes" bigint DEFAULT 0, + "shares" bigint DEFAULT 0, + "score" bigint DEFAULT 0, + "follows" bigint DEFAULT 0, + CONSTRAINT "collection_stats_id_unique" UNIQUE("id") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "collection" ( + "id" serial PRIMARY KEY NOT NULL, + "name" varchar(255), + "description" text, + "is_private" boolean, + "is_active" boolean DEFAULT true, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp, + "deleted_at" timestamp, + "thumbnail" varchar(255), + CONSTRAINT "collection_id_unique" UNIQUE("id") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "resource" ( + "id" serial PRIMARY KEY NOT NULL, + "name" varchar(256) NOT NULL, + "author" varchar(256) NOT NULL, + "description" varchar(256), + "bucket_key" varchar(256), + "link" varchar(256), + "thumbnail" varchar(256), + "active" boolean DEFAULT false NOT NULL, + "published_at" timestamp, + "submited_at" timestamp, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp, + "deleted_at" timestamp, + CONSTRAINT "resource_id_unique" UNIQUE("id"), + CONSTRAINT "resource_bucket_key_unique" UNIQUE("bucket_key") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "stats_resources" ( + "id" serial PRIMARY KEY NOT NULL, + "resource_id" bigint NOT NULL, + "views" bigint DEFAULT 0 NOT NULL, + "downloads" bigint DEFAULT 0 NOT NULL, + "shares" bigint DEFAULT 0 NOT NULL, + "score" bigint DEFAULT 0 NOT NULL, + CONSTRAINT "stats_resources_id_unique" UNIQUE("id") +); + +CREATE TYPE status AS ENUM ('pending', 'approved', 'rejected'); +CREATE TYPE reasons AS ENUM ('reason1', 'reason2', 'reason3', 'reason4'); + +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "submission" ( + "id" serial PRIMARY KEY NOT NULL, + "status" "status" DEFAULT 'pending' NOT NULL, + "justification" text, + "reason" "reasons" NOT NULL, + "answered_at" timestamp, + "created_at" timestamp DEFAULT now() NOT NULL, + CONSTRAINT "submission_id_unique" UNIQUE("id") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "user_stats" ( + "id" serial PRIMARY KEY NOT NULL, + "user_id" integer NOT NULL, + "score" integer DEFAULT 0 NOT NULL, + "likes" integer DEFAULT 0, + "likes_received" integer DEFAULT 0, + "follows" integer DEFAULT 0, + "followers" integer DEFAULT 0, + "collections" integer DEFAULT 0, + "submitted_resources" integer DEFAULT 0, + "approved_resources" integer DEFAULT 0, + "reviewed_resources" integer DEFAULT 0, + "comments" integer DEFAULT 0, + CONSTRAINT "user_stats_id_unique" UNIQUE("id") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "user" ( + "id" serial PRIMARY KEY NOT NULL, + "name" varchar(255) NOT NULL, + "username" varchar(255) NOT NULL, + "password" varchar(255) NOT NULL, + "email" varchar(255) NOT NULL, + "description" text, + "institution" text, + "birthday" timestamp NOT NULL, + "cpf" varchar(255) NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + "confirmed_at" timestamp, + "confirmation_sent_at" timestamp, + "deleted_at" timestamp, + "reactivated_at" timestamp, + "active" boolean, + CONSTRAINT "user_id_unique" UNIQUE("id"), + CONSTRAINT "user_username_unique" UNIQUE("username"), + CONSTRAINT "user_email_unique" UNIQUE("email") +); +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "collection_stats" ADD CONSTRAINT "collection_stats_collection_id_collection_id_fk" FOREIGN KEY ("collection_id") REFERENCES "public"."collection"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "stats_resources" ADD CONSTRAINT "stats_resources_resource_id_resource_id_fk" FOREIGN KEY ("resource_id") REFERENCES "public"."resource"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "user_stats" ADD CONSTRAINT "user_stats_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; diff --git a/src/db/migrations/0001_fine_marvel_boy.sql b/src/db/migrations/0001_fine_marvel_boy.sql new file mode 100644 index 0000000000000000000000000000000000000000..747014b290b91b98714e84a55ccaf25c6b4d4bbe --- /dev/null +++ b/src/db/migrations/0001_fine_marvel_boy.sql @@ -0,0 +1 @@ +ALTER TABLE "submission" DROP CONSTRAINT "submission_id_unique"; \ No newline at end of file diff --git a/src/db/migrations/meta/0000_snapshot.json b/src/db/migrations/meta/0000_snapshot.json deleted file mode 100644 index 04d2b88c8a96d953ce6327f02eca1550c149d2cf..0000000000000000000000000000000000000000 --- a/src/db/migrations/meta/0000_snapshot.json +++ /dev/null @@ -1,633 +0,0 @@ -{ - "id": "63132df0-078f-4e91-a6fa-a6a7717c996a", - "prevId": "00000000-0000-0000-0000-000000000000", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.collection_stats": { - "name": "collection_stats", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "collection_id": { - "name": "collection_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "views": { - "name": "views", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": 0 - }, - "downloads": { - "name": "downloads", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": 0 - }, - "likes": { - "name": "likes", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": 0 - }, - "shares": { - "name": "shares", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": 0 - }, - "score": { - "name": "score", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": 0 - }, - "follows": { - "name": "follows", - "type": "bigint", - "primaryKey": false, - "notNull": false, - "default": 0 - } - }, - "indexes": {}, - "foreignKeys": { - "collection_stats_collection_id_collection_id_fk": { - "name": "collection_stats_collection_id_collection_id_fk", - "tableFrom": "collection_stats", - "tableTo": "collection", - "columnsFrom": [ - "collection_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "collection_stats_id_unique": { - "name": "collection_stats_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.collection": { - "name": "collection", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "is_private": { - "name": "is_private", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "is_active": { - "name": "is_active", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "deleted_at": { - "name": "deleted_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "thumbnail": { - "name": "thumbnail", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "collection_id_unique": { - "name": "collection_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.resource": { - "name": "resource", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(256)", - "primaryKey": false, - "notNull": true - }, - "author": { - "name": "author", - "type": "varchar(256)", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "varchar(256)", - "primaryKey": false, - "notNull": false - }, - "bucket_key": { - "name": "bucket_key", - "type": "varchar(256)", - "primaryKey": false, - "notNull": false - }, - "link": { - "name": "link", - "type": "varchar(256)", - "primaryKey": false, - "notNull": false - }, - "thumbnail": { - "name": "thumbnail", - "type": "varchar(256)", - "primaryKey": false, - "notNull": true - }, - "active": { - "name": "active", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "published_at": { - "name": "published_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "submited_at": { - "name": "submited_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "deleted_at": { - "name": "deleted_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "resource_id_unique": { - "name": "resource_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - }, - "resource_bucket_key_unique": { - "name": "resource_bucket_key_unique", - "nullsNotDistinct": false, - "columns": [ - "bucket_key" - ] - } - } - }, - "public.stats_resources": { - "name": "stats_resources", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "resource_id": { - "name": "resource_id", - "type": "bigint", - "primaryKey": false, - "notNull": true - }, - "views": { - "name": "views", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "downloads": { - "name": "downloads", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "shares": { - "name": "shares", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "score": { - "name": "score", - "type": "bigint", - "primaryKey": false, - "notNull": true, - "default": 0 - } - }, - "indexes": {}, - "foreignKeys": { - "stats_resources_resource_id_resource_id_fk": { - "name": "stats_resources_resource_id_resource_id_fk", - "tableFrom": "stats_resources", - "tableTo": "resource", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "stats_resources_id_unique": { - "name": "stats_resources_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.subjects": { - "name": "subjects", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "subjects_id_unique": { - "name": "subjects_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - }, - "subjects_name_unique": { - "name": "subjects_name_unique", - "nullsNotDistinct": false, - "columns": [ - "name" - ] - } - } - }, - "public.user_stats": { - "name": "user_stats", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "score": { - "name": "score", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "likes": { - "name": "likes", - "type": "integer", - "primaryKey": false, - "notNull": false, - "default": 0 - }, - "likes_received": { - "name": "likes_received", - "type": "integer", - "primaryKey": false, - "notNull": false, - "default": 0 - }, - "follows": { - "name": "follows", - "type": "integer", - "primaryKey": false, - "notNull": false, - "default": 0 - }, - "followers": { - "name": "followers", - "type": "integer", - "primaryKey": false, - "notNull": false, - "default": 0 - }, - "collections": { - "name": "collections", - "type": "integer", - "primaryKey": false, - "notNull": false, - "default": 0 - }, - "submitted_resources": { - "name": "submitted_resources", - "type": "integer", - "primaryKey": false, - "notNull": false, - "default": 0 - }, - "approved_resources": { - "name": "approved_resources", - "type": "integer", - "primaryKey": false, - "notNull": false, - "default": 0 - }, - "reviewed_resources": { - "name": "reviewed_resources", - "type": "integer", - "primaryKey": false, - "notNull": false, - "default": 0 - }, - "comments": { - "name": "comments", - "type": "integer", - "primaryKey": false, - "notNull": false, - "default": 0 - } - }, - "indexes": {}, - "foreignKeys": { - "user_stats_user_id_user_id_fk": { - "name": "user_stats_user_id_user_id_fk", - "tableFrom": "user_stats", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_stats_id_unique": { - "name": "user_stats_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - } - } - }, - "public.user": { - "name": "user", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "username": { - "name": "username", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "password": { - "name": "password", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "email": { - "name": "email", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "institution": { - "name": "institution", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "birthday": { - "name": "birthday", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "cpf": { - "name": "cpf", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "confirmed_at": { - "name": "confirmed_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "confirmation_sent_at": { - "name": "confirmation_sent_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "deleted_at": { - "name": "deleted_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "reactivated_at": { - "name": "reactivated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "active": { - "name": "active", - "type": "boolean", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_id_unique": { - "name": "user_id_unique", - "nullsNotDistinct": false, - "columns": [ - "id" - ] - }, - "user_username_unique": { - "name": "user_username_unique", - "nullsNotDistinct": false, - "columns": [ - "username" - ] - }, - "user_email_unique": { - "name": "user_email_unique", - "nullsNotDistinct": false, - "columns": [ - "email" - ] - } - } - } - }, - "enums": {}, - "schemas": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} \ No newline at end of file diff --git a/src/db/migrations/meta/_journal.json b/src/db/migrations/meta/_journal.json deleted file mode 100644 index 2578d6f20185432ea970925e879b491514ce1927..0000000000000000000000000000000000000000 --- a/src/db/migrations/meta/_journal.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "version": "7", - "dialect": "postgresql", - "entries": [ - { - "idx": 0, - "version": "7", - "when": 1727355232127, - "tag": "0000_abnormal_spyke", - "breakpoints": true - } - ] -} \ No newline at end of file diff --git a/src/db/repo/submission.repo.ts b/src/db/repo/submission.repo.ts new file mode 100644 index 0000000000000000000000000000000000000000..fa2cd5b3314e7da0575d382d6dce2765d5d65619 --- /dev/null +++ b/src/db/repo/submission.repo.ts @@ -0,0 +1,51 @@ +import { Service } from "typedi"; +import type { SubmissionInput, SubmissionModel, SubmissionUpdate } from "../schema/submission.model"; +import submissionTable, { submissionSchemas } from "../schema/submission.model"; +import db from ".."; +import { eq } from "drizzle-orm"; + +@Service() +export class SubmissionRepo { + async create(submission: SubmissionInput): Promise<SubmissionModel> { + const [ret] = await db + .insert(submissionTable) + .values(submission) + .returning() + + return submissionSchemas.submissionModelSchema.parse(ret) + } + + async update(submission: SubmissionUpdate): Promise<SubmissionModel> { + submission.answered_at = new Date().toISOString(); + const[ret] = await db + .update(submissionTable) + .set(submission) + .where(eq(submissionTable.id, submission.id)) + .returning() + + return submissionSchemas.submissionModelSchema.parse(ret) + } + + async delete(id: SubmissionModel['id']): Promise<SubmissionModel> { + const [ret] = await db + .delete(submissionTable) + .where(eq(submissionTable.id, id)) + .returning() + + return submissionSchemas.submissionModelSchema.parse(ret) + } + + async find(id: SubmissionModel['id']): Promise<SubmissionModel | undefined> { + const submission = await db.query.submissionTable.findFirst({ + where: eq(submissionTable.id, id), + }) + + return submission ? submissionSchemas.submissionModelSchema.parse(submission) : undefined + } + + async findMany(): Promise<SubmissionModel[]> { + return submissionSchemas.submissionModelSchema + .array() + .parse(await db.query.submissionTable.findMany()) + } +} \ No newline at end of file diff --git a/src/db/schema/index.ts b/src/db/schema/index.ts index 5a397c112ec21eaf4c76fecb8b428b42191cc128..20548b4ac65ca0291914b559c4ebf671f488f38f 100644 --- a/src/db/schema/index.ts +++ b/src/db/schema/index.ts @@ -2,12 +2,10 @@ import userStatsTable from './user-stats.model' import userTable from './user.model' import resourceTable from './resource.schema' import statsResourcesTable from './stats-resources.schema' - import collectionStatsTable from './collection-stats.model' import collectionTable from './collections.model' import subjectsTable from './subjects.schema' - - +import submissionTable from './submission.model' export { userTable, @@ -16,7 +14,8 @@ export { collectionTable, statsResourcesTable, collectionStatsTable, - subjectsTable + subjectsTable, + submissionTable } export const tables = [ @@ -26,7 +25,8 @@ export const tables = [ statsResourcesTable, collectionTable, collectionStatsTable, - subjectsTable + subjectsTable, + submissionTable ] diff --git a/src/db/schema/submission.model.ts b/src/db/schema/submission.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..fd86cdfe9272ce133330db083c8b561fb03f5d46 --- /dev/null +++ b/src/db/schema/submission.model.ts @@ -0,0 +1,35 @@ +import { pgEnum, pgTable, serial, text, timestamp } from "drizzle-orm/pg-core"; +import { createInsertSchema, createSelectSchema } from "drizzle-zod"; +import type { z } from "zod"; + +const statusEnum = pgEnum('status', ['pending', 'approved', 'rejected']) +// as razões são sobre o que o usuário quer reportar +const reasonsEnum = pgEnum('reason', ['reason1', 'reason2', 'reason3', 'reason4']) + +const submissionTable = pgTable('submission', { + id: serial('id').primaryKey().notNull(), + status: statusEnum('status').default('pending'), + justification: text('justification'), + reason: reasonsEnum('reason').default('reason4'), + answered_at: timestamp('answered_at', { mode: 'string'}), + created_at: timestamp('created_at', { mode: 'string' }).notNull().defaultNow(), +}) + +const submissionModelSchema = createSelectSchema(submissionTable) +const submissionDtoSchema = submissionModelSchema +const submissionInputSchema = createInsertSchema(submissionTable) +const submissionUpdateSchema = submissionInputSchema.partial().required({ id: true }) + +export type SubmissionModel = z.infer<typeof submissionModelSchema> +export type SubmissionDto = z.infer<typeof submissionDtoSchema> +export type SubmissionInput = z.infer<typeof submissionInputSchema> +export type SubmissionUpdate = z.infer<typeof submissionUpdateSchema> + +export const submissionSchemas = { + submissionModelSchema, + submissionDtoSchema, + submissionInputSchema, + submissionUpdateSchema, +} + +export default submissionTable \ No newline at end of file diff --git a/src/db/seed.ts b/src/db/seed.ts index 026a3b7ce9f44a65cf5656b24de1cc0870d76758..7e6d973851f550b317551302fbc83a974dd569dc 100644 --- a/src/db/seed.ts +++ b/src/db/seed.ts @@ -28,5 +28,6 @@ await seeds.statsResourcesSeed(db) await seeds.collectionSeed(db) await seeds.collectionStatsSeed(db) await seeds.subjectsData(db) +await seeds.submissionSeed(db) await connection.end() diff --git a/src/db/seeds/index.ts b/src/db/seeds/index.ts index 020b761fab6a5a5578113d9ac5328d3a44bb989e..4c28bd46d9aa0b38ba6bb23c600a9a3591e6a9ab 100644 --- a/src/db/seeds/index.ts +++ b/src/db/seeds/index.ts @@ -4,4 +4,5 @@ export {default as resourceSeed} from './resource.seed' export {default as statsResourcesSeed} from './statsResources.seed' export { default as collectionSeed } from './collections.seed' export { default as collectionStatsSeed } from './collection-stats.seed' -export { default as subjectsData } from './subjects.seed' \ No newline at end of file +export { default as subjectsData } from './subjects.seed' +export { default as submissionSeed } from './submission.seed' diff --git a/src/db/seeds/submission.seed.ts b/src/db/seeds/submission.seed.ts new file mode 100644 index 0000000000000000000000000000000000000000..aa155f46478e6904999136dbdbd2894eb87d143f --- /dev/null +++ b/src/db/seeds/submission.seed.ts @@ -0,0 +1,30 @@ +import type db from ".."; +import { submissionTable } from "../schema"; +import type { SubmissionInput } from "../schema/submission.model"; + +export default async function seed(db: db) { + await db.insert(submissionTable).values(submissionData) +} + +const submissionData: SubmissionInput[] = [ + { + status: 'pending', + justification: ' ', + reason: 'reason1', + }, + { + status: 'pending', + justification: ' ', + reason: 'reason2', + }, + { + status: 'pending', + justification: ' ', + reason: 'reason3', + }, + { + status: 'pending', + justification: ' ', + reason: 'reason4', + } +] \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 06c893cfb79f3887727dd9eacac5641baca41357..49b12a991b371bd0d8d6a5019a49d6f66ca374db 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,6 +16,7 @@ import { signUpRouter, userRouter } from './routes/user.route' import { uploaderRouter } from './routes/uploader.route' import { collectionsStatsRouter, getCollectionsStats } from './routes/collection-stats.route' import { publicSubjectsRouter, subjectsRouter } from './routes/subjects.route' +import { submissionRouter } from './routes/submission.route' const app = new Hono() @@ -58,6 +59,8 @@ app .route('/resource', publicResourceRouter) .route('/statsResource', publicStatsResourceRouter) .route('/subjects', publicSubjectsRouter) + .route('/get-collections', getCollections) + .route('/get-collection-stats', getCollectionsStats) //rotas que precisam de token app @@ -68,14 +71,9 @@ app .route('/resource', resourceRouter) .route('/statsResource', statsResourceRouter) .route('/subjects', subjectsRouter) - -app.route('/getCollections', getCollections) -app.route('/get-collections', getCollections) -app.route('/get-collection-stats', getCollectionsStats) -app - .basePath('/api') .route('/collection', collectionsRouter) .route('/collection-stats', collectionsStatsRouter) + .route('/submission', submissionRouter) export default app export type AppType = typeof app diff --git a/src/routes/submission.route.ts b/src/routes/submission.route.ts new file mode 100644 index 0000000000000000000000000000000000000000..fb51f5baf26aaf770b53050b22f3c54f8720b22b --- /dev/null +++ b/src/routes/submission.route.ts @@ -0,0 +1,131 @@ +import { SubmissionService } from "@/services/submission.service"; +import Container from "typedi"; +import { honoWithJwt } from ".."; +import { zValidator } from "@hono/zod-validator"; +import { submissionSchemas } from "@/db/schema/submission.model"; +import { createApexError, HttpStatus } from "@/services/error.service"; + +const service = Container.get(SubmissionService); + +export const submissionRouter = honoWithJwt() + .post( + '/create', + zValidator('json', submissionSchemas.submissionInputSchema), + async (c) => { + try { + const input = await c.req.valid('json') + + const submission = submissionSchemas.submissionDtoSchema.parse( + await service.create(input) + ) + + return c.json({ submission }) + } catch (e) { + return c.json( + createApexError({ + status: 'error', + message: 'could not create submission', + code: HttpStatus.BAD_REQUEST, + path: c.req.routePath, + suggestion: 'check the input and try again', + }), + HttpStatus.BAD_REQUEST + ) + } + } + ) + .post( + '/update', + zValidator('json', submissionSchemas.submissionUpdateSchema), + async (c) => { + try { + const input = await c.req.valid('json') + + const submission = submissionSchemas.submissionDtoSchema.parse( + await service.update(input) + ) + + return c.json({ submission }) + } catch (e) { + console.log(e) + + return c.json( + createApexError({ + status: 'error', + message: 'could not update submission', + code: HttpStatus.BAD_REQUEST, + path: c.req.routePath, + suggestion: 'check the input and try again', + }), + HttpStatus.BAD_REQUEST + ) + } + } + ) + .post('/delete/:id', async (c) => { + try { + const id = +c.req.param('id') + + const submission = submissionSchemas.submissionDtoSchema.parse( + await service.delete(id) + ) + + return c.json({ submission }) + } catch (e) { + return c.json( + createApexError({ + status: 'error', + message: 'could not delete submission', + code: HttpStatus.BAD_REQUEST, + path: c.req.routePath, + suggestion: 'check the input and try again', + }), + HttpStatus.BAD_REQUEST + ) + } + }) + .get('/find/:id', async (c) => { + try { + const id = +c.req.param('id') + + const submission = submissionSchemas.submissionDtoSchema.parse( + await service.find(id) + ) + + return c.json({ submission }) + } catch (e) { + return c.json( + createApexError({ + status: 'error', + message: 'could not find submission', + code: HttpStatus.BAD_REQUEST, + path: c.req.routePath, + suggestion: 'check the input and try again', + }), + HttpStatus.NOT_FOUND + ) + } + }) + .get('/get-all', async (c) => { + try { + const submissions = submissionSchemas.submissionDtoSchema.array().parse( + await service.findMany() + ) + + return c.json({ submissions }) + } catch (e) { + return c.json( + createApexError({ + status: 'error', + message: 'could not find submissions', + code: HttpStatus.BAD_REQUEST, + path: c.req.routePath, + suggestion: 'check the input and try again', + }), + HttpStatus.NOT_FOUND + ) + } + }) + + + diff --git a/src/services/submission.service.ts b/src/services/submission.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..7d384817790f15765f5912b1be3fd7ab90b3fb57 --- /dev/null +++ b/src/services/submission.service.ts @@ -0,0 +1,29 @@ +import { SubmissionRepo } from "@/db/repo/submission.repo"; +import type { SubmissionInput, SubmissionModel, SubmissionUpdate } from "@/db/schema/submission.model"; +import { Inject, Service } from "typedi"; + +@Service() +export class SubmissionService { + @Inject() + private readonly repo: SubmissionRepo + + async create(submission: SubmissionInput): Promise<SubmissionInput> { + return this.repo.create(submission) + } + + async update(submission: SubmissionUpdate): Promise<SubmissionInput> { + return this.repo.update(submission) + } + + async delete(id: SubmissionModel['id']): Promise<SubmissionInput> { + return this.repo.delete(id) + } + + async find(id: SubmissionModel['id']): Promise<SubmissionModel | undefined> { + return this.repo.find(id) + } + + async findMany(): Promise<SubmissionModel[]> { + return this.repo.findMany() + } +} \ No newline at end of file