diff --git a/backend/server/adventures/admin.py b/backend/server/adventures/admin.py index 7ac6842..ab8bfc6 100644 --- a/backend/server/adventures/admin.py +++ b/backend/server/adventures/admin.py @@ -46,8 +46,9 @@ from users.models import CustomUser class CustomUserAdmin(UserAdmin): model = CustomUser list_display = ['username', 'email', 'is_staff', 'is_active', 'image_display'] + readonly_fields = ('uuid',) fieldsets = UserAdmin.fieldsets + ( - (None, {'fields': ('profile_pic',)}), + (None, {'fields': ('profile_pic', 'uuid', 'public_profile')}), ) def image_display(self, obj): if obj.profile_pic: diff --git a/backend/server/adventures/views.py b/backend/server/adventures/views.py index 73a66ad..31c2d8e 100644 --- a/backend/server/adventures/views.py +++ b/backend/server/adventures/views.py @@ -10,11 +10,14 @@ from django.core.exceptions import PermissionDenied from worldtravel.models import VisitedRegion, Region, Country from .serializers import AdventureImageSerializer, AdventureSerializer, CollectionSerializer, NoteSerializer, TransportationSerializer, ChecklistSerializer from rest_framework.permissions import IsAuthenticated -from django.db.models import Q, Prefetch -from .permissions import CollectionShared, IsOwnerOrReadOnly, IsOwnerOrSharedWithFullAccess, IsPublicOrOwnerOrSharedWithFullAccess, IsPublicReadOnly +from django.db.models import Q +from .permissions import CollectionShared, IsOwnerOrSharedWithFullAccess, IsPublicOrOwnerOrSharedWithFullAccess from rest_framework.pagination import PageNumberPagination from django.shortcuts import get_object_or_404 from rest_framework import status +from django.contrib.auth import get_user_model + +User = get_user_model() class StandardResultsSetPagination(PageNumberPagination): page_size = 25 @@ -398,6 +401,49 @@ class CollectionViewSet(viewsets.ModelViewSet): instance._prefetched_objects_cache = {} return Response(serializer.data) + + # Adds a new user to the shared_with field of an adventure + @action(detail=True, methods=['post'], url_path='share/(?P[^/.]+)') + def share(self, request, pk=None, uuid=None): + collection = self.get_object() + if not uuid: + return Response({"error": "User UUID is required"}, status=400) + try: + user = User.objects.get(uuid=uuid, public_profile=True) + except User.DoesNotExist: + return Response({"error": "User not found"}, status=404) + + if user == request.user: + return Response({"error": "Cannot share with yourself"}, status=400) + + if collection.shared_with.filter(id=user.id).exists(): + return Response({"error": "Adventure is already shared with this user"}, status=400) + + collection.shared_with.add(user) + collection.save() + return Response({"success": f"Shared with {user.username}"}) + + @action(detail=True, methods=['post'], url_path='unshare/(?P[^/.]+)') + def unshare(self, request, pk=None, uuid=None): + if not request.user.is_authenticated: + return Response({"error": "User is not authenticated"}, status=400) + collection = self.get_object() + if not uuid: + return Response({"error": "User UUID is required"}, status=400) + try: + user = User.objects.get(uuid=uuid, public_profile=True) + except User.DoesNotExist: + return Response({"error": "User not found"}, status=404) + + if user == request.user: + return Response({"error": "Cannot unshare with yourself"}, status=400) + + if not collection.shared_with.filter(id=user.id).exists(): + return Response({"error": "Collection is not shared with this user"}, status=400) + + collection.shared_with.remove(user) + collection.save() + return Response({"success": f"Unshared with {user.username}"}) def get_queryset(self): if self.action == 'destroy': diff --git a/backend/server/users/migrations/0002_customuser_public_profile.py b/backend/server/users/migrations/0002_customuser_public_profile.py new file mode 100644 index 0000000..e8ba313 --- /dev/null +++ b/backend/server/users/migrations/0002_customuser_public_profile.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.8 on 2024-09-06 23:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='customuser', + name='public_profile', + field=models.BooleanField(default=False), + ), + ] diff --git a/backend/server/users/models.py b/backend/server/users/models.py index d1fd990..fa28f1c 100644 --- a/backend/server/users/models.py +++ b/backend/server/users/models.py @@ -6,6 +6,7 @@ from django_resized import ResizedImageField class CustomUser(AbstractUser): profile_pic = ResizedImageField(force_format="WEBP", quality=75, null=True, blank=True, upload_to='profile-pics/') uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) + public_profile = models.BooleanField(default=False) def __str__(self): return self.username \ No newline at end of file