diff --git a/src/hooks/useFileOperations.js b/src/hooks/useFileOperations.js
index 0ea8c35..084766b 100644
--- a/src/hooks/useFileOperations.js
+++ b/src/hooks/useFileOperations.js
@@ -66,11 +66,25 @@ export const useFileOperations = () => {
}
}, []);
+ const downloadFile = useCallback(async (filename) => {
+ setIsLoading(true);
+ try {
+ const res = await fetch(`/api/files/download?file=${encodeURIComponent(filename)}`);
+ if (res.ok) {
+ return await res.text();
+ }
+ throw new Error('Failed to download file');
+ } finally {
+ setIsLoading(false);
+ }
+ }, []);
+
return {
createFile,
updateFile,
deleteFile,
getFiles,
+ downloadFile,
isLoading,
};
};
diff --git a/src/pages/api/files/[id].js b/src/pages/api/files/[id].js
new file mode 100644
index 0000000..420815d
--- /dev/null
+++ b/src/pages/api/files/[id].js
@@ -0,0 +1,60 @@
+// src/pages/api/files/[id].js
+import dbConnect from '@/lib/mongodb';
+import { verifyToken } from '@/lib/auth';
+import File from '@/models/File';
+
+export default async function handler(req, res) {
+ await dbConnect();
+
+ if (req.method !== 'DELETE') {
+ return res.status(405).json({ error: 'Method not allowed' });
+ }
+
+ try {
+ const user = await verifyToken(req);
+ const { id } = req.query;
+
+ if (!id) {
+ return res.status(400).json({ error: 'File ID is required' });
+ }
+
+ // Find the file
+ const file = await File.findById(id);
+ if (!file) {
+ return res.status(404).json({ error: 'File not found' });
+ }
+
+ // Check if user is the owner
+ if (file.owner.toString() === user._id.toString()) {
+ // User is owner - delete the file completely
+ await File.findByIdAndDelete(id);
+ return res.status(200).json({
+ message: 'File deleted successfully',
+ deletedFile: file
+ });
+ }
+
+ // Check if user is a collaborator
+ const collaboratorIndex = file.collaborators.findIndex(
+ collab => collab.user.toString() === user._id.toString()
+ );
+
+ if (collaboratorIndex !== -1) {
+ // User is collaborator - remove them from collaborators (unshare)
+ file.collaborators.splice(collaboratorIndex, 1);
+ await file.save();
+
+ return res.status(200).json({
+ message: 'File unshared successfully',
+ unsharedFile: file
+ });
+ }
+
+ // User has no access to the file
+ return res.status(403).json({ error: 'Access denied' });
+
+ } catch (error) {
+ console.error('Delete error:', error);
+ res.status(500).json({ error: 'Failed to delete file' });
+ }
+}
\ No newline at end of file
diff --git a/src/pages/api/files/database.js b/src/pages/api/files/database.js
index 34c6452..14425d6 100644
--- a/src/pages/api/files/database.js
+++ b/src/pages/api/files/database.js
@@ -105,9 +105,21 @@ export default async function handler(req, res) {
}
if (req.method === 'GET') {
- const files = Array.from(fileDatabase.values());
- console.log('Getting files, database size:', fileDatabase.size);
- res.status(200).json(files);
+ const { id } = req.query;
+
+ if (id) {
+ // Get specific file by ID
+ const file = fileDatabase.get(id);
+ if (!file) {
+ return res.status(404).json({ error: 'File not found' });
+ }
+ res.status(200).json(file);
+ } else {
+ // Get all files
+ const files = Array.from(fileDatabase.values());
+ console.log('Getting files, database size:', fileDatabase.size);
+ res.status(200).json(files);
+ }
} else if (req.method === 'POST') {
const { name, content, type } = req.body;
const fileId = `file_${Date.now()}`;
diff --git a/src/pages/api/files/download.js b/src/pages/api/files/download.js
new file mode 100644
index 0000000..6215c9f
--- /dev/null
+++ b/src/pages/api/files/download.js
@@ -0,0 +1,71 @@
+// src/pages/api/files/download.js
+import dbConnect from '@/lib/mongodb';
+import { verifyToken } from '@/lib/auth';
+
+// Simple in-memory storage for files (replace with your actual database logic)
+let fileStorage = new Map();
+
+export default async function handler(req, res) {
+ if (req.method !== 'GET') {
+ return res.status(405).json({ error: 'Method not allowed' });
+ }
+
+ try {
+ await dbConnect();
+ const user = await verifyToken(req);
+ const { file: filename } = req.query;
+
+ if (!filename) {
+ return res.status(400).json({ error: 'Filename is required' });
+ }
+
+ // Get files from the database endpoint
+ const dbResponse = await fetch(`${getBaseUrl(req)}/api/files/database`, {
+ headers: {
+ 'Cookie': req.headers.cookie || ''
+ }
+ });
+
+ if (!dbResponse.ok) {
+ throw new Error('Failed to fetch files from database');
+ }
+
+ const files = await dbResponse.json();
+ const file = files.find(f => f.name === filename);
+
+ if (!file) {
+ return res.status(404).json({ error: 'File not found' });
+ }
+
+ // Set headers for file download
+ res.setHeader('Content-Type', 'text/plain');
+ res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
+
+ // Send file content
+ res.status(200).send(file.content || '');
+ } catch (error) {
+ console.error('Download error:', error);
+
+ // Fallback: try to get file from localStorage data
+ try {
+ const files = JSON.parse(localStorage.getItem('orbitos-files') || '[]');
+ const file = files.find(f => f.name === filename);
+
+ if (file) {
+ res.setHeader('Content-Type', 'text/plain');
+ res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
+ return res.status(200).send(file.content || '');
+ }
+ } catch (fallbackError) {
+ console.error('Fallback download also failed:', fallbackError);
+ }
+
+ res.status(500).json({ error: 'Failed to download file' });
+ }
+}
+
+function getBaseUrl(req) {
+ const host = req.headers.host;
+ const protocol = req.headers['x-forwarded-proto'] || 'http';
+ return `${protocol}://${host}`;
+}
\ No newline at end of file
diff --git a/src/pages/api/files/index.js b/src/pages/api/files/index.js
index 8e6eac5..c986cb6 100644
--- a/src/pages/api/files/index.js
+++ b/src/pages/api/files/index.js
@@ -11,7 +11,8 @@ export default async function handler(req, res) {
try {
const files = await File.find({
$or: [{ owner: user._id }, { 'collaborators.user': user._id }],
- }).populate('owner', 'username');
+ }).populate('owner', 'username _id'); // Include _id in populate
+
res.json({ files });
} catch (error) {
res.status(500).json({ error: 'Failed to fetch files' });
diff --git a/src/pages/apps/filemanager.js b/src/pages/apps/filemanager.js
index 187783b..3502087 100644
--- a/src/pages/apps/filemanager.js
+++ b/src/pages/apps/filemanager.js
@@ -3,8 +3,9 @@
import React, { useState, useEffect } from 'react';
import { useTheme } from '@/context/ThemeContext';
import { useDrive } from '@/context/DriveContext';
+import { useAuth } from '@/context/AuthContext';
-const FileItem = ({ item, source, theme, onDownload, onShare, onDelete }) => {
+const FileItem = ({ item, source, theme, onDownload, onShare, onDelete, currentUserId }) => {
const isGdrive = source === 'gdrive';
const icon = isGdrive ? (
@@ -17,6 +18,9 @@ const FileItem = ({ item, source, theme, onDownload, onShare, onDelete }) => {
// Get the correct file ID - use item.id for Google Drive, item._id for local files
const fileId = item.id || item._id;
+ // Check if current user is the owner (for local files)
+ const isOwner = !isGdrive && item.owner && item.owner._id === currentUserId;
+
return (