Remove chunked upload code (no longer needed with direct bypass)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
8220ad5d3b
commit
9214aed499
|
|
@ -10,8 +10,6 @@ from portal.views_shared_space import (
|
|||
SharedSpaceLogoutView,
|
||||
SharedSpaceUploadAPIView,
|
||||
SharedSpaceFileListView,
|
||||
ChunkedUploadInitView,
|
||||
ChunkedUploadChunkView,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -20,7 +18,5 @@ urlpatterns = [
|
|||
path('login/', SharedSpaceLoginView.as_view(), name='shared_space_login'),
|
||||
path('logout/', SharedSpaceLogoutView.as_view(), name='shared_space_logout'),
|
||||
path('api/upload/', SharedSpaceUploadAPIView.as_view(), name='shared_space_upload'),
|
||||
path('api/upload/init/', ChunkedUploadInitView.as_view(), name='chunked_upload_init'),
|
||||
path('api/upload/chunk/', ChunkedUploadChunkView.as_view(), name='chunked_upload_chunk'),
|
||||
path('files/', SharedSpaceFileListView.as_view(), name='shared_space_files'),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -5,11 +5,6 @@ Each topic is accessible via a subdomain (e.g., cofi.rfiles.online).
|
|||
Anyone can view files and upload new ones - no password required.
|
||||
"""
|
||||
|
||||
import os
|
||||
import uuid
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.files.base import File
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.http import JsonResponse, Http404
|
||||
from django.views import View
|
||||
|
|
@ -18,8 +13,6 @@ from django.utils.decorators import method_decorator
|
|||
|
||||
from files.models import SharedSpace, MediaFile, PublicShare
|
||||
|
||||
CHUNK_UPLOAD_DIR = os.path.join(settings.MEDIA_ROOT, 'chunks')
|
||||
|
||||
|
||||
def get_topic_or_404(request):
|
||||
"""Get the topic (shared space) from the request's subdomain slug."""
|
||||
|
|
@ -224,171 +217,6 @@ class DirectUploadAPIView(View):
|
|||
})
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name='dispatch')
|
||||
class ChunkedUploadInitView(View):
|
||||
"""Initialize a chunked upload session."""
|
||||
|
||||
def post(self, request):
|
||||
space = get_topic_or_404(request)
|
||||
filename = request.POST.get('filename', '')
|
||||
total_size = int(request.POST.get('total_size', 0))
|
||||
total_chunks = int(request.POST.get('total_chunks', 0))
|
||||
mime_type = request.POST.get('mime_type', 'application/octet-stream')
|
||||
action = request.POST.get('action', '')
|
||||
|
||||
if not filename or total_chunks < 1:
|
||||
return JsonResponse({'error': 'Invalid parameters'}, status=400)
|
||||
|
||||
if space.max_file_size_mb > 0:
|
||||
max_size_bytes = space.max_file_size_mb * 1024 * 1024
|
||||
if total_size > max_size_bytes:
|
||||
return JsonResponse({
|
||||
'error': f'File too large. Maximum size is {space.max_file_size_mb}MB'
|
||||
}, status=400)
|
||||
|
||||
# Check for duplicate
|
||||
existing = MediaFile.objects.filter(
|
||||
shared_space=space,
|
||||
original_filename=filename,
|
||||
).first()
|
||||
|
||||
if existing and action != 'overwrite':
|
||||
existing_share = existing.public_shares.filter(is_active=True).first()
|
||||
return JsonResponse({
|
||||
'duplicate': True,
|
||||
'existing_file': {
|
||||
'id': str(existing.id),
|
||||
'title': existing.title,
|
||||
'filename': existing.original_filename,
|
||||
'size': existing.file_size,
|
||||
'share_url': existing_share.get_public_url() if existing_share else None,
|
||||
},
|
||||
}, status=409)
|
||||
|
||||
upload_id = str(uuid.uuid4())
|
||||
chunk_dir = os.path.join(CHUNK_UPLOAD_DIR, upload_id)
|
||||
os.makedirs(chunk_dir, exist_ok=True)
|
||||
|
||||
# Store metadata
|
||||
import json
|
||||
meta = {
|
||||
'filename': filename,
|
||||
'total_size': total_size,
|
||||
'total_chunks': total_chunks,
|
||||
'mime_type': mime_type,
|
||||
'space_id': str(space.id),
|
||||
'action': action,
|
||||
}
|
||||
with open(os.path.join(chunk_dir, 'meta.json'), 'w') as f:
|
||||
json.dump(meta, f)
|
||||
|
||||
return JsonResponse({'upload_id': upload_id})
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name='dispatch')
|
||||
class ChunkedUploadChunkView(View):
|
||||
"""Receive a single chunk and finalize when all chunks are received."""
|
||||
|
||||
def post(self, request):
|
||||
space = get_topic_or_404(request)
|
||||
upload_id = request.POST.get('upload_id', '')
|
||||
chunk_index = int(request.POST.get('chunk_index', -1))
|
||||
chunk_file = request.FILES.get('chunk')
|
||||
|
||||
if not upload_id or chunk_index < 0 or not chunk_file:
|
||||
return JsonResponse({'error': 'Invalid parameters'}, status=400)
|
||||
|
||||
chunk_dir = os.path.join(CHUNK_UPLOAD_DIR, upload_id)
|
||||
meta_path = os.path.join(chunk_dir, 'meta.json')
|
||||
if not os.path.isdir(chunk_dir) or not os.path.exists(meta_path):
|
||||
return JsonResponse({'error': 'Invalid upload_id'}, status=400)
|
||||
|
||||
import json
|
||||
with open(meta_path) as f:
|
||||
meta = json.load(f)
|
||||
|
||||
# Verify this chunk belongs to this space
|
||||
if meta['space_id'] != str(space.id):
|
||||
return JsonResponse({'error': 'Space mismatch'}, status=403)
|
||||
|
||||
# Write chunk to disk
|
||||
chunk_path = os.path.join(chunk_dir, f'{chunk_index:06d}')
|
||||
with open(chunk_path, 'wb') as f:
|
||||
for part in chunk_file.chunks():
|
||||
f.write(part)
|
||||
|
||||
# Check if all chunks received
|
||||
received = len([
|
||||
n for n in os.listdir(chunk_dir)
|
||||
if n != 'meta.json'
|
||||
])
|
||||
|
||||
if received < meta['total_chunks']:
|
||||
return JsonResponse({
|
||||
'received': received,
|
||||
'total': meta['total_chunks'],
|
||||
})
|
||||
|
||||
# All chunks received — assemble the file
|
||||
assembled_path = os.path.join(chunk_dir, 'assembled')
|
||||
with open(assembled_path, 'wb') as out:
|
||||
for i in range(meta['total_chunks']):
|
||||
part_path = os.path.join(chunk_dir, f'{i:06d}')
|
||||
with open(part_path, 'rb') as part:
|
||||
while True:
|
||||
buf = part.read(8192)
|
||||
if not buf:
|
||||
break
|
||||
out.write(buf)
|
||||
|
||||
# Handle overwrite
|
||||
if meta['action'] == 'overwrite':
|
||||
existing = MediaFile.objects.filter(
|
||||
shared_space=space,
|
||||
original_filename=meta['filename'],
|
||||
).first()
|
||||
if existing:
|
||||
existing.file.delete(save=False)
|
||||
existing.delete()
|
||||
|
||||
# Create MediaFile from assembled file
|
||||
with open(assembled_path, 'rb') as f:
|
||||
django_file = File(f, name=meta['filename'])
|
||||
media_file = MediaFile.objects.create(
|
||||
file=django_file,
|
||||
original_filename=meta['filename'],
|
||||
title=meta['filename'],
|
||||
mime_type=meta['mime_type'],
|
||||
uploaded_by=request.user if request.user.is_authenticated else None,
|
||||
shared_space=space,
|
||||
)
|
||||
|
||||
share = PublicShare.objects.create(
|
||||
media_file=media_file,
|
||||
created_by=request.user if request.user.is_authenticated else None,
|
||||
note=f'Uploaded to topic: {space.slug}',
|
||||
)
|
||||
|
||||
# Cleanup chunk directory
|
||||
import shutil
|
||||
shutil.rmtree(chunk_dir, ignore_errors=True)
|
||||
|
||||
return JsonResponse({
|
||||
'success': True,
|
||||
'file': {
|
||||
'id': str(media_file.id),
|
||||
'title': media_file.title,
|
||||
'filename': media_file.original_filename,
|
||||
'size': media_file.file_size,
|
||||
'mime_type': media_file.mime_type,
|
||||
},
|
||||
'share': {
|
||||
'token': share.token,
|
||||
'url': share.get_public_url(),
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
class SharedSpaceFileListView(View):
|
||||
"""List all files in the topic."""
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue