feat: trash (soft delete) with admin tool management
Build & Push Docker Image / build (push) Successful in 2m15s
Build & Push Docker Image / build (push) Successful in 2m15s
- tools: add deletedAt/deletedBy, soft delete via DELETE /tools/:id when actor has trash entitlement, else immediate hard delete - trash endpoints: GET /tools/trash, POST /tools/trash (admin bulk), POST /tools/trash/restore, DELETE /tools/trash, POST /tools/trash/empty - trash feature for premium/enterprise; exclude trashed from all public surfaces (browse, categories, features, tags, similar, ratings, costs, analytics, redundancy) - TRASH_RETENTION_DAYS env (0 = keep forever) with hourly purge job - frontend: /trash page (premium+, restore for all, permanent delete + empty for admin), admin Tools tab with multi-select bulk trash, sidebar Trash link, tool-detail delete hint
This commit is contained in:
@@ -122,7 +122,9 @@ export const UpdateToolResponse = zod.object({
|
||||
"features": zod.array(zod.string()).optional(),
|
||||
"tags": zod.array(zod.string()).optional(),
|
||||
"createdAt": zod.coerce.date(),
|
||||
"updatedAt": zod.coerce.date()
|
||||
"updatedAt": zod.coerce.date(),
|
||||
"deletedAt": zod.coerce.date().nullish(),
|
||||
"deletedBy": zod.string().nullish()
|
||||
})
|
||||
|
||||
|
||||
@@ -134,6 +136,83 @@ export const DeleteToolParams = zod.object({
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* @summary List trashed (soft-deleted) tools
|
||||
*/
|
||||
export const ListTrashedToolsQueryParams = zod.object({
|
||||
"search": zod.coerce.string().optional()
|
||||
})
|
||||
|
||||
export const ListTrashedToolsResponseItem = zod.object({
|
||||
"id": zod.number(),
|
||||
"name": zod.string(),
|
||||
"description": zod.string(),
|
||||
"category": zod.string(),
|
||||
"websiteUrl": zod.string().nullish(),
|
||||
"iconUrl": zod.string().nullish(),
|
||||
"createdBy": zod.string().nullish(),
|
||||
"features": zod.array(zod.string()).optional(),
|
||||
"tags": zod.array(zod.string()).optional(),
|
||||
"createdAt": zod.coerce.date(),
|
||||
"updatedAt": zod.coerce.date(),
|
||||
"deletedAt": zod.coerce.date().nullish(),
|
||||
"deletedBy": zod.string().nullish()
|
||||
})
|
||||
export const ListTrashedToolsResponse = zod.array(ListTrashedToolsResponseItem)
|
||||
|
||||
|
||||
/**
|
||||
* @summary Move tools to trash (admin)
|
||||
*/
|
||||
export const trashToolsBodyIdsMax = 500;
|
||||
|
||||
|
||||
|
||||
export const TrashToolsBody = zod.object({
|
||||
"ids": zod.array(zod.number()).min(1).max(trashToolsBodyIdsMax)
|
||||
})
|
||||
|
||||
export const TrashToolsResponse = zod.object({
|
||||
"trashed": zod.number().optional()
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* @summary Permanently delete trashed tools (admin)
|
||||
*/
|
||||
export const deleteTrashedToolsBodyIdsMax = 500;
|
||||
|
||||
|
||||
|
||||
export const DeleteTrashedToolsBody = zod.object({
|
||||
"ids": zod.array(zod.number()).min(1).max(deleteTrashedToolsBodyIdsMax)
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* @summary Restore trashed tools
|
||||
*/
|
||||
export const restoreToolsBodyIdsMax = 500;
|
||||
|
||||
|
||||
|
||||
export const RestoreToolsBody = zod.object({
|
||||
"ids": zod.array(zod.number()).min(1).max(restoreToolsBodyIdsMax)
|
||||
})
|
||||
|
||||
export const RestoreToolsResponse = zod.object({
|
||||
"restored": zod.number().optional()
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* @summary Permanently delete all trashed tools (admin)
|
||||
*/
|
||||
export const EmptyTrashResponse = zod.object({
|
||||
"deleted": zod.number().optional()
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* @summary List ratings for a tool
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Generated by orval v8.9.1 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* ToolRate API — Tool listing and rating platform
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export type EmptyTrash200 = {
|
||||
deleted?: number;
|
||||
};
|
||||
@@ -14,6 +14,7 @@ export * from './authUser';
|
||||
export * from './authUserRole';
|
||||
export * from './authUserTier';
|
||||
export * from './categoryStats';
|
||||
export * from './emptyTrash200';
|
||||
export * from './errorResponse';
|
||||
export * from './getRatingDistributionParams';
|
||||
export * from './getTopToolsMetric';
|
||||
@@ -22,16 +23,20 @@ export * from './healthStatus';
|
||||
export * from './listAuditLogsParams';
|
||||
export * from './listToolsParams';
|
||||
export * from './listToolsSort';
|
||||
export * from './listTrashedToolsParams';
|
||||
export * from './localLoginInput';
|
||||
export * from './rating';
|
||||
export * from './ratingDistribution';
|
||||
export * from './ratingInput';
|
||||
export * from './restoreTools200';
|
||||
export * from './scoreBucket';
|
||||
export * from './tool';
|
||||
export * from './toolInput';
|
||||
export * from './toolUpdate';
|
||||
export * from './toolWithStats';
|
||||
export * from './topToolEntry';
|
||||
export * from './trashTools200';
|
||||
export * from './trashToolsInput';
|
||||
export * from './user';
|
||||
export * from './userCreateInput';
|
||||
export * from './userCreateInputRole';
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Generated by orval v8.9.1 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* ToolRate API — Tool listing and rating platform
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export type ListTrashedToolsParams = {
|
||||
search?: string;
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Generated by orval v8.9.1 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* ToolRate API — Tool listing and rating platform
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export type RestoreTools200 = {
|
||||
restored?: number;
|
||||
};
|
||||
@@ -21,4 +21,8 @@ export interface Tool {
|
||||
tags?: string[];
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
/** @nullable */
|
||||
deletedAt?: Date | null;
|
||||
/** @nullable */
|
||||
deletedBy?: string | null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Generated by orval v8.9.1 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* ToolRate API — Tool listing and rating platform
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export type TrashTools200 = {
|
||||
trashed?: number;
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Generated by orval v8.9.1 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* ToolRate API — Tool listing and rating platform
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export interface TrashToolsInput {
|
||||
/**
|
||||
* @minItems 1
|
||||
* @maxItems 500
|
||||
*/
|
||||
ids: number[];
|
||||
}
|
||||
Reference in New Issue
Block a user