mirror of
https://github.com/kyantech/Palmr.git
synced 2025-11-02 13:03:15 +00:00
feat: add preview feature for social media sharing (#293)
This commit is contained in:
@@ -536,4 +536,17 @@ export class ReverseShareController {
|
||||
return reply.status(500).send({ error: "Internal server error" });
|
||||
}
|
||||
}
|
||||
|
||||
async getReverseShareMetadataByAlias(request: FastifyRequest, reply: FastifyReply) {
|
||||
try {
|
||||
const { alias } = request.params as { alias: string };
|
||||
const metadata = await this.reverseShareService.getReverseShareMetadataByAlias(alias);
|
||||
return reply.send(metadata);
|
||||
} catch (error: any) {
|
||||
if (error.message === "Reverse share not found") {
|
||||
return reply.status(404).send({ error: error.message });
|
||||
}
|
||||
return reply.status(400).send({ error: error.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -592,4 +592,32 @@ export async function reverseShareRoutes(app: FastifyInstance) {
|
||||
},
|
||||
reverseShareController.copyFileToUserFiles.bind(reverseShareController)
|
||||
);
|
||||
|
||||
app.get(
|
||||
"/reverse-shares/alias/:alias/metadata",
|
||||
{
|
||||
schema: {
|
||||
tags: ["Reverse Share"],
|
||||
operationId: "getReverseShareMetadataByAlias",
|
||||
summary: "Get reverse share metadata by alias for Open Graph",
|
||||
description: "Get lightweight metadata for a reverse share by alias, used for social media previews",
|
||||
params: z.object({
|
||||
alias: z.string().describe("Alias of the reverse share"),
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
name: z.string().nullable(),
|
||||
description: z.string().nullable(),
|
||||
totalFiles: z.number(),
|
||||
hasPassword: z.boolean(),
|
||||
isExpired: z.boolean(),
|
||||
isInactive: z.boolean(),
|
||||
maxFiles: z.number().nullable(),
|
||||
}),
|
||||
404: z.object({ error: z.string() }),
|
||||
},
|
||||
},
|
||||
},
|
||||
reverseShareController.getReverseShareMetadataByAlias.bind(reverseShareController)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -773,4 +773,30 @@ export class ReverseShareService {
|
||||
updatedAt: file.updatedAt.toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
async getReverseShareMetadataByAlias(alias: string) {
|
||||
const reverseShare = await this.reverseShareRepository.findByAlias(alias);
|
||||
if (!reverseShare) {
|
||||
throw new Error("Reverse share not found");
|
||||
}
|
||||
|
||||
// Check if reverse share is expired
|
||||
const isExpired = reverseShare.expiration && new Date(reverseShare.expiration) < new Date();
|
||||
|
||||
// Check if inactive
|
||||
const isInactive = !reverseShare.isActive;
|
||||
|
||||
const totalFiles = reverseShare.files?.length || 0;
|
||||
const hasPassword = !!reverseShare.password;
|
||||
|
||||
return {
|
||||
name: reverseShare.name,
|
||||
description: reverseShare.description,
|
||||
totalFiles,
|
||||
hasPassword,
|
||||
isExpired,
|
||||
isInactive,
|
||||
maxFiles: reverseShare.maxFiles,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,4 +295,17 @@ export class ShareController {
|
||||
return reply.status(400).send({ error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
async getShareMetadataByAlias(request: FastifyRequest, reply: FastifyReply) {
|
||||
try {
|
||||
const { alias } = request.params as { alias: string };
|
||||
const metadata = await this.shareService.getShareMetadataByAlias(alias);
|
||||
return reply.send(metadata);
|
||||
} catch (error: any) {
|
||||
if (error.message === "Share not found") {
|
||||
return reply.status(404).send({ error: error.message });
|
||||
}
|
||||
return reply.status(400).send({ error: error.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@ export interface IShareRepository {
|
||||
findShareBySecurityId(
|
||||
securityId: string
|
||||
): Promise<(Share & { security: ShareSecurity; files: any[]; folders: any[] }) | null>;
|
||||
findShareByAlias(
|
||||
alias: string
|
||||
): Promise<(Share & { security: ShareSecurity; files: any[]; folders: any[]; recipients: any[] }) | null>;
|
||||
updateShare(id: string, data: Partial<Share>): Promise<Share>;
|
||||
updateShareSecurity(id: string, data: Partial<ShareSecurity>): Promise<ShareSecurity>;
|
||||
deleteShare(id: string): Promise<Share>;
|
||||
@@ -130,6 +133,41 @@ export class PrismaShareRepository implements IShareRepository {
|
||||
});
|
||||
}
|
||||
|
||||
async findShareByAlias(alias: string) {
|
||||
const shareAlias = await prisma.shareAlias.findUnique({
|
||||
where: { alias },
|
||||
include: {
|
||||
share: {
|
||||
include: {
|
||||
security: true,
|
||||
files: true,
|
||||
folders: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
description: true,
|
||||
objectName: true,
|
||||
parentId: true,
|
||||
userId: true,
|
||||
createdAt: true,
|
||||
updatedAt: true,
|
||||
_count: {
|
||||
select: {
|
||||
files: true,
|
||||
children: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
recipients: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return shareAlias?.share || null;
|
||||
}
|
||||
|
||||
async updateShare(id: string, data: Partial<Share>): Promise<Share> {
|
||||
return prisma.share.update({
|
||||
where: { id },
|
||||
|
||||
@@ -347,4 +347,32 @@ export async function shareRoutes(app: FastifyInstance) {
|
||||
},
|
||||
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)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -440,4 +440,31 @@ export class ShareService {
|
||||
notifiedRecipients,
|
||||
};
|
||||
}
|
||||
|
||||
async getShareMetadataByAlias(alias: string) {
|
||||
const share = await this.shareRepository.findShareByAlias(alias);
|
||||
if (!share) {
|
||||
throw new Error("Share not found");
|
||||
}
|
||||
|
||||
// Check if share is expired
|
||||
const isExpired = share.expiration && new Date(share.expiration) < new Date();
|
||||
|
||||
// Check if max views reached
|
||||
const isMaxViewsReached = share.security.maxViews !== null && share.views >= share.security.maxViews;
|
||||
|
||||
const totalFiles = share.files?.length || 0;
|
||||
const totalFolders = share.folders?.length || 0;
|
||||
const hasPassword = !!share.security.password;
|
||||
|
||||
return {
|
||||
name: share.name,
|
||||
description: share.description,
|
||||
totalFiles,
|
||||
totalFolders,
|
||||
hasPassword,
|
||||
isExpired,
|
||||
isMaxViewsReached,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user