mirror of
https://github.com/kyantech/Palmr.git
synced 2025-10-23 06:11:58 +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" });
|
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)
|
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(),
|
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 });
|
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(
|
findShareBySecurityId(
|
||||||
securityId: string
|
securityId: string
|
||||||
): Promise<(Share & { security: ShareSecurity; files: any[]; folders: any[] }) | null>;
|
): 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>;
|
updateShare(id: string, data: Partial<Share>): Promise<Share>;
|
||||||
updateShareSecurity(id: string, data: Partial<ShareSecurity>): Promise<ShareSecurity>;
|
updateShareSecurity(id: string, data: Partial<ShareSecurity>): Promise<ShareSecurity>;
|
||||||
deleteShare(id: string): Promise<Share>;
|
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> {
|
async updateShare(id: string, data: Partial<Share>): Promise<Share> {
|
||||||
return prisma.share.update({
|
return prisma.share.update({
|
||||||
where: { id },
|
where: { id },
|
||||||
|
@@ -347,4 +347,32 @@ export async function shareRoutes(app: FastifyInstance) {
|
|||||||
},
|
},
|
||||||
shareController.notifyRecipients.bind(shareController)
|
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,
|
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,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1056,7 +1056,8 @@
|
|||||||
"upload": {
|
"upload": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"title": "رفع الملفات - Palmr",
|
"title": "رفع الملفات - Palmr",
|
||||||
"description": "رفع الملفات عبر الرابط المشترك"
|
"description": "رفع الملفات عبر الرابط المشترك",
|
||||||
|
"descriptionWithLimit": "تحميل الملفات (الحد الأقصى {limit} ملفات)"
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
"defaultTitle": "رفع الملفات",
|
"defaultTitle": "رفع الملفات",
|
||||||
@@ -1365,7 +1366,11 @@
|
|||||||
"description": "قد يكون تم حذف هذه المشاركة أو انتهت صلاحيتها."
|
"description": "قد يكون تم حذف هذه المشاركة أو انتهت صلاحيتها."
|
||||||
},
|
},
|
||||||
"pageTitle": "المشاركة",
|
"pageTitle": "المشاركة",
|
||||||
"downloadAll": "تحميل الكل"
|
"downloadAll": "تحميل الكل",
|
||||||
|
"metadata": {
|
||||||
|
"defaultDescription": "مشاركة الملفات بشكل آمن",
|
||||||
|
"filesShared": "{count, plural, =1 {ملف واحد تمت مشاركته} other {# ملفات تمت مشاركتها}}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shareActions": {
|
"shareActions": {
|
||||||
"deleteTitle": "حذف المشاركة",
|
"deleteTitle": "حذف المشاركة",
|
||||||
|
@@ -1056,7 +1056,8 @@
|
|||||||
"upload": {
|
"upload": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"title": "Dateien senden - Palmr",
|
"title": "Dateien senden - Palmr",
|
||||||
"description": "Senden Sie Dateien über den geteilten Link"
|
"description": "Senden Sie Dateien über den geteilten Link",
|
||||||
|
"descriptionWithLimit": "Dateien hochladen (max. {limit} Dateien)"
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
"defaultTitle": "Dateien senden",
|
"defaultTitle": "Dateien senden",
|
||||||
@@ -1363,7 +1364,11 @@
|
|||||||
"description": "Diese Freigabe wurde möglicherweise gelöscht oder ist abgelaufen."
|
"description": "Diese Freigabe wurde möglicherweise gelöscht oder ist abgelaufen."
|
||||||
},
|
},
|
||||||
"pageTitle": "Freigabe",
|
"pageTitle": "Freigabe",
|
||||||
"downloadAll": "Alle herunterladen"
|
"downloadAll": "Alle herunterladen",
|
||||||
|
"metadata": {
|
||||||
|
"defaultDescription": "Dateien sicher teilen",
|
||||||
|
"filesShared": "{count, plural, =1 {1 Datei geteilt} other {# Dateien geteilt}}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shareActions": {
|
"shareActions": {
|
||||||
"deleteTitle": "Freigabe Löschen",
|
"deleteTitle": "Freigabe Löschen",
|
||||||
|
@@ -1057,7 +1057,8 @@
|
|||||||
"upload": {
|
"upload": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"title": "Send Files - Palmr",
|
"title": "Send Files - Palmr",
|
||||||
"description": "Send files through the shared link"
|
"description": "Send files through the shared link",
|
||||||
|
"descriptionWithLimit": "Upload files (max {limit} files)"
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
"defaultTitle": "Send Files",
|
"defaultTitle": "Send Files",
|
||||||
@@ -1361,7 +1362,11 @@
|
|||||||
"title": "Share Not Found",
|
"title": "Share Not Found",
|
||||||
"description": "This share may have been deleted or expired."
|
"description": "This share may have been deleted or expired."
|
||||||
},
|
},
|
||||||
"pageTitle": "Share"
|
"pageTitle": "Share",
|
||||||
|
"metadata": {
|
||||||
|
"defaultDescription": "Share files securely",
|
||||||
|
"filesShared": "{count, plural, =1 {1 file shared} other {# files shared}}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shareActions": {
|
"shareActions": {
|
||||||
"fileTitle": "Share File",
|
"fileTitle": "Share File",
|
||||||
|
@@ -1056,7 +1056,8 @@
|
|||||||
"upload": {
|
"upload": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"title": "Enviar Archivos - Palmr",
|
"title": "Enviar Archivos - Palmr",
|
||||||
"description": "Envía archivos a través del enlace compartido"
|
"description": "Envía archivos a través del enlace compartido",
|
||||||
|
"descriptionWithLimit": "Subir archivos (máx. {limit} archivos)"
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
"defaultTitle": "Enviar Archivos",
|
"defaultTitle": "Enviar Archivos",
|
||||||
@@ -1363,7 +1364,11 @@
|
|||||||
"description": "Esta compartición puede haber sido eliminada o haber expirado."
|
"description": "Esta compartición puede haber sido eliminada o haber expirado."
|
||||||
},
|
},
|
||||||
"pageTitle": "Compartición",
|
"pageTitle": "Compartición",
|
||||||
"downloadAll": "Descargar Todo"
|
"downloadAll": "Descargar Todo",
|
||||||
|
"metadata": {
|
||||||
|
"defaultDescription": "Compartir archivos de forma segura",
|
||||||
|
"filesShared": "{count, plural, =1 {1 archivo compartido} other {# archivos compartidos}}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shareActions": {
|
"shareActions": {
|
||||||
"deleteTitle": "Eliminar Compartir",
|
"deleteTitle": "Eliminar Compartir",
|
||||||
|
@@ -1056,7 +1056,8 @@
|
|||||||
"upload": {
|
"upload": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"title": "Envoyer des Fichiers - Palmr",
|
"title": "Envoyer des Fichiers - Palmr",
|
||||||
"description": "Envoyez des fichiers via le lien partagé"
|
"description": "Envoyez des fichiers via le lien partagé",
|
||||||
|
"descriptionWithLimit": "Télécharger des fichiers (max {limit} fichiers)"
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
"defaultTitle": "Envoyer des Fichiers",
|
"defaultTitle": "Envoyer des Fichiers",
|
||||||
@@ -1363,7 +1364,11 @@
|
|||||||
"description": "Ce partage a peut-être été supprimé ou a expiré."
|
"description": "Ce partage a peut-être été supprimé ou a expiré."
|
||||||
},
|
},
|
||||||
"pageTitle": "Partage",
|
"pageTitle": "Partage",
|
||||||
"downloadAll": "Tout Télécharger"
|
"downloadAll": "Tout Télécharger",
|
||||||
|
"metadata": {
|
||||||
|
"defaultDescription": "Partager des fichiers en toute sécurité",
|
||||||
|
"filesShared": "{count, plural, =1 {1 fichier partagé} other {# fichiers partagés}}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shareActions": {
|
"shareActions": {
|
||||||
"deleteTitle": "Supprimer le Partage",
|
"deleteTitle": "Supprimer le Partage",
|
||||||
|
@@ -1056,7 +1056,8 @@
|
|||||||
"upload": {
|
"upload": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"title": "फ़ाइलें भेजें - पाल्मर",
|
"title": "फ़ाइलें भेजें - पाल्मर",
|
||||||
"description": "साझा किए गए लिंक के माध्यम से फ़ाइलें भेजें"
|
"description": "साझा किए गए लिंक के माध्यम से फ़ाइलें भेजें",
|
||||||
|
"descriptionWithLimit": "फ़ाइलें अपलोड करें (अधिकतम {limit} फ़ाइलें)"
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
"defaultTitle": "फ़ाइलें भेजें",
|
"defaultTitle": "फ़ाइलें भेजें",
|
||||||
@@ -1363,7 +1364,11 @@
|
|||||||
"description": "यह साझाकरण हटा दिया गया हो सकता है या समाप्त हो चुका है।"
|
"description": "यह साझाकरण हटा दिया गया हो सकता है या समाप्त हो चुका है।"
|
||||||
},
|
},
|
||||||
"pageTitle": "साझाकरण",
|
"pageTitle": "साझाकरण",
|
||||||
"downloadAll": "सभी डाउनलोड करें"
|
"downloadAll": "सभी डाउनलोड करें",
|
||||||
|
"metadata": {
|
||||||
|
"defaultDescription": "फाइलों को सुरक्षित रूप से साझा करें",
|
||||||
|
"filesShared": "{count, plural, =1 {1 फ़ाइल साझा की गई} other {# फ़ाइलें साझा की गईं}}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shareActions": {
|
"shareActions": {
|
||||||
"deleteTitle": "साझाकरण हटाएं",
|
"deleteTitle": "साझाकरण हटाएं",
|
||||||
|
@@ -1056,7 +1056,8 @@
|
|||||||
"upload": {
|
"upload": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"title": "Invia File - Palmr",
|
"title": "Invia File - Palmr",
|
||||||
"description": "Invia file attraverso il link condiviso"
|
"description": "Invia file attraverso il link condiviso",
|
||||||
|
"descriptionWithLimit": "Carica file (max {limit} file)"
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
"defaultTitle": "Invia File",
|
"defaultTitle": "Invia File",
|
||||||
@@ -1363,7 +1364,11 @@
|
|||||||
"description": "Questa condivisione potrebbe essere stata eliminata o è scaduta."
|
"description": "Questa condivisione potrebbe essere stata eliminata o è scaduta."
|
||||||
},
|
},
|
||||||
"pageTitle": "Condivisione",
|
"pageTitle": "Condivisione",
|
||||||
"downloadAll": "Scarica Tutto"
|
"downloadAll": "Scarica Tutto",
|
||||||
|
"metadata": {
|
||||||
|
"defaultDescription": "Condividi file in modo sicuro",
|
||||||
|
"filesShared": "{count, plural, =1 {1 file condiviso} other {# file condivisi}}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shareActions": {
|
"shareActions": {
|
||||||
"deleteTitle": "Elimina Condivisione",
|
"deleteTitle": "Elimina Condivisione",
|
||||||
|
@@ -1056,7 +1056,8 @@
|
|||||||
"upload": {
|
"upload": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"title": "ファイルを送信 - Palmr",
|
"title": "ファイルを送信 - Palmr",
|
||||||
"description": "共有リンクを通じてファイルを送信"
|
"description": "共有リンクを通じてファイルを送信",
|
||||||
|
"descriptionWithLimit": "ファイルをアップロード(最大{limit}ファイル)"
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
"defaultTitle": "ファイルを送信",
|
"defaultTitle": "ファイルを送信",
|
||||||
@@ -1363,7 +1364,11 @@
|
|||||||
"description": "この共有は削除されたか、期限が切れている可能性があります。"
|
"description": "この共有は削除されたか、期限が切れている可能性があります。"
|
||||||
},
|
},
|
||||||
"pageTitle": "共有",
|
"pageTitle": "共有",
|
||||||
"downloadAll": "すべてダウンロード"
|
"downloadAll": "すべてダウンロード",
|
||||||
|
"metadata": {
|
||||||
|
"defaultDescription": "ファイルを安全に共有",
|
||||||
|
"filesShared": "{count, plural, =1 {1 ファイルが共有されました} other {# ファイルが共有されました}}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shareActions": {
|
"shareActions": {
|
||||||
"deleteTitle": "共有を削除",
|
"deleteTitle": "共有を削除",
|
||||||
|
@@ -1056,7 +1056,8 @@
|
|||||||
"upload": {
|
"upload": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"title": "파일 보내기 - Palmr",
|
"title": "파일 보내기 - Palmr",
|
||||||
"description": "공유된 링크를 통해 파일 보내기"
|
"description": "공유된 링크를 통해 파일 보내기",
|
||||||
|
"descriptionWithLimit": "파일 업로드 (최대 {limit}개 파일)"
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
"defaultTitle": "파일 보내기",
|
"defaultTitle": "파일 보내기",
|
||||||
@@ -1363,7 +1364,11 @@
|
|||||||
"description": "이 공유는 삭제되었거나 만료되었을 수 있습니다."
|
"description": "이 공유는 삭제되었거나 만료되었을 수 있습니다."
|
||||||
},
|
},
|
||||||
"pageTitle": "공유",
|
"pageTitle": "공유",
|
||||||
"downloadAll": "모두 다운로드"
|
"downloadAll": "모두 다운로드",
|
||||||
|
"metadata": {
|
||||||
|
"defaultDescription": "파일을 안전하게 공유",
|
||||||
|
"filesShared": "{count, plural, =1 {1개 파일 공유됨} other {#개 파일 공유됨}}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shareActions": {
|
"shareActions": {
|
||||||
"deleteTitle": "공유 삭제",
|
"deleteTitle": "공유 삭제",
|
||||||
|
@@ -1056,7 +1056,8 @@
|
|||||||
"upload": {
|
"upload": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"title": "Bestanden Verzenden - Palmr",
|
"title": "Bestanden Verzenden - Palmr",
|
||||||
"description": "Verzend bestanden via de gedeelde link"
|
"description": "Verzend bestanden via de gedeelde link",
|
||||||
|
"descriptionWithLimit": "Upload bestanden (max {limit} bestanden)"
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
"defaultTitle": "Bestanden Verzenden",
|
"defaultTitle": "Bestanden Verzenden",
|
||||||
@@ -1363,7 +1364,11 @@
|
|||||||
"description": "Dit delen is mogelijk verwijderd of verlopen."
|
"description": "Dit delen is mogelijk verwijderd of verlopen."
|
||||||
},
|
},
|
||||||
"pageTitle": "Delen",
|
"pageTitle": "Delen",
|
||||||
"downloadAll": "Alles Downloaden"
|
"downloadAll": "Alles Downloaden",
|
||||||
|
"metadata": {
|
||||||
|
"defaultDescription": "Bestanden veilig delen",
|
||||||
|
"filesShared": "{count, plural, =1 {1 bestand gedeeld} other {# bestanden gedeeld}}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shareActions": {
|
"shareActions": {
|
||||||
"deleteTitle": "Delen Verwijderen",
|
"deleteTitle": "Delen Verwijderen",
|
||||||
|
@@ -1056,7 +1056,8 @@
|
|||||||
"upload": {
|
"upload": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"title": "Wyślij pliki - Palmr",
|
"title": "Wyślij pliki - Palmr",
|
||||||
"description": "Wysyłaj pliki za pośrednictwem udostępnionego linku"
|
"description": "Wysyłaj pliki za pośrednictwem udostępnionego linku",
|
||||||
|
"descriptionWithLimit": "Prześlij pliki (maks. {limit} plików)"
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
"defaultTitle": "Wyślij pliki",
|
"defaultTitle": "Wyślij pliki",
|
||||||
@@ -1363,7 +1364,11 @@
|
|||||||
"description": "To udostępnienie mogło zostać usunięte lub wygasło."
|
"description": "To udostępnienie mogło zostać usunięte lub wygasło."
|
||||||
},
|
},
|
||||||
"pageTitle": "Udostępnij",
|
"pageTitle": "Udostępnij",
|
||||||
"downloadAll": "Pobierz wszystkie"
|
"downloadAll": "Pobierz wszystkie",
|
||||||
|
"metadata": {
|
||||||
|
"defaultDescription": "Bezpiecznie udostępniaj pliki",
|
||||||
|
"filesShared": "{count, plural, =1 {1 plik udostępniony} other {# plików udostępnionych}}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shareActions": {
|
"shareActions": {
|
||||||
"deleteTitle": "Usuń udostępnienie",
|
"deleteTitle": "Usuń udostępnienie",
|
||||||
|
@@ -1057,7 +1057,8 @@
|
|||||||
"upload": {
|
"upload": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"title": "Enviar Arquivos - Palmr",
|
"title": "Enviar Arquivos - Palmr",
|
||||||
"description": "Envie arquivos através do link compartilhado"
|
"description": "Envie arquivos através do link compartilhado",
|
||||||
|
"descriptionWithLimit": "Enviar arquivos (máx. {limit} arquivos)"
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
"defaultTitle": "Enviar Arquivos",
|
"defaultTitle": "Enviar Arquivos",
|
||||||
@@ -1364,7 +1365,11 @@
|
|||||||
"description": "Este compartilhamento pode ter sido excluído ou expirado."
|
"description": "Este compartilhamento pode ter sido excluído ou expirado."
|
||||||
},
|
},
|
||||||
"pageTitle": "Compartilhamento",
|
"pageTitle": "Compartilhamento",
|
||||||
"downloadAll": "Baixar todos"
|
"downloadAll": "Baixar todos",
|
||||||
|
"metadata": {
|
||||||
|
"defaultDescription": "Compartilhar arquivos com segurança",
|
||||||
|
"filesShared": "{count, plural, =1 {1 arquivo compartilhado} other {# arquivos compartilhados}}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shareActions": {
|
"shareActions": {
|
||||||
"deleteTitle": "Excluir Compartilhamento",
|
"deleteTitle": "Excluir Compartilhamento",
|
||||||
|
@@ -1056,7 +1056,8 @@
|
|||||||
"upload": {
|
"upload": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"title": "Отправка файлов - Palmr",
|
"title": "Отправка файлов - Palmr",
|
||||||
"description": "Отправка файлов через общую ссылку"
|
"description": "Отправка файлов через общую ссылку",
|
||||||
|
"descriptionWithLimit": "Загрузить файлы (макс. {limit} файлов)"
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
"defaultTitle": "Отправка файлов",
|
"defaultTitle": "Отправка файлов",
|
||||||
@@ -1363,7 +1364,11 @@
|
|||||||
"description": "Этот общий доступ может быть удален или истек."
|
"description": "Этот общий доступ может быть удален или истек."
|
||||||
},
|
},
|
||||||
"pageTitle": "Общий доступ",
|
"pageTitle": "Общий доступ",
|
||||||
"downloadAll": "Скачать все"
|
"downloadAll": "Скачать все",
|
||||||
|
"metadata": {
|
||||||
|
"defaultDescription": "Безопасный обмен файлами",
|
||||||
|
"filesShared": "{count, plural, =1 {1 файл отправлен} other {# файлов отправлено}}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shareActions": {
|
"shareActions": {
|
||||||
"deleteTitle": "Удалить Общий Доступ",
|
"deleteTitle": "Удалить Общий Доступ",
|
||||||
|
@@ -1056,7 +1056,8 @@
|
|||||||
"upload": {
|
"upload": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"title": "Dosya Gönder - Palmr",
|
"title": "Dosya Gönder - Palmr",
|
||||||
"description": "Paylaşılan bağlantı üzerinden dosya gönderin"
|
"description": "Paylaşılan bağlantı üzerinden dosya gönderin",
|
||||||
|
"descriptionWithLimit": "Dosya yükle (maks. {limit} dosya)"
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
"defaultTitle": "Dosya Gönder",
|
"defaultTitle": "Dosya Gönder",
|
||||||
@@ -1363,7 +1364,11 @@
|
|||||||
"description": "Bu paylaşım silinmiş veya süresi dolmuş olabilir."
|
"description": "Bu paylaşım silinmiş veya süresi dolmuş olabilir."
|
||||||
},
|
},
|
||||||
"pageTitle": "Paylaşım",
|
"pageTitle": "Paylaşım",
|
||||||
"downloadAll": "Tümünü İndir"
|
"downloadAll": "Tümünü İndir",
|
||||||
|
"metadata": {
|
||||||
|
"defaultDescription": "Dosyaları güvenli bir şekilde paylaşın",
|
||||||
|
"filesShared": "{count, plural, =1 {1 dosya paylaşıldı} other {# dosya paylaşıldı}}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shareActions": {
|
"shareActions": {
|
||||||
"deleteTitle": "Paylaşımı Sil",
|
"deleteTitle": "Paylaşımı Sil",
|
||||||
|
@@ -1056,7 +1056,8 @@
|
|||||||
"upload": {
|
"upload": {
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"title": "上传文件 - Palmr",
|
"title": "上传文件 - Palmr",
|
||||||
"description": "通过共享链接上传文件"
|
"description": "通过共享链接上传文件",
|
||||||
|
"descriptionWithLimit": "上传文件(最多 {limit} 个文件)"
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
"defaultTitle": "上传文件",
|
"defaultTitle": "上传文件",
|
||||||
@@ -1363,7 +1364,11 @@
|
|||||||
"description": "该共享可能已被删除或已过期。"
|
"description": "该共享可能已被删除或已过期。"
|
||||||
},
|
},
|
||||||
"pageTitle": "共享",
|
"pageTitle": "共享",
|
||||||
"downloadAll": "下载所有"
|
"downloadAll": "下载所有",
|
||||||
|
"metadata": {
|
||||||
|
"defaultDescription": "安全共享文件",
|
||||||
|
"filesShared": "{count, plural, =1 {已共享 1 个文件} other {已共享 # 个文件}}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shareActions": {
|
"shareActions": {
|
||||||
"deleteTitle": "删除共享",
|
"deleteTitle": "删除共享",
|
||||||
|
@@ -1,12 +1,91 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
import { headers } from "next/headers";
|
||||||
import { getTranslations } from "next-intl/server";
|
import { getTranslations } from "next-intl/server";
|
||||||
|
|
||||||
export async function generateMetadata(): Promise<Metadata> {
|
async function getReverseShareMetadata(alias: string) {
|
||||||
|
try {
|
||||||
|
const API_BASE_URL = process.env.API_BASE_URL || "http://localhost:3333";
|
||||||
|
const response = await fetch(`${API_BASE_URL}/reverse-shares/alias/${alias}/metadata`, {
|
||||||
|
cache: "no-store",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await response.json();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching reverse share metadata:", error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAppInfo() {
|
||||||
|
try {
|
||||||
|
const API_BASE_URL = process.env.API_BASE_URL || "http://localhost:3333";
|
||||||
|
const response = await fetch(`${API_BASE_URL}/app/info`, {
|
||||||
|
cache: "no-store",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
return { appName: "Palmr", appDescription: "File sharing platform", appLogo: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
return await response.json();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching app info:", error);
|
||||||
|
return { appName: "Palmr", appDescription: "File sharing platform", appLogo: null };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBaseUrl(): string {
|
||||||
|
const headersList = headers();
|
||||||
|
const protocol = headersList.get("x-forwarded-proto") || "http";
|
||||||
|
const host = headersList.get("x-forwarded-host") || headersList.get("host") || "localhost:3000";
|
||||||
|
return `${protocol}://${host}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateMetadata({ params }: { params: { alias: string } }): Promise<Metadata> {
|
||||||
const t = await getTranslations();
|
const t = await getTranslations();
|
||||||
|
const metadata = await getReverseShareMetadata(params.alias);
|
||||||
|
const appInfo = await getAppInfo();
|
||||||
|
|
||||||
|
const title = metadata?.name || t("reverseShares.upload.metadata.title");
|
||||||
|
const description =
|
||||||
|
metadata?.description ||
|
||||||
|
(metadata?.maxFiles
|
||||||
|
? t("reverseShares.upload.metadata.descriptionWithLimit", { limit: metadata.maxFiles })
|
||||||
|
: t("reverseShares.upload.metadata.description"));
|
||||||
|
|
||||||
|
const baseUrl = getBaseUrl();
|
||||||
|
const shareUrl = `${baseUrl}/r/${params.alias}`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: t("reverseShares.upload.metadata.title"),
|
title,
|
||||||
description: t("reverseShares.upload.metadata.description"),
|
description,
|
||||||
|
openGraph: {
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
url: shareUrl,
|
||||||
|
siteName: appInfo.appName || "Palmr",
|
||||||
|
type: "website",
|
||||||
|
images: appInfo.appLogo
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
url: appInfo.appLogo,
|
||||||
|
width: 1200,
|
||||||
|
height: 630,
|
||||||
|
alt: appInfo.appName || "Palmr",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [],
|
||||||
|
},
|
||||||
|
twitter: {
|
||||||
|
card: "summary_large_image",
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
images: appInfo.appLogo ? [appInfo.appLogo] : [],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,15 +1,96 @@
|
|||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
|
import { headers } from "next/headers";
|
||||||
import { getTranslations } from "next-intl/server";
|
import { getTranslations } from "next-intl/server";
|
||||||
|
|
||||||
interface LayoutProps {
|
interface LayoutProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
|
params: { alias: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function generateMetadata(): Promise<Metadata> {
|
async function getShareMetadata(alias: string) {
|
||||||
|
try {
|
||||||
|
const API_BASE_URL = process.env.API_BASE_URL || "http://localhost:3333";
|
||||||
|
const response = await fetch(`${API_BASE_URL}/shares/alias/${alias}/metadata`, {
|
||||||
|
cache: "no-store",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await response.json();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching share metadata:", error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAppInfo() {
|
||||||
|
try {
|
||||||
|
const API_BASE_URL = process.env.API_BASE_URL || "http://localhost:3333";
|
||||||
|
const response = await fetch(`${API_BASE_URL}/app/info`, {
|
||||||
|
cache: "no-store",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
return { appName: "Palmr", appDescription: "File sharing platform", appLogo: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
return await response.json();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching app info:", error);
|
||||||
|
return { appName: "Palmr", appDescription: "File sharing platform", appLogo: null };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBaseUrl(): string {
|
||||||
|
const headersList = headers();
|
||||||
|
const protocol = headersList.get("x-forwarded-proto") || "http";
|
||||||
|
const host = headersList.get("x-forwarded-host") || headersList.get("host") || "localhost:3000";
|
||||||
|
return `${protocol}://${host}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateMetadata({ params }: { params: { alias: string } }): Promise<Metadata> {
|
||||||
const t = await getTranslations();
|
const t = await getTranslations();
|
||||||
|
const metadata = await getShareMetadata(params.alias);
|
||||||
|
const appInfo = await getAppInfo();
|
||||||
|
|
||||||
|
const title = metadata?.name || t("share.pageTitle");
|
||||||
|
const description =
|
||||||
|
metadata?.description ||
|
||||||
|
(metadata?.totalFiles
|
||||||
|
? t("share.metadata.filesShared", { count: metadata.totalFiles + (metadata.totalFolders || 0) })
|
||||||
|
: appInfo.appDescription || t("share.metadata.defaultDescription"));
|
||||||
|
|
||||||
|
const baseUrl = getBaseUrl();
|
||||||
|
const shareUrl = `${baseUrl}/s/${params.alias}`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: `${t("share.pageTitle")}`,
|
title,
|
||||||
|
description,
|
||||||
|
openGraph: {
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
url: shareUrl,
|
||||||
|
siteName: appInfo.appName || "Palmr",
|
||||||
|
type: "website",
|
||||||
|
images: appInfo.appLogo
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
url: appInfo.appLogo,
|
||||||
|
width: 1200,
|
||||||
|
height: 630,
|
||||||
|
alt: appInfo.appName || "Palmr",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [],
|
||||||
|
},
|
||||||
|
twitter: {
|
||||||
|
card: "summary_large_image",
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
images: appInfo.appLogo ? [appInfo.appLogo] : [],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user