mirror of
https://github.com/kyantech/Palmr.git
synced 2025-10-22 22:02:00 +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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -1056,7 +1056,8 @@
|
||||
"upload": {
|
||||
"metadata": {
|
||||
"title": "رفع الملفات - Palmr",
|
||||
"description": "رفع الملفات عبر الرابط المشترك"
|
||||
"description": "رفع الملفات عبر الرابط المشترك",
|
||||
"descriptionWithLimit": "تحميل الملفات (الحد الأقصى {limit} ملفات)"
|
||||
},
|
||||
"layout": {
|
||||
"defaultTitle": "رفع الملفات",
|
||||
@@ -1365,7 +1366,11 @@
|
||||
"description": "قد يكون تم حذف هذه المشاركة أو انتهت صلاحيتها."
|
||||
},
|
||||
"pageTitle": "المشاركة",
|
||||
"downloadAll": "تحميل الكل"
|
||||
"downloadAll": "تحميل الكل",
|
||||
"metadata": {
|
||||
"defaultDescription": "مشاركة الملفات بشكل آمن",
|
||||
"filesShared": "{count, plural, =1 {ملف واحد تمت مشاركته} other {# ملفات تمت مشاركتها}}"
|
||||
}
|
||||
},
|
||||
"shareActions": {
|
||||
"deleteTitle": "حذف المشاركة",
|
||||
|
@@ -1056,7 +1056,8 @@
|
||||
"upload": {
|
||||
"metadata": {
|
||||
"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": {
|
||||
"defaultTitle": "Dateien senden",
|
||||
@@ -1363,7 +1364,11 @@
|
||||
"description": "Diese Freigabe wurde möglicherweise gelöscht oder ist abgelaufen."
|
||||
},
|
||||
"pageTitle": "Freigabe",
|
||||
"downloadAll": "Alle herunterladen"
|
||||
"downloadAll": "Alle herunterladen",
|
||||
"metadata": {
|
||||
"defaultDescription": "Dateien sicher teilen",
|
||||
"filesShared": "{count, plural, =1 {1 Datei geteilt} other {# Dateien geteilt}}"
|
||||
}
|
||||
},
|
||||
"shareActions": {
|
||||
"deleteTitle": "Freigabe Löschen",
|
||||
|
@@ -1057,7 +1057,8 @@
|
||||
"upload": {
|
||||
"metadata": {
|
||||
"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": {
|
||||
"defaultTitle": "Send Files",
|
||||
@@ -1361,7 +1362,11 @@
|
||||
"title": "Share Not Found",
|
||||
"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": {
|
||||
"fileTitle": "Share File",
|
||||
|
@@ -1056,7 +1056,8 @@
|
||||
"upload": {
|
||||
"metadata": {
|
||||
"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": {
|
||||
"defaultTitle": "Enviar Archivos",
|
||||
@@ -1363,7 +1364,11 @@
|
||||
"description": "Esta compartición puede haber sido eliminada o haber expirado."
|
||||
},
|
||||
"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": {
|
||||
"deleteTitle": "Eliminar Compartir",
|
||||
|
@@ -1056,7 +1056,8 @@
|
||||
"upload": {
|
||||
"metadata": {
|
||||
"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": {
|
||||
"defaultTitle": "Envoyer des Fichiers",
|
||||
@@ -1363,7 +1364,11 @@
|
||||
"description": "Ce partage a peut-être été supprimé ou a expiré."
|
||||
},
|
||||
"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": {
|
||||
"deleteTitle": "Supprimer le Partage",
|
||||
|
@@ -1056,7 +1056,8 @@
|
||||
"upload": {
|
||||
"metadata": {
|
||||
"title": "फ़ाइलें भेजें - पाल्मर",
|
||||
"description": "साझा किए गए लिंक के माध्यम से फ़ाइलें भेजें"
|
||||
"description": "साझा किए गए लिंक के माध्यम से फ़ाइलें भेजें",
|
||||
"descriptionWithLimit": "फ़ाइलें अपलोड करें (अधिकतम {limit} फ़ाइलें)"
|
||||
},
|
||||
"layout": {
|
||||
"defaultTitle": "फ़ाइलें भेजें",
|
||||
@@ -1363,7 +1364,11 @@
|
||||
"description": "यह साझाकरण हटा दिया गया हो सकता है या समाप्त हो चुका है।"
|
||||
},
|
||||
"pageTitle": "साझाकरण",
|
||||
"downloadAll": "सभी डाउनलोड करें"
|
||||
"downloadAll": "सभी डाउनलोड करें",
|
||||
"metadata": {
|
||||
"defaultDescription": "फाइलों को सुरक्षित रूप से साझा करें",
|
||||
"filesShared": "{count, plural, =1 {1 फ़ाइल साझा की गई} other {# फ़ाइलें साझा की गईं}}"
|
||||
}
|
||||
},
|
||||
"shareActions": {
|
||||
"deleteTitle": "साझाकरण हटाएं",
|
||||
|
@@ -1056,7 +1056,8 @@
|
||||
"upload": {
|
||||
"metadata": {
|
||||
"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": {
|
||||
"defaultTitle": "Invia File",
|
||||
@@ -1363,7 +1364,11 @@
|
||||
"description": "Questa condivisione potrebbe essere stata eliminata o è scaduta."
|
||||
},
|
||||
"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": {
|
||||
"deleteTitle": "Elimina Condivisione",
|
||||
|
@@ -1056,7 +1056,8 @@
|
||||
"upload": {
|
||||
"metadata": {
|
||||
"title": "ファイルを送信 - Palmr",
|
||||
"description": "共有リンクを通じてファイルを送信"
|
||||
"description": "共有リンクを通じてファイルを送信",
|
||||
"descriptionWithLimit": "ファイルをアップロード(最大{limit}ファイル)"
|
||||
},
|
||||
"layout": {
|
||||
"defaultTitle": "ファイルを送信",
|
||||
@@ -1363,7 +1364,11 @@
|
||||
"description": "この共有は削除されたか、期限が切れている可能性があります。"
|
||||
},
|
||||
"pageTitle": "共有",
|
||||
"downloadAll": "すべてダウンロード"
|
||||
"downloadAll": "すべてダウンロード",
|
||||
"metadata": {
|
||||
"defaultDescription": "ファイルを安全に共有",
|
||||
"filesShared": "{count, plural, =1 {1 ファイルが共有されました} other {# ファイルが共有されました}}"
|
||||
}
|
||||
},
|
||||
"shareActions": {
|
||||
"deleteTitle": "共有を削除",
|
||||
|
@@ -1056,7 +1056,8 @@
|
||||
"upload": {
|
||||
"metadata": {
|
||||
"title": "파일 보내기 - Palmr",
|
||||
"description": "공유된 링크를 통해 파일 보내기"
|
||||
"description": "공유된 링크를 통해 파일 보내기",
|
||||
"descriptionWithLimit": "파일 업로드 (최대 {limit}개 파일)"
|
||||
},
|
||||
"layout": {
|
||||
"defaultTitle": "파일 보내기",
|
||||
@@ -1363,7 +1364,11 @@
|
||||
"description": "이 공유는 삭제되었거나 만료되었을 수 있습니다."
|
||||
},
|
||||
"pageTitle": "공유",
|
||||
"downloadAll": "모두 다운로드"
|
||||
"downloadAll": "모두 다운로드",
|
||||
"metadata": {
|
||||
"defaultDescription": "파일을 안전하게 공유",
|
||||
"filesShared": "{count, plural, =1 {1개 파일 공유됨} other {#개 파일 공유됨}}"
|
||||
}
|
||||
},
|
||||
"shareActions": {
|
||||
"deleteTitle": "공유 삭제",
|
||||
|
@@ -1056,7 +1056,8 @@
|
||||
"upload": {
|
||||
"metadata": {
|
||||
"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": {
|
||||
"defaultTitle": "Bestanden Verzenden",
|
||||
@@ -1363,7 +1364,11 @@
|
||||
"description": "Dit delen is mogelijk verwijderd of verlopen."
|
||||
},
|
||||
"pageTitle": "Delen",
|
||||
"downloadAll": "Alles Downloaden"
|
||||
"downloadAll": "Alles Downloaden",
|
||||
"metadata": {
|
||||
"defaultDescription": "Bestanden veilig delen",
|
||||
"filesShared": "{count, plural, =1 {1 bestand gedeeld} other {# bestanden gedeeld}}"
|
||||
}
|
||||
},
|
||||
"shareActions": {
|
||||
"deleteTitle": "Delen Verwijderen",
|
||||
|
@@ -1056,7 +1056,8 @@
|
||||
"upload": {
|
||||
"metadata": {
|
||||
"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": {
|
||||
"defaultTitle": "Wyślij pliki",
|
||||
@@ -1363,7 +1364,11 @@
|
||||
"description": "To udostępnienie mogło zostać usunięte lub wygasło."
|
||||
},
|
||||
"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": {
|
||||
"deleteTitle": "Usuń udostępnienie",
|
||||
|
@@ -1057,7 +1057,8 @@
|
||||
"upload": {
|
||||
"metadata": {
|
||||
"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": {
|
||||
"defaultTitle": "Enviar Arquivos",
|
||||
@@ -1364,7 +1365,11 @@
|
||||
"description": "Este compartilhamento pode ter sido excluído ou expirado."
|
||||
},
|
||||
"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": {
|
||||
"deleteTitle": "Excluir Compartilhamento",
|
||||
|
@@ -1056,7 +1056,8 @@
|
||||
"upload": {
|
||||
"metadata": {
|
||||
"title": "Отправка файлов - Palmr",
|
||||
"description": "Отправка файлов через общую ссылку"
|
||||
"description": "Отправка файлов через общую ссылку",
|
||||
"descriptionWithLimit": "Загрузить файлы (макс. {limit} файлов)"
|
||||
},
|
||||
"layout": {
|
||||
"defaultTitle": "Отправка файлов",
|
||||
@@ -1363,7 +1364,11 @@
|
||||
"description": "Этот общий доступ может быть удален или истек."
|
||||
},
|
||||
"pageTitle": "Общий доступ",
|
||||
"downloadAll": "Скачать все"
|
||||
"downloadAll": "Скачать все",
|
||||
"metadata": {
|
||||
"defaultDescription": "Безопасный обмен файлами",
|
||||
"filesShared": "{count, plural, =1 {1 файл отправлен} other {# файлов отправлено}}"
|
||||
}
|
||||
},
|
||||
"shareActions": {
|
||||
"deleteTitle": "Удалить Общий Доступ",
|
||||
|
@@ -1056,7 +1056,8 @@
|
||||
"upload": {
|
||||
"metadata": {
|
||||
"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": {
|
||||
"defaultTitle": "Dosya Gönder",
|
||||
@@ -1363,7 +1364,11 @@
|
||||
"description": "Bu paylaşım silinmiş veya süresi dolmuş olabilir."
|
||||
},
|
||||
"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": {
|
||||
"deleteTitle": "Paylaşımı Sil",
|
||||
|
@@ -1056,7 +1056,8 @@
|
||||
"upload": {
|
||||
"metadata": {
|
||||
"title": "上传文件 - Palmr",
|
||||
"description": "通过共享链接上传文件"
|
||||
"description": "通过共享链接上传文件",
|
||||
"descriptionWithLimit": "上传文件(最多 {limit} 个文件)"
|
||||
},
|
||||
"layout": {
|
||||
"defaultTitle": "上传文件",
|
||||
@@ -1363,7 +1364,11 @@
|
||||
"description": "该共享可能已被删除或已过期。"
|
||||
},
|
||||
"pageTitle": "共享",
|
||||
"downloadAll": "下载所有"
|
||||
"downloadAll": "下载所有",
|
||||
"metadata": {
|
||||
"defaultDescription": "安全共享文件",
|
||||
"filesShared": "{count, plural, =1 {已共享 1 个文件} other {已共享 # 个文件}}"
|
||||
}
|
||||
},
|
||||
"shareActions": {
|
||||
"deleteTitle": "删除共享",
|
||||
|
@@ -1,12 +1,91 @@
|
||||
import type { Metadata } from "next";
|
||||
import { headers } from "next/headers";
|
||||
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 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 {
|
||||
title: t("reverseShares.upload.metadata.title"),
|
||||
description: t("reverseShares.upload.metadata.description"),
|
||||
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] : [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -1,15 +1,96 @@
|
||||
import { Metadata } from "next";
|
||||
import { headers } from "next/headers";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
|
||||
interface LayoutProps {
|
||||
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 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 {
|
||||
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