Skip to content
Snippets Groups Projects
Commit 9a0be945 authored by Richard Fernando Heise Ferreira's avatar Richard Fernando Heise Ferreira
Browse files

Merge branch 'issue-19-fix-delete-resource' into 'develop'

issue #19: FIX delete resources

See merge request !7
parents 0c677235 b7a6fb84
Branches
No related tags found
1 merge request!7issue #19: FIX delete resources
......@@ -7,7 +7,7 @@ services:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- "5432:5432"
- "5433:5432"
networks:
- apex_network
volumes:
......
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 DEFAULT 'sem descrição',
"institution" text DEFAULT 'sem instituição',
"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 DEFAULT true,
CONSTRAINT "user_id_unique" UNIQUE("id"),
CONSTRAINT "user_username_unique" UNIQUE("username"),
CONSTRAINT "user_email_unique" UNIQUE("email")
);
--> statement-breakpoint
ALTER TABLE "resource" ADD COLUMN "active" boolean DEFAULT false NOT NULL;--> 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 $$;
{
"id": "1ab52913-6a40-4df5-b569-1fd63fb22a9a",
"prevId": "ed42f7cb-45e7-47c8-93d7-a35abfc74f5a",
"version": "7",
"dialect": "postgresql",
"tables": {
"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": false
},
"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.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,
"default": "'sem descrição'"
},
"institution": {
"name": "institution",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'sem instituição'"
},
"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,
"default": true
}
},
"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
......@@ -29,6 +29,13 @@
"when": 1726750555860,
"tag": "0003_polite_wallflower",
"breakpoints": true
},
{
"idx": 4,
"version": "7",
"when": 1727099258603,
"tag": "0004_confused_maestro",
"breakpoints": true
}
]
}
\ No newline at end of file
......@@ -2,7 +2,7 @@ import { Service } from "typedi";
import { resourceSchema, type ResourceInput, type ResourceModel, type ResourceUpdate } from "../schema/resource.schema";
import db from '..'
import resourceTable from "../schema/resource.schema";
import { eq } from 'drizzle-orm'
import { eq, sql, and } from 'drizzle-orm'
@Service()
......@@ -28,7 +28,7 @@ export class ResourceRepo {
return resourceSchema.model.parse(ret)
}
async delete (id: ResourceModel['id']): Promise<ResourceModel> {
async deleteData(id: ResourceModel['id']): Promise<ResourceModel> {
const [ret] = await db
.delete(resourceTable)
.where(eq(resourceTable.id, id))
......@@ -37,17 +37,44 @@ export class ResourceRepo {
return resourceSchema.model.parse(ret)
}
async delete(id: ResourceModel['id']): Promise<ResourceModel> {
const [ret] = await db
.update(resourceTable)
.set({
deleted_at: sql`NOW()`,
active: false
})
.where(eq(resourceTable.id, id))
.returning()
return resourceSchema.model.parse(ret)
}
async active(id: ResourceModel['id']): Promise<ResourceModel> {
const [ret] = await db
.update(resourceTable)
.set({
deleted_at: null,
active: true
})
.where(eq(resourceTable.id, id))
.returning()
return resourceSchema.model.parse(ret)
}
async find(id: ResourceModel['id']): Promise<ResourceModel | undefined> {
const resource = await db.query.resourceTable.findFirst({
where: eq(resourceTable.id, id),
where: and(eq(resourceTable.id, id), eq(resourceTable.active, true)),
})
return resourceSchema.model.parse(resource)
return resource ? resourceSchema.model.parse(resource) : undefined;
}
async findMany(): Promise<ResourceModel[]> {
return resourceSchema.model.array().parse(await db.query.resourceTable.findMany())
return resourceSchema.model.array().parse(await db.query.resourceTable.findMany({ where: eq(resourceTable.active, true) }))
}
......
......@@ -3,13 +3,13 @@ import {
serial,
varchar,
timestamp,
boolean,
} from 'drizzle-orm/pg-core'
import { sql } from 'drizzle-orm'
import { createInsertSchema, createSelectSchema } from 'drizzle-zod'
import type { z } from 'zod'
//por padrao active é false, só é true quando o recurso é aprovado
const resourceTable = pgTable('resource', {
id: serial('id').notNull().primaryKey().unique(),
name: varchar('name', { length: 256 }).notNull(),
......@@ -18,6 +18,7 @@ const resourceTable = pgTable('resource', {
bucket_key: varchar('bucket_key', { length: 256 }).unique(),
link: varchar('link', { length: 256 }),
thumbnail: varchar('thumbnail', { length: 256 }),
active: boolean('active').notNull().default(false),
published_at: timestamp('published_at', { mode: 'string' }),
submited_at: timestamp('submited_at', { mode: 'string' }),
created_at: timestamp('created_at', { mode: 'string' })
......
......@@ -65,11 +65,11 @@ export const resourceRouter = honoWithJwt()
})
// rota para deletar um recurso
.post('/delete/:id',
.post('/deleteData/:id',
async (c) => {
try {
const id = +c.req.param('id')
const resource = resourceSchema.dto.parse(await service.delete(id))
const resource = resourceSchema.dto.parse(await service.deleteData(id))
//onDelete: "cascade" -> presente no stats-resources.schema.ts ja exclui o stats
......@@ -89,6 +89,53 @@ export const resourceRouter = honoWithJwt()
}
)
//rota para dizer que o recurso foi deletado
.post('/delete/:id',
async (c) => {
try {
const id = +c.req.param('id')
const resource = resourceSchema.dto.parse(await service.delete(id))
return c.json(resource)
} catch (e) {
return c.json(
createApexError({
status: 'error',
message: 'could not delete the resource',
code: HttpStatus.BAD_REQUEST,
path: c.req.routePath,
suggestion: 'check the id and try again',
}),
HttpStatus.BAD_REQUEST
)
}
}
)
//rota para tornar o recurso ativo
.post('/active/:id',
async (c) => {
try {
const id = +c.req.param('id')
const resource = resourceSchema.dto.parse(await service.active(id))
return c.json(resource)
} catch (e) {
return c.json(
createApexError({
status: 'error',
message: 'could not active the resource',
code: HttpStatus.BAD_REQUEST,
path: c.req.routePath,
suggestion: 'check the id and try again',
}),
HttpStatus.BAD_REQUEST
)
}
}
)
export const publicResourceRouter = new Hono()
// rota para listar todos os recursos
.get('/all', async (c) => {
......
......@@ -15,10 +15,18 @@ export class ResourceService {
return this.repo.update(resource)
}
async deleteData(id: ResourceModel['id']): Promise<ResourceModel> {
return this.repo.deleteData(id)
}
async delete(id: ResourceModel['id']): Promise<ResourceModel> {
return this.repo.delete(id)
}
async active(id: ResourceModel['id']): Promise<ResourceModel> {
return this.repo.active(id)
}
async findById(id: ResourceModel['id']): Promise<ResourceModel | undefined> {
return this.repo.find(id)
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment