Files
Palmr/apps/server/src/modules/share/routes.ts

379 lines
11 KiB
TypeScript

import { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
import { z } from "zod";
import { ShareController } from "./controller";
import {
CreateShareSchema,
ShareAliasResponseSchema,
ShareResponseSchema,
UpdateShareItemsSchema,
UpdateSharePasswordSchema,
UpdateShareRecipientsSchema,
UpdateShareSchema,
} from "./dto";
export async function shareRoutes(app: FastifyInstance) {
const shareController = new ShareController();
const preValidation = async (request: FastifyRequest, reply: FastifyReply) => {
try {
await request.jwtVerify();
} catch (err) {
console.error(err);
reply.status(401).send({ error: "Token inválido ou ausente." });
}
};
app.post(
"/shares",
{
preValidation,
schema: {
tags: ["Share"],
operationId: "createShare",
summary: "Create a new share",
description: "Create a new share with files and/or folders",
body: CreateShareSchema,
response: {
201: z.object({
share: ShareResponseSchema,
}),
400: z.object({ error: z.string().describe("Error message") }),
401: z.object({ error: z.string().describe("Error message") }),
},
},
},
shareController.createShare.bind(shareController)
);
app.get(
"/shares/me",
{
preValidation,
schema: {
tags: ["Share"],
operationId: "listUserShares",
summary: "List all shares created by the authenticated user",
description: "List all shares created by the authenticated user",
response: {
200: z.object({
shares: z.array(ShareResponseSchema),
}),
400: z.object({ error: z.string().describe("Error message") }),
401: z.object({ error: z.string().describe("Error message") }),
},
},
},
shareController.listUserShares.bind(shareController)
);
app.get(
"/shares/:shareId",
{
schema: {
tags: ["Share"],
operationId: "getShare",
summary: "Get a share by ID",
description: "Get a share by ID",
params: z.object({
shareId: z.string().describe("The share ID"),
}),
querystring: z.object({
password: z.string().optional().describe("The share password"),
}),
response: {
200: z.object({
share: ShareResponseSchema,
}),
400: z.object({ error: z.string().describe("Error message") }),
401: z.object({ error: z.string().describe("Error message") }),
404: z.object({ error: z.string().describe("Error message") }),
},
},
},
shareController.getShare.bind(shareController)
);
app.put(
"/shares",
{
preValidation,
schema: {
tags: ["Share"],
operationId: "updateShare",
summary: "Update a share",
description: "Update a share",
body: UpdateShareSchema,
response: {
200: z.object({
share: ShareResponseSchema,
}),
400: z.object({ error: z.string().describe("Error message") }),
401: z.object({ error: z.string().describe("Error message") }),
},
},
},
shareController.updateShare.bind(shareController)
);
app.delete(
"/shares/:id",
{
schema: {
tags: ["Share"],
operationId: "deleteShare",
summary: "Delete a share",
description: "Delete a share",
params: z.object({
id: z.string().describe("The share ID"),
}),
response: {
200: z.object({
share: ShareResponseSchema,
}),
400: z.object({ error: z.string().describe("Error message") }),
},
},
},
shareController.deleteShare.bind(shareController)
);
app.patch(
"/shares/:shareId/password",
{
preValidation,
schema: {
tags: ["Share"],
operationId: "updateSharePassword",
summary: "Update share password",
params: z.object({
shareId: z.string(),
}),
body: UpdateSharePasswordSchema,
response: {
200: z.object({
share: ShareResponseSchema,
}),
400: z.object({ error: z.string().describe("Error message") }),
401: z.object({ error: z.string().describe("Error message") }),
404: z.object({ error: z.string().describe("Error message") }),
},
},
},
shareController.updatePassword.bind(shareController)
);
app.post(
"/shares/:shareId/items",
{
preValidation,
schema: {
tags: ["Share"],
operationId: "addItems",
summary: "Add files and/or folders to share",
params: z.object({
shareId: z.string().describe("The share ID"),
}),
body: UpdateShareItemsSchema,
response: {
200: z.object({
share: ShareResponseSchema,
}),
400: z.object({ error: z.string().describe("Error message") }),
401: z.object({ error: z.string().describe("Error message") }),
404: z.object({ error: z.string().describe("Error message") }),
},
},
},
shareController.addItems.bind(shareController)
);
app.delete(
"/shares/:shareId/items",
{
preValidation,
schema: {
tags: ["Share"],
operationId: "removeItems",
summary: "Remove files and/or folders from share",
params: z.object({
shareId: z.string().describe("The share ID"),
}),
body: UpdateShareItemsSchema,
response: {
200: z.object({
share: ShareResponseSchema,
}),
400: z.object({ error: z.string().describe("Error message") }),
401: z.object({ error: z.string().describe("Error message") }),
404: z.object({ error: z.string().describe("Error message") }),
},
},
},
shareController.removeItems.bind(shareController)
);
app.post(
"/shares/:shareId/recipients",
{
preValidation,
schema: {
tags: ["Share"],
operationId: "addRecipients",
summary: "Add recipients to a share",
params: z.object({
shareId: z.string().describe("The share ID"),
}),
body: UpdateShareRecipientsSchema,
response: {
200: z.object({
share: ShareResponseSchema,
}),
400: z.object({ error: z.string().describe("Error message") }),
401: z.object({ error: z.string().describe("Error message") }),
404: z.object({ error: z.string().describe("Error message") }),
},
},
},
shareController.addRecipients.bind(shareController)
);
app.delete(
"/shares/:shareId/recipients",
{
preValidation,
schema: {
tags: ["Share"],
operationId: "removeRecipients",
summary: "Remove recipients from a share",
description: "Remove recipients from a share",
params: z.object({
shareId: z.string().describe("The share ID"),
}),
body: UpdateShareRecipientsSchema,
response: {
200: z.object({
share: ShareResponseSchema,
}),
400: z.object({ error: z.string().describe("Error message") }),
401: z.object({ error: z.string().describe("Error message") }),
404: z.object({ error: z.string().describe("Error message") }),
},
},
},
shareController.removeRecipients.bind(shareController)
);
app.post(
"/shares/:shareId/alias",
{
preValidation,
schema: {
tags: ["Share"],
operationId: "createShareAlias",
summary: "Create or update share alias",
params: z.object({
shareId: z.string().describe("The share ID"),
}),
body: z.object({
alias: z
.string()
.regex(/^[a-zA-Z0-9]+$/, "Alias must contain only letters and numbers")
.min(3, "Alias must be at least 3 characters long")
.max(30, "Alias must not exceed 30 characters"),
}),
response: {
200: z.object({
alias: ShareAliasResponseSchema,
}),
400: z.object({ error: z.string() }),
401: z.object({ error: z.string() }),
404: z.object({ error: z.string() }),
},
},
},
shareController.createOrUpdateAlias.bind(shareController)
);
app.get(
"/shares/alias/:alias",
{
schema: {
tags: ["Share"],
operationId: "getShareByAlias",
summary: "Get share by alias",
params: z.object({
alias: z.string().describe("The share alias"),
}),
querystring: z.object({
password: z.string().optional().describe("The share password"),
}),
response: {
200: z.object({
share: ShareResponseSchema,
}),
404: z.object({ error: z.string() }),
},
},
},
shareController.getShareByAlias.bind(shareController)
);
app.post(
"/shares/:shareId/notify",
{
preValidation,
schema: {
tags: ["Share"],
operationId: "notifyRecipients",
summary: "Send email notification to share recipients",
description: "Send email notification with share link to all recipients",
params: z.object({
shareId: z.string().describe("The share ID"),
}),
body: z.object({
shareLink: z.string().url().describe("The frontend share URL"),
}),
response: {
200: z.object({
message: z.string().describe("Success message"),
notifiedRecipients: z.array(z.string()).describe("List of notified email addresses"),
}),
400: z.object({ error: z.string() }),
401: z.object({ error: z.string() }),
404: z.object({ error: z.string() }),
},
},
},
shareController.notifyRecipients.bind(shareController)
);
app.get(
"/shares/alias/:alias/metadata",
{
schema: {
tags: ["Share"],
operationId: "getShareMetadataByAlias",
summary: "Get share metadata by alias for Open Graph",
description: "Get lightweight metadata for a share by alias, used for social media previews",
params: z.object({
alias: z.string().describe("The share alias"),
}),
response: {
200: z.object({
name: z.string().nullable(),
description: z.string().nullable(),
totalFiles: z.number(),
totalFolders: z.number(),
hasPassword: z.boolean(),
isExpired: z.boolean(),
isMaxViewsReached: z.boolean(),
}),
404: z.object({ error: z.string() }),
},
},
},
shareController.getShareMetadataByAlias.bind(shareController)
);
}