Signature Containers
-Manage your signature containers and signed files
-Signature Containers
+Manage your signature containers and signed files
Pending Signing Requests
-{inv.file?.displayName || inv.file?.name || 'Unknown Signature Container'}
- {#if inv.file?.description} -{inv.file.description}
- {/if} -Invited {new Date(inv.invitedAt).toLocaleDateString()}
-Pending Signing Requests
+{inv.file?.displayName || inv.file?.name || 'Unknown Signature Container'}
+ {#if inv.file?.description} +{inv.file.description}
+ {/if} +Invited {new Date(inv.invitedAt).toLocaleDateString()}
Loading documents...
-No signature containers yet
-Create your first signature container to get started
- - Create Signature Container - -{doc.displayName || doc.name}
- - {getStatusBadge(doc.status).text} - -{doc.description}
+Loading documents...
+No signature containers yet
+Create your first signature container to get started
+ + Create Signature Container + +{file?.displayName || file?.name || 'Signature Container'}
+{file?.displayName || file?.name || 'Signature Container'}
{#if file?.description}{file.description}
{/if}Preview not available for this file type
{file.mimeType}
Preview not available
@@ -348,21 +399,37 @@ {/if}Signature Container
Name
-{file.displayName || file.name}
+{file.displayName || file.name}
Description
-{file.description}
+{file.description}
File Information
Sign Signature Container
-Scan this QR code with your eID Wallet to sign the signature container
++ {isMobileDevice() ? 'Click the button below to open your eID Wallet and sign' : 'Scan this QR code with your eID Wallet to sign the signature container'} +
1. Click the button above
+2. Your eID wallet app will open
+3. Review and sign the message
+4. The signature will be recorded automatically
+ {:else} +1. Open your eID Wallet app
+2. Scan this QR code
+3. Review and sign the message
+4. The signature will be recorded automatically
+ {/if}diff --git a/platforms/file-manager-api/src/controllers/FileController.ts b/platforms/file-manager-api/src/controllers/FileController.ts index a481aab2..06be92a4 100644 --- a/platforms/file-manager-api/src/controllers/FileController.ts +++ b/platforms/file-manager-api/src/controllers/FileController.ts @@ -26,6 +26,28 @@ export class FileController { return res.status(401).json({ error: "Authentication required" }); } + // Check file size limit (5MB) + const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB in bytes + if (req.file.size > MAX_FILE_SIZE) { + return res.status(413).json({ + error: "File size exceeds 5MB limit", + maxSize: MAX_FILE_SIZE, + fileSize: req.file.size + }); + } + + // Check user's storage quota (1GB total) + const { used, limit } = await this.fileService.getUserStorageUsage(req.user.id); + if (used + req.file.size > limit) { + return res.status(413).json({ + error: "Storage quota exceeded", + used, + limit, + fileSize: req.file.size, + available: limit - used + }); + } + const { displayName, description, folderId } = req.body; // Normalize folderId - convert string "null" to actual null @@ -338,5 +360,19 @@ export class FileController { res.status(500).json({ error: "Failed to move file" }); } }; + + getStorageUsage = async (req: Request, res: Response) => { + try { + if (!req.user) { + return res.status(401).json({ error: "Authentication required" }); + } + + const usage = await this.fileService.getUserStorageUsage(req.user.id); + res.json(usage); + } catch (error) { + console.error("Error getting storage usage:", error); + res.status(500).json({ error: "Failed to get storage usage" }); + } + }; } diff --git a/platforms/file-manager-api/src/index.ts b/platforms/file-manager-api/src/index.ts index 7dc78839..e1a3372a 100644 --- a/platforms/file-manager-api/src/index.ts +++ b/platforms/file-manager-api/src/index.ts @@ -95,6 +95,9 @@ app.patch("/api/files/:id", authGuard, fileController.updateFile); app.delete("/api/files/:id", authGuard, fileController.deleteFile); app.post("/api/files/:id/move", authGuard, fileController.moveFile); +// Storage routes +app.get("/api/storage", authGuard, fileController.getStorageUsage); + // Folder routes app.post("/api/folders", authGuard, folderController.createFolder); app.get("/api/folders", authGuard, folderController.getFolders); diff --git a/platforms/file-manager-api/src/services/FileService.ts b/platforms/file-manager-api/src/services/FileService.ts index 45d07698..84a022a3 100644 --- a/platforms/file-manager-api/src/services/FileService.ts +++ b/platforms/file-manager-api/src/services/FileService.ts @@ -317,5 +317,34 @@ export class FileService { return false; } + + async getUserStorageUsage(userId: string): Promise<{ used: number; limit: number; fileCount: number; folderCount: number }> { + const FOLDER_SIZE = 4 * 1024; // 4KB per folder + + // Get sum of all file sizes and count + const fileResult = await this.fileRepository + .createQueryBuilder('file') + .select('COALESCE(SUM(CAST(file.size AS BIGINT)), 0)', 'totalSize') + .addSelect('COUNT(file.id)', 'fileCount') + .where('file.ownerId = :userId', { userId }) + .getRawOne(); + + // Count all folders + const folderResult = await this.folderRepository + .createQueryBuilder('folder') + .select('COUNT(folder.id)', 'folderCount') + .where('folder.ownerId = :userId', { userId }) + .getRawOne(); + + const fileSize = Number(fileResult?.totalSize || 0); + const fileCount = Number(fileResult?.fileCount || 0); + const folderCount = Number(folderResult?.folderCount || 0); + const folderSize = folderCount * FOLDER_SIZE; + + const used = fileSize + folderSize; + const limit = 1073741824; // 1GB in bytes + + return { used, limit, fileCount, folderCount }; + } } diff --git a/platforms/file-manager-api/src/services/NotificationService.ts b/platforms/file-manager-api/src/services/NotificationService.ts index 8efe5e38..44df96b2 100644 --- a/platforms/file-manager-api/src/services/NotificationService.ts +++ b/platforms/file-manager-api/src/services/NotificationService.ts @@ -235,7 +235,7 @@ export class NotificationService { const fileName = file.displayName || file.name; const descriptionText = file.description ? `\nDescription: ${file.description}` : ''; const fileManagerUrl = process.env.PUBLIC_FILE_MANAGER_BASE_URL || 'http://localhost:3005'; - const fileLink = `${fileManagerUrl}/files/${file.id}`; + const fileLink = `${fileManagerUrl}/files/${file.id}?view=shared`; return `📁 File Shared @@ -264,9 +264,7 @@ Time: ${formattedTime} const sharerText = sharerName ? ` from ${sharerName}` : ''; const fileManagerUrl = process.env.PUBLIC_FILE_MANAGER_BASE_URL || 'http://localhost:3005'; - const folderLink = folder.parentFolderId - ? `${fileManagerUrl}/files?folderId=${folder.id}` - : `${fileManagerUrl}/files?folderId=${folder.id}`; + const folderLink = `${fileManagerUrl}/files?view=shared&folderId=${folder.id}`; return `📂 Folder Shared diff --git a/platforms/file-manager/.svelte-kit/generated/client/app.js b/platforms/file-manager/.svelte-kit/generated/client/app.js index ea1b6623..bc4c6a1c 100644 --- a/platforms/file-manager/.svelte-kit/generated/client/app.js +++ b/platforms/file-manager/.svelte-kit/generated/client/app.js @@ -7,7 +7,9 @@ export const nodes = [ () => import('./nodes/3'), () => import('./nodes/4'), () => import('./nodes/5'), - () => import('./nodes/6') + () => import('./nodes/6'), + () => import('./nodes/7'), + () => import('./nodes/8') ]; export const server_loads = []; @@ -15,8 +17,10 @@ export const server_loads = []; export const dictionary = { "/": [3], "/(auth)/auth": [4], - "/(protected)/files": [5,[2]], - "/(protected)/files/[id]": [6,[2]] + "/(auth)/deeplink-login": [5], + "/(protected)/files": [6,[2]], + "/(protected)/files/[id]": [7,[2]], + "/(protected)/storage": [8,[2]] }; export const hooks = { diff --git a/platforms/file-manager/.svelte-kit/generated/client/nodes/5.js b/platforms/file-manager/.svelte-kit/generated/client/nodes/5.js index 5362e6db..2b85113b 100644 --- a/platforms/file-manager/.svelte-kit/generated/client/nodes/5.js +++ b/platforms/file-manager/.svelte-kit/generated/client/nodes/5.js @@ -1 +1 @@ -export { default as component } from "../../../../src/routes/(protected)/files/+page.svelte"; \ No newline at end of file +export { default as component } from "../../../../src/routes/(auth)/deeplink-login/+page.svelte"; \ No newline at end of file diff --git a/platforms/file-manager/.svelte-kit/generated/client/nodes/6.js b/platforms/file-manager/.svelte-kit/generated/client/nodes/6.js index 8bd5dab8..5362e6db 100644 --- a/platforms/file-manager/.svelte-kit/generated/client/nodes/6.js +++ b/platforms/file-manager/.svelte-kit/generated/client/nodes/6.js @@ -1 +1 @@ -export { default as component } from "../../../../src/routes/(protected)/files/[id]/+page.svelte"; \ No newline at end of file +export { default as component } from "../../../../src/routes/(protected)/files/+page.svelte"; \ No newline at end of file diff --git a/platforms/file-manager/.svelte-kit/generated/client/nodes/7.js b/platforms/file-manager/.svelte-kit/generated/client/nodes/7.js new file mode 100644 index 00000000..8bd5dab8 --- /dev/null +++ b/platforms/file-manager/.svelte-kit/generated/client/nodes/7.js @@ -0,0 +1 @@ +export { default as component } from "../../../../src/routes/(protected)/files/[id]/+page.svelte"; \ No newline at end of file diff --git a/platforms/file-manager/.svelte-kit/generated/client/nodes/8.js b/platforms/file-manager/.svelte-kit/generated/client/nodes/8.js new file mode 100644 index 00000000..dca40a71 --- /dev/null +++ b/platforms/file-manager/.svelte-kit/generated/client/nodes/8.js @@ -0,0 +1 @@ +export { default as component } from "../../../../src/routes/(protected)/storage/+page.svelte"; \ No newline at end of file diff --git a/platforms/file-manager/.svelte-kit/generated/server/internal.js b/platforms/file-manager/.svelte-kit/generated/server/internal.js index ddd9f428..fe43d086 100644 --- a/platforms/file-manager/.svelte-kit/generated/server/internal.js +++ b/platforms/file-manager/.svelte-kit/generated/server/internal.js @@ -24,7 +24,7 @@ export const options = { app: ({ head, body, assets, nonce, env }) => "\n\n\t
\n\t\t\n\t\t\n\t\t" + head + "\n\t\n\t\n\t\tAuthenticating...
+