diff --git a/safeshare/safeshare-frontend/src/pages/downloadFile.js b/safeshare/safeshare-frontend/src/pages/downloadFile.js
index 1c706d0..b0e80e7 100644
--- a/safeshare/safeshare-frontend/src/pages/downloadFile.js
+++ b/safeshare/safeshare-frontend/src/pages/downloadFile.js
@@ -1,6 +1,6 @@
-import React, { useState } from 'react';
+import React, {useState} from 'react';
import axios from 'axios';
-import { Link } from 'react-router-dom';
+import {Link} from 'react-router-dom';
function DownloadFile() {
const [passcode, setPasscode] = useState('');
@@ -12,37 +12,42 @@ function DownloadFile() {
const handleDownloadFile = () => {
if (passcode) {
- axios.get(`http://127.0.0.1:8000/api/files/${passcode}/`)
+ axios.get(`http://127.0.0.1:8000/api/files/${passcode}/`, {responseType: 'blob'})
.then(response => {
- // print json data from response
- console.log(response.data);
- const fileData = response.data.file;
- if (fileData) {
- // Convert the data to a Blob
- const blob = new Blob([fileData], { type: 'application/octet-stream' });
+ let filename = 'downloaded_file'; // Default filename
- // Create a temporary URL for the Blob
- const url = window.URL.createObjectURL(blob);
+ // Check if the Content-Disposition header exists
+ if (response.headers['content-disposition']) {
+ const contentDisposition = response.headers['content-disposition'];
+ const filenameMatch = contentDisposition.match(/filename="(.+)"/);
- // Create a dynamically generated anchor element
- const a = document.createElement('a');
- a.href = url;
- a.download = response.data.filename;
-
- // Trigger a click event on the anchor element to simulate a download
- a.click();
-
- // Clean up the temporary URL
- window.URL.revokeObjectURL(url);
+ if (filenameMatch) {
+ filename = filenameMatch[1];
+ }
}
+
+ const blob = new Blob([response.data], {type: 'application/octet-stream'});
+
+ const url = window.URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = filename;
+
+ a.style.display = 'none';
+ document.body.appendChild(a);
+ a.click();
+
+ // Clean up the temporary URL and remove the dynamically created anchor element
+ window.URL.revokeObjectURL(url);
+ document.body.removeChild(a);
})
.catch(error => {
- // print error if any
console.log(error);
});
}
};
+
return (
@@ -61,7 +66,8 @@ function DownloadFile() {
className="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring focus:border-blue-300"
/>
-
diff --git a/safeshare/safeshare/settings.py b/safeshare/safeshare/settings.py
index 9f3bc6f..be54820 100644
--- a/safeshare/safeshare/settings.py
+++ b/safeshare/safeshare/settings.py
@@ -95,6 +95,10 @@ CORS_ALLOWED_ORIGINS = [
'http://localhost:3000',
]
+CORS_EXPOSE_HEADERS = [
+ 'Content-Disposition',
+]
+
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
@@ -177,6 +181,12 @@ AUTH_PASSWORD_VALIDATORS = [
},
]
+# Media Storage
+MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
+
+if not os.path.exists(MEDIA_ROOT):
+ os.makedirs(MEDIA_ROOT)
+
# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/
diff --git a/safeshare/safeshare_app/views/file.py b/safeshare/safeshare_app/views/file.py
index 556d05c..8530e11 100644
--- a/safeshare/safeshare_app/views/file.py
+++ b/safeshare/safeshare_app/views/file.py
@@ -1,13 +1,17 @@
import threading
import uuid
+import os
from django.core.cache import cache
from rest_framework.decorators import api_view
from rest_framework.response import Response
+from django.http import HttpResponse
+from django.conf import settings
+from urllib.parse import quote
-@api_view(['GET', 'POST'])
-def manage_items(request, *args, **kwargs):
+@api_view(['POST'])
+def manage_items(request):
if request.method == 'POST':
# Define a timeout value (in seconds)
timeout = 5
@@ -15,6 +19,7 @@ def manage_items(request, *args, **kwargs):
# Get the list of files and the TTL value from the request data
files = request.FILES.getlist('file')
ttl = request.data.get('ttl')
+
if not ttl:
# Set ttl to 3 days
ttl = 259200 # 3 * 24 * 60 * 60
@@ -28,28 +33,33 @@ def manage_items(request, *args, **kwargs):
except ValueError:
return Response({'msg': 'Invalid TTL format'}, status=400)
- # Define a function to save a single file in a thread
- def save_file_to_redis(file):
+ # Define a function to save a single file
+ def save_file_locally(file):
key = uuid.uuid4().hex
# Get the filename
filename = file.name
- # Convert file to bytes
- content = file.read()
+ # Define the path to save the file locally
+ save_path = os.path.join(settings.MEDIA_ROOT, filename)
- # Set with the provided TTL
+ # Save the file locally
+ with open(save_path, 'wb') as destination:
+ for chunk in file.chunks():
+ destination.write(chunk)
+
+ # Store the file path in the cache with the provided TTL
cache.set(key,
{
'filename': filename,
- 'content': content
+ 'path': save_path,
},
timeout=ttl)
response = {
'key': key,
'filename': filename,
- 'msg': f"{key} successfully set to {filename} with TTL {ttl} seconds"
+ 'msg': f"{key} successfully set to {filename} with TTL {ttl} seconds",
}
# Append the response to the shared responses list
@@ -61,7 +71,7 @@ def manage_items(request, *args, **kwargs):
# Create a thread for each file
file_threads = []
for file in files:
- file_thread = threading.Thread(target=save_file_to_redis, args=(file,))
+ file_thread = threading.Thread(target=save_file_locally, args=(file,))
file_threads.append(file_thread)
# Start all file-saving threads
@@ -93,62 +103,79 @@ def manage_items(request, *args, **kwargs):
@api_view(['GET', 'PUT', 'DELETE'])
def manage_item(request, *args, **kwargs):
if request.method == 'GET':
- if kwargs['key']:
+ if 'key' in kwargs:
value = cache.get(kwargs['key'])
if value:
- response = {
- 'key': kwargs['key'],
- 'file': value['content'],
- 'filename': value['filename'],
- 'msg': 'success'
- }
- return Response(response, status=200)
+ # Check if the 'path' key is in the stored value
+ if 'path' in value:
+ file_path = value['path']
+ if os.path.exists(file_path):
+ with open(file_path, 'rb') as f:
+ response = HttpResponse(f.read(), content_type='application/octet-stream')
+ response['Content-Disposition'] = f'attachment; filename="{quote(value["filename"])}"'
+ return response
+ else:
+ response = {
+ 'msg': 'File not found'
+ }
+ return Response(response, status=404)
else:
response = {
- 'key': kwargs['key'],
- 'file': None,
- 'filename': None,
'msg': 'Not found'
}
return Response(response, status=404)
- # elif request.method == 'PUT':
- # if kwargs['key']:
- # request_data = json.loads(request.body)
- # new_value = request_data['value']
- # value = redis_instance.get(kwargs['key'])
- # if value:
- # redis_instance.set(kwargs['key'], new_value)
- # response = {
- # 'key': kwargs['key'],
- # 'file': value,
- # 'msg': f"Successfully updated {kwargs['key']}"
- # }
- # return Response(response, status=200)
- # else:
- # response = {
- # 'key': kwargs['key'],
- # 'value': None,
- # 'msg': 'Not found'
- # }
- # return Response(response, status=404)
-
elif request.method == 'DELETE':
- if kwargs['key']:
- result = cache.delete(kwargs['key'])
- if result == 1:
- response = {
- 'msg': f"{kwargs['key']} successfully deleted"
- }
- return Response(response, status=404)
+ if 'key' in kwargs:
+ value = cache.get(kwargs['key'])
+ if value:
+ if 'path' in value:
+ file_path = value['path']
+
+ # Check if the file exists
+ if os.path.exists(file_path):
+ # Delete the file
+ os.remove(file_path)
+
+ # Delete the cache entry
+ cache.delete(kwargs['key'])
+
+ response = {
+ 'msg': f"{kwargs['key']} successfully deleted"
+ }
+ return Response(response, status=200)
+ else:
+ response = {
+ 'msg': 'File not found'
+ }
+ return Response(response, status=404)
else:
response = {
'key': kwargs['key'],
- 'file': None,
'msg': 'Not found'
}
return Response(response, status=404)
+# elif request.method == 'PUT':
+# if kwargs['key']:
+# request_data = json.loads(request.body)
+# new_value = request_data['value']
+# value = redis_instance.get(kwargs['key'])
+# if value:
+# redis_instance.set(kwargs['key'], new_value)
+# response = {
+# 'key': kwargs['key'],
+# 'file': value,
+# 'msg': f"Successfully updated {kwargs['key']}"
+# }
+# return Response(response, status=200)
+# else:
+# response = {
+# 'key': kwargs['key'],
+# 'value': None,
+# 'msg': 'Not found'
+# }
+# return Response(response, status=404)
# class FileView(viewsets.ModelViewSet):
# queryset = File.objects.all()
# serializer_class = FileSerializer