1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-07-24 23:39:37 +02:00

feat: implement attachment management with upload, delete, and permission checks; update serializers and models

This commit is contained in:
Sean Morley 2025-01-19 22:22:03 -05:00
parent e0fa62c1ea
commit 94c3e3d363
15 changed files with 444 additions and 10 deletions

View file

@ -0,0 +1,19 @@
# Generated by Django 5.0.8 on 2025-01-19 22:17
import adventures.models
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('adventures', '0018_attachment'),
]
operations = [
migrations.AlterField(
model_name='attachment',
name='file',
field=models.FileField(upload_to=adventures.models.PathAndRename('attachments/')),
),
]

View file

@ -0,0 +1,19 @@
# Generated by Django 5.0.8 on 2025-01-19 22:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('adventures', '0019_alter_attachment_file'),
]
operations = [
migrations.AddField(
model_name='attachment',
name='name',
field=models.CharField(default='', max_length=200),
preserve_default=False,
),
]

View file

@ -0,0 +1,18 @@
# Generated by Django 5.0.8 on 2025-01-19 22:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('adventures', '0020_attachment_name'),
]
operations = [
migrations.AlterField(
model_name='attachment',
name='name',
field=models.CharField(blank=True, max_length=200, null=True),
),
]

View file

@ -292,8 +292,9 @@ class Attachment(models.Model):
id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, primary_key=True)
user_id = models.ForeignKey(
User, on_delete=models.CASCADE, default=default_user_id)
file = models.FileField(upload_to='attachments/')
file = models.FileField(upload_to=PathAndRename('attachments/'))
adventure = models.ForeignKey(Adventure, related_name='attachments', on_delete=models.CASCADE)
name = models.CharField(max_length=200, null=True, blank=True)
def __str__(self):
return self.file.url

View file

@ -25,7 +25,7 @@ class AttachmentSerializer(CustomModelSerializer):
extension = serializers.SerializerMethodField()
class Meta:
model = Attachment
fields = ['id', 'file', 'adventure', 'extension']
fields = ['id', 'file', 'adventure', 'extension', 'name']
read_only_fields = ['id']
def get_extension(self, obj):

View file

@ -17,6 +17,7 @@ router.register(r'categories', CategoryViewSet, basename='categories')
router.register(r'ics-calendar', IcsCalendarGeneratorViewSet, basename='ics-calendar')
router.register(r'overpass', OverpassViewSet, basename='overpass')
router.register(r'search', GlobalSearchView, basename='search')
router.register(r'attachments', AttachmentViewSet, basename='attachments')
urlpatterns = [

View file

@ -11,4 +11,5 @@ from .overpass_view import *
from .reverse_geocode_view import *
from .stats_view import *
from .transportation_view import *
from .global_search_view import *
from .global_search_view import *
from .attachment_view import *

View file

@ -0,0 +1,39 @@
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from django.db.models import Q
from adventures.models import Adventure, Attachment
from adventures.serializers import AttachmentSerializer
import uuid
class AttachmentViewSet(viewsets.ModelViewSet):
serializer_class = AttachmentSerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
return Attachment.objects.filter(user_id=self.request.user)
@action(detail=True, methods=['post'])
def attachment_delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
def create(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return Response({"error": "User is not authenticated"}, status=status.HTTP_401_UNAUTHORIZED)
adventure_id = request.data.get('adventure')
try:
adventure = Adventure.objects.get(id=adventure_id)
except Adventure.DoesNotExist:
return Response({"error": "Adventure not found"}, status=status.HTTP_404_NOT_FOUND)
if adventure.user_id != request.user:
# Check if the adventure has a collection
if adventure.collection:
# Check if the user is in the collection's shared_with list
if not adventure.collection.shared_with.filter(id=request.user.id).exists():
return Response({"error": "User does not have permission to access this adventure"}, status=status.HTTP_403_FORBIDDEN)
else:
return Response({"error": "User does not own this adventure"}, status=status.HTTP_403_FORBIDDEN)
return super().create(request, *args, **kwargs)