mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-07-24 15:29:36 +02:00
Allow for Sharing of Collections to other Public Users
This commit is contained in:
commit
4a293798eb
47 changed files with 1368 additions and 311 deletions
|
@ -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:
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 5.0.8 on 2024-09-02 13:21
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('adventures', '0004_transportation_end_date'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='collection',
|
||||
name='shared_with',
|
||||
field=models.ManyToManyField(blank=True, related_name='shared_with', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
|
@ -81,6 +81,7 @@ class Collection(models.Model):
|
|||
end_date = models.DateField(blank=True, null=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
is_archived = models.BooleanField(default=False)
|
||||
shared_with = models.ManyToManyField(User, related_name='shared_with', blank=True)
|
||||
|
||||
|
||||
# if connected adventures are private and collection is public, raise an error
|
||||
|
|
|
@ -27,4 +27,71 @@ class IsPublicReadOnly(permissions.BasePermission):
|
|||
return obj.is_public or obj.user_id == request.user
|
||||
|
||||
# Write permissions are only allowed to the owner of the object
|
||||
return obj.user_id == request.user
|
||||
|
||||
class CollectionShared(permissions.BasePermission):
|
||||
"""
|
||||
Custom permission to only allow read-only access to public objects,
|
||||
and write access to the owner of the object.
|
||||
"""
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
|
||||
# Read permissions are allowed if the object is shared with the user
|
||||
if obj.shared_with and obj.shared_with.filter(id=request.user.id).exists():
|
||||
return True
|
||||
|
||||
# Write permissions are allowed if the object is shared with the user
|
||||
if request.method not in permissions.SAFE_METHODS and obj.shared_with.filter(id=request.user.id).exists():
|
||||
return True
|
||||
|
||||
# Read permissions are allowed if the object is public
|
||||
if request.method in permissions.SAFE_METHODS:
|
||||
return obj.is_public or obj.user_id == request.user
|
||||
|
||||
# Write permissions are only allowed to the owner of the object
|
||||
return obj.user_id == request.user
|
||||
|
||||
class IsOwnerOrSharedWithFullAccess(permissions.BasePermission):
|
||||
"""
|
||||
Custom permission to allow:
|
||||
- Full access for shared users
|
||||
- Full access for owners
|
||||
- Read-only access for others on safe methods
|
||||
"""
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
# Check if the object has a collection
|
||||
if hasattr(obj, 'collection') and obj.collection:
|
||||
# Allow all actions for shared users
|
||||
if request.user in obj.collection.shared_with.all():
|
||||
return True
|
||||
|
||||
# Always allow GET, HEAD, or OPTIONS requests (safe methods)
|
||||
if request.method in permissions.SAFE_METHODS:
|
||||
return True
|
||||
|
||||
# Allow all actions for the owner
|
||||
return obj.user_id == request.user
|
||||
|
||||
class IsPublicOrOwnerOrSharedWithFullAccess(permissions.BasePermission):
|
||||
"""
|
||||
Custom permission to allow:
|
||||
- Read-only access for public objects
|
||||
- Full access for shared users
|
||||
- Full access for owners
|
||||
"""
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
# Allow read-only access for public objects
|
||||
if obj.is_public and request.method in permissions.SAFE_METHODS:
|
||||
return True
|
||||
|
||||
# Check if the object has a collection
|
||||
if hasattr(obj, 'collection') and obj.collection:
|
||||
# Allow all actions for shared users
|
||||
if request.user in obj.collection.shared_with.all():
|
||||
return True
|
||||
|
||||
# Allow all actions for the owner
|
||||
return obj.user_id == request.user
|
|
@ -8,19 +8,6 @@ class AdventureImageSerializer(serializers.ModelSerializer):
|
|||
fields = ['id', 'image', 'adventure']
|
||||
read_only_fields = ['id']
|
||||
|
||||
# def to_representation(self, instance):
|
||||
# representation = super().to_representation(instance)
|
||||
|
||||
# # Build the full URL for the image
|
||||
# request = self.context.get('request')
|
||||
# if request and instance.image:
|
||||
# public_url = request.build_absolute_uri(instance.image.url)
|
||||
# else:
|
||||
# public_url = f"{os.environ.get('PUBLIC_URL', 'http://127.0.0.1:8000').rstrip('/')}/media/{instance.image.name}"
|
||||
|
||||
# representation['image'] = public_url
|
||||
# return representation
|
||||
|
||||
def to_representation(self, instance):
|
||||
representation = super().to_representation(instance)
|
||||
if instance.image:
|
||||
|
@ -55,29 +42,6 @@ class TransportationSerializer(serializers.ModelSerializer):
|
|||
]
|
||||
read_only_fields = ['id', 'created_at', 'updated_at', 'user_id']
|
||||
|
||||
def validate(self, data):
|
||||
# Check if the collection is public and the transportation is not
|
||||
collection = data.get('collection')
|
||||
is_public = data.get('is_public', False)
|
||||
if collection and collection.is_public and not is_public:
|
||||
raise serializers.ValidationError(
|
||||
'Transportations associated with a public collection must be public.'
|
||||
)
|
||||
|
||||
# Check if the user owns the collection
|
||||
request = self.context.get('request')
|
||||
if request and collection and collection.user_id != request.user:
|
||||
raise serializers.ValidationError(
|
||||
'Transportations must be associated with collections owned by the same user.'
|
||||
)
|
||||
|
||||
return data
|
||||
|
||||
def create(self, validated_data):
|
||||
# Set the user_id to the current user
|
||||
validated_data['user_id'] = self.context['request'].user
|
||||
return super().create(validated_data)
|
||||
|
||||
class NoteSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
|
@ -87,29 +51,6 @@ class NoteSerializer(serializers.ModelSerializer):
|
|||
'is_public', 'collection', 'created_at', 'updated_at'
|
||||
]
|
||||
read_only_fields = ['id', 'created_at', 'updated_at', 'user_id']
|
||||
|
||||
def validate(self, data):
|
||||
# Check if the collection is public and the transportation is not
|
||||
collection = data.get('collection')
|
||||
is_public = data.get('is_public', False)
|
||||
if collection and collection.is_public and not is_public:
|
||||
raise serializers.ValidationError(
|
||||
'Notes associated with a public collection must be public.'
|
||||
)
|
||||
|
||||
# Check if the user owns the collection
|
||||
request = self.context.get('request')
|
||||
if request and collection and collection.user_id != request.user:
|
||||
raise serializers.ValidationError(
|
||||
'Notes must be associated with collections owned by the same user.'
|
||||
)
|
||||
|
||||
return data
|
||||
|
||||
def create(self, validated_data):
|
||||
# Set the user_id to the current user
|
||||
validated_data['user_id'] = self.context['request'].user
|
||||
return super().create(validated_data)
|
||||
|
||||
class ChecklistItemSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
|
@ -119,29 +60,15 @@ class ChecklistItemSerializer(serializers.ModelSerializer):
|
|||
]
|
||||
read_only_fields = ['id', 'created_at', 'updated_at', 'user_id', 'checklist']
|
||||
|
||||
def validate(self, data):
|
||||
# Check if the checklist is public and the checklist item is not
|
||||
checklist = data.get('checklist')
|
||||
is_checked = data.get('is_checked', False)
|
||||
if checklist and checklist.is_public and not is_checked:
|
||||
raise serializers.ValidationError(
|
||||
'Checklist items associated with a public checklist must be checked.'
|
||||
)
|
||||
|
||||
# Check if the user owns the checklist
|
||||
request = self.context.get('request')
|
||||
if request and checklist and checklist.user_id != request.user:
|
||||
raise serializers.ValidationError(
|
||||
'Checklist items must be associated with checklists owned by the same user.'
|
||||
)
|
||||
|
||||
return data
|
||||
|
||||
def create(self, validated_data):
|
||||
# Set the user_id to the current user
|
||||
validated_data['user_id'] = self.context['request'].user
|
||||
return super().create(validated_data)
|
||||
|
||||
# def validate(self, data):
|
||||
# # Check if the checklist is public and the checklist item is not
|
||||
# checklist = data.get('checklist')
|
||||
# is_checked = data.get('is_checked', False)
|
||||
# if checklist and checklist.is_public and not is_checked:
|
||||
# raise serializers.ValidationError(
|
||||
# 'Checklist items associated with a public checklist must be checked.'
|
||||
# )
|
||||
|
||||
|
||||
class ChecklistSerializer(serializers.ModelSerializer):
|
||||
items = ChecklistItemSerializer(many=True, source='checklistitem_set')
|
||||
|
@ -204,13 +131,6 @@ class ChecklistSerializer(serializers.ModelSerializer):
|
|||
'Checklists associated with a public collection must be public.'
|
||||
)
|
||||
|
||||
# Check if the user owns the checklist
|
||||
request = self.context.get('request')
|
||||
if request and collection and collection.user_id != request.user:
|
||||
raise serializers.ValidationError(
|
||||
'Checklists must be associated with collections owned by the same user.'
|
||||
)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
|
@ -225,5 +145,14 @@ class CollectionSerializer(serializers.ModelSerializer):
|
|||
class Meta:
|
||||
model = Collection
|
||||
# fields are all plus the adventures field
|
||||
fields = ['id', 'description', 'user_id', 'name', 'is_public', 'adventures', 'created_at', 'start_date', 'end_date', 'transportations', 'notes', 'updated_at', 'checklists', 'is_archived']
|
||||
fields = ['id', 'description', 'user_id', 'name', 'is_public', 'adventures', 'created_at', 'start_date', 'end_date', 'transportations', 'notes', 'updated_at', 'checklists', 'is_archived', 'shared_with']
|
||||
read_only_fields = ['id', 'created_at', 'updated_at', 'user_id']
|
||||
|
||||
def to_representation(self, instance):
|
||||
representation = super().to_representation(instance)
|
||||
# Make it display the user uuid for the shared users instead of the PK
|
||||
shared_uuids = []
|
||||
for user in instance.shared_with.all():
|
||||
shared_uuids.append(str(user.uuid))
|
||||
representation['shared_with'] = shared_uuids
|
||||
return representation
|
|
@ -6,14 +6,18 @@ from rest_framework import viewsets
|
|||
from django.db.models.functions import Lower
|
||||
from rest_framework.response import Response
|
||||
from .models import Adventure, Checklist, Collection, Transportation, Note, AdventureImage
|
||||
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 IsOwnerOrReadOnly, 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
|
||||
|
@ -28,7 +32,7 @@ from django.db.models import Q
|
|||
|
||||
class AdventureViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = AdventureSerializer
|
||||
permission_classes = [IsOwnerOrReadOnly, IsPublicReadOnly]
|
||||
permission_classes = [IsOwnerOrSharedWithFullAccess, IsPublicOrOwnerOrSharedWithFullAccess]
|
||||
pagination_class = StandardResultsSetPagination
|
||||
|
||||
def apply_sorting(self, queryset):
|
||||
|
@ -68,41 +72,36 @@ class AdventureViewSet(viewsets.ModelViewSet):
|
|||
return queryset.order_by(ordering)
|
||||
|
||||
def get_queryset(self):
|
||||
# if the user is not authenticated return only public adventures for retrieve action
|
||||
if not self.request.user.is_authenticated:
|
||||
if self.action == 'retrieve':
|
||||
return Adventure.objects.filter(is_public=True)
|
||||
return Adventure.objects.none()
|
||||
|
||||
|
||||
if self.action == 'retrieve':
|
||||
# For individual adventure retrieval, include public adventures
|
||||
return Adventure.objects.filter(
|
||||
Q(is_public=True) | Q(user_id=self.request.user.id)
|
||||
Q(is_public=True) | Q(user_id=self.request.user.id) | Q(collection__shared_with=self.request.user)
|
||||
)
|
||||
else:
|
||||
# For other actions, only include user's own adventures
|
||||
return Adventure.objects.filter(user_id=self.request.user.id)
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
# Prevent listing all adventures
|
||||
return Response({"detail": "Listing all adventures is not allowed."},
|
||||
status=status.HTTP_403_FORBIDDEN)
|
||||
# For other actions, include user's own adventures and shared adventures
|
||||
return Adventure.objects.filter(
|
||||
Q(user_id=self.request.user.id) | Q(collection__shared_with=self.request.user)
|
||||
)
|
||||
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
queryset = self.get_queryset()
|
||||
adventure = get_object_or_404(queryset, pk=kwargs['pk'])
|
||||
serializer = self.get_serializer(adventure)
|
||||
return Response(serializer.data)
|
||||
|
||||
def perform_create(self, serializer):
|
||||
adventure = serializer.save(user_id=self.request.user)
|
||||
if adventure.collection:
|
||||
adventure.is_public = adventure.collection.is_public
|
||||
adventure.save()
|
||||
|
||||
def perform_update(self, serializer):
|
||||
adventure = serializer.save()
|
||||
if adventure.collection:
|
||||
adventure.is_public = adventure.collection.is_public
|
||||
adventure.save()
|
||||
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(user_id=self.request.user)
|
||||
|
||||
|
||||
@action(detail=False, methods=['get'])
|
||||
def filtered(self, request):
|
||||
types = request.query_params.get('types', '').split(',')
|
||||
|
@ -195,6 +194,100 @@ class AdventureViewSet(viewsets.ModelViewSet):
|
|||
queryset = self.apply_sorting(queryset)
|
||||
serializer = self.get_serializer(queryset, many=True)
|
||||
return Response(serializer.data)
|
||||
|
||||
def update(self, request, *args, **kwargs):
|
||||
# Retrieve the current object
|
||||
instance = self.get_object()
|
||||
|
||||
# Partially update the instance with the request data
|
||||
serializer = self.get_serializer(instance, data=request.data, partial=True)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
# if the adventure is trying to have is_public changed and its part of a collection return an error
|
||||
if new_collection is not None:
|
||||
serializer.validated_data['is_public'] = new_collection.is_public
|
||||
elif instance.collection:
|
||||
serializer.validated_data['is_public'] = instance.collection.is_public
|
||||
|
||||
|
||||
# Retrieve the collection from the validated data
|
||||
new_collection = serializer.validated_data.get('collection')
|
||||
|
||||
user = request.user
|
||||
print(new_collection)
|
||||
|
||||
if new_collection is not None and new_collection!=instance.collection:
|
||||
# Check if the user is the owner of the new collection
|
||||
if new_collection.user_id != user or instance.user_id != user:
|
||||
raise PermissionDenied("You do not have permission to use this collection.")
|
||||
elif new_collection is None:
|
||||
# Handle the case where the user is trying to set the collection to None
|
||||
if instance.collection is not None and instance.collection.user_id != user:
|
||||
raise PermissionDenied("You cannot remove the collection as you are not the owner.")
|
||||
|
||||
# Perform the update
|
||||
self.perform_update(serializer)
|
||||
|
||||
# Return the updated instance
|
||||
return Response(serializer.data)
|
||||
|
||||
def partial_update(self, request, *args, **kwargs):
|
||||
# Retrieve the current object
|
||||
instance = self.get_object()
|
||||
|
||||
# Partially update the instance with the request data
|
||||
serializer = self.get_serializer(instance, data=request.data, partial=True)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
# Retrieve the collection from the validated data
|
||||
new_collection = serializer.validated_data.get('collection')
|
||||
|
||||
user = request.user
|
||||
print(new_collection)
|
||||
|
||||
# if the adventure is trying to have is_public changed and its part of a collection return an error
|
||||
if new_collection is not None:
|
||||
serializer.validated_data['is_public'] = new_collection.is_public
|
||||
elif instance.collection:
|
||||
serializer.validated_data['is_public'] = instance.collection.is_public
|
||||
|
||||
if new_collection is not None and new_collection!=instance.collection:
|
||||
# Check if the user is the owner of the new collection
|
||||
if new_collection.user_id != user or instance.user_id != user:
|
||||
raise PermissionDenied("You do not have permission to use this collection.")
|
||||
elif new_collection is None:
|
||||
# Handle the case where the user is trying to set the collection to None
|
||||
if instance.collection is not None and instance.collection.user_id != user:
|
||||
raise PermissionDenied("You cannot remove the collection as you are not the owner.")
|
||||
|
||||
# Perform the update
|
||||
self.perform_update(serializer)
|
||||
|
||||
# Return the updated instance
|
||||
return Response(serializer.data)
|
||||
|
||||
def perform_update(self, serializer):
|
||||
serializer.save()
|
||||
|
||||
# when creating an adventure, make sure the user is the owner of the collection or shared with the collection
|
||||
def perform_create(self, serializer):
|
||||
# Retrieve the collection from the validated data
|
||||
collection = serializer.validated_data.get('collection')
|
||||
|
||||
# Check if a collection is provided
|
||||
if collection:
|
||||
user = self.request.user
|
||||
# Check if the user is the owner or is in the shared_with list
|
||||
if collection.user_id != user and not collection.shared_with.filter(id=user.id).exists():
|
||||
# Return an error response if the user does not have permission
|
||||
raise PermissionDenied("You do not have permission to use this collection.")
|
||||
# if collection the owner of the adventure is the owner of the collection
|
||||
# set the is_public field of the adventure to the is_public field of the collection
|
||||
serializer.save(user_id=collection.user_id, is_public=collection.is_public)
|
||||
return
|
||||
|
||||
# Save the adventure with the current user as the owner
|
||||
serializer.save(user_id=self.request.user)
|
||||
|
||||
def paginate_and_respond(self, queryset, request):
|
||||
paginator = self.pagination_class()
|
||||
|
@ -207,7 +300,7 @@ class AdventureViewSet(viewsets.ModelViewSet):
|
|||
|
||||
class CollectionViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = CollectionSerializer
|
||||
permission_classes = [IsOwnerOrReadOnly, IsPublicReadOnly]
|
||||
permission_classes = [CollectionShared]
|
||||
pagination_class = StandardResultsSetPagination
|
||||
|
||||
# def get_queryset(self):
|
||||
|
@ -244,7 +337,7 @@ class CollectionViewSet(viewsets.ModelViewSet):
|
|||
# make sure the user is authenticated
|
||||
if not request.user.is_authenticated:
|
||||
return Response({"error": "User is not authenticated"}, status=400)
|
||||
queryset = self.get_queryset()
|
||||
queryset = Collection.objects.filter(user_id=request.user.id)
|
||||
queryset = self.apply_sorting(queryset)
|
||||
collections = self.paginate_and_respond(queryset, request)
|
||||
return collections
|
||||
|
@ -285,10 +378,21 @@ class CollectionViewSet(viewsets.ModelViewSet):
|
|||
serializer = self.get_serializer(instance, data=request.data, partial=partial)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
if 'collection' in serializer.validated_data:
|
||||
new_collection = serializer.validated_data['collection']
|
||||
# if the new collection is different from the old one and the user making the request is not the owner of the new collection return an error
|
||||
if new_collection != instance.collection and new_collection.user_id != request.user:
|
||||
return Response({"error": "User does not own the new collection"}, status=400)
|
||||
|
||||
# Check if the 'is_public' field is present in the update data
|
||||
if 'is_public' in serializer.validated_data:
|
||||
new_public_status = serializer.validated_data['is_public']
|
||||
|
||||
# if is_publuc has changed and the user is not the owner of the collection return an error
|
||||
if new_public_status != instance.is_public and instance.user_id != request.user:
|
||||
print(f"User {request.user.id} does not own the collection {instance.id} that is owned by {instance.user_id}")
|
||||
return Response({"error": "User does not own the collection"}, status=400)
|
||||
|
||||
# Update associated adventures to match the collection's is_public status
|
||||
Adventure.objects.filter(collection=instance).update(is_public=new_public_status)
|
||||
|
||||
|
@ -310,25 +414,86 @@ class CollectionViewSet(viewsets.ModelViewSet):
|
|||
instance._prefetched_objects_cache = {}
|
||||
|
||||
return Response(serializer.data)
|
||||
|
||||
# make an action to retreive all adventures that are shared with the user
|
||||
@action(detail=False, methods=['get'])
|
||||
def shared(self, request):
|
||||
if not request.user.is_authenticated:
|
||||
return Response({"error": "User is not authenticated"}, status=400)
|
||||
queryset = Collection.objects.filter(
|
||||
shared_with=request.user
|
||||
)
|
||||
queryset = self.apply_sorting(queryset)
|
||||
serializer = self.get_serializer(queryset, many=True)
|
||||
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<uuid>[^/.]+)')
|
||||
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<uuid>[^/.]+)')
|
||||
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':
|
||||
return Collection.objects.filter(user_id=self.request.user.id)
|
||||
|
||||
if self.action in ['update', 'partial_update']:
|
||||
return Collection.objects.filter(user_id=self.request.user.id)
|
||||
return Collection.objects.filter(
|
||||
Q(user_id=self.request.user.id) | Q(shared_with=self.request.user)
|
||||
).distinct()
|
||||
|
||||
if self.action == 'retrieve':
|
||||
if not self.request.user.is_authenticated:
|
||||
return Collection.objects.filter(is_public=True)
|
||||
return Collection.objects.filter(
|
||||
Q(is_public=True) | Q(user_id=self.request.user.id)
|
||||
)
|
||||
Q(is_public=True) | Q(user_id=self.request.user.id) | Q(shared_with=self.request.user)
|
||||
).distinct()
|
||||
|
||||
# For other actions (like list), only include user's non-archived collections
|
||||
# For list action, include collections owned by the user or shared with the user, that are not archived
|
||||
return Collection.objects.filter(
|
||||
Q(user_id=self.request.user.id) & Q(is_archived=False)
|
||||
)
|
||||
(Q(user_id=self.request.user.id) | Q(shared_with=self.request.user)) & Q(is_archived=False)
|
||||
).distinct()
|
||||
|
||||
|
||||
def perform_create(self, serializer):
|
||||
# This is ok because you cannot share a collection when creating it
|
||||
serializer.save(user_id=self.request.user)
|
||||
|
||||
def paginate_and_respond(self, queryset, request):
|
||||
|
@ -430,7 +595,7 @@ class ActivityTypesView(viewsets.ViewSet):
|
|||
class TransportationViewSet(viewsets.ModelViewSet):
|
||||
queryset = Transportation.objects.all()
|
||||
serializer_class = TransportationSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
permission_classes = [IsOwnerOrSharedWithFullAccess, IsPublicOrOwnerOrSharedWithFullAccess]
|
||||
filterset_fields = ['type', 'is_public', 'collection']
|
||||
|
||||
# return error message if user is not authenticated on the root endpoint
|
||||
|
@ -451,21 +616,108 @@ class TransportationViewSet(viewsets.ModelViewSet):
|
|||
|
||||
|
||||
def get_queryset(self):
|
||||
|
||||
"""
|
||||
This view should return a list of all transportations
|
||||
for the currently authenticated user.
|
||||
"""
|
||||
user = self.request.user
|
||||
return Transportation.objects.filter(user_id=user)
|
||||
# if the user is not authenticated return only public transportations for retrieve action
|
||||
if not self.request.user.is_authenticated:
|
||||
if self.action == 'retrieve':
|
||||
return Transportation.objects.filter(is_public=True)
|
||||
return Transportation.objects.none()
|
||||
|
||||
|
||||
if self.action == 'retrieve':
|
||||
# For individual adventure retrieval, include public adventures
|
||||
return Transportation.objects.filter(
|
||||
Q(is_public=True) | Q(user_id=self.request.user.id) | Q(collection__shared_with=self.request.user)
|
||||
)
|
||||
else:
|
||||
# For other actions, include user's own adventures and shared adventures
|
||||
return Transportation.objects.filter(
|
||||
Q(user_id=self.request.user.id) | Q(collection__shared_with=self.request.user)
|
||||
)
|
||||
|
||||
def partial_update(self, request, *args, **kwargs):
|
||||
# Retrieve the current object
|
||||
instance = self.get_object()
|
||||
|
||||
# Partially update the instance with the request data
|
||||
serializer = self.get_serializer(instance, data=request.data, partial=True)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
# Retrieve the collection from the validated data
|
||||
new_collection = serializer.validated_data.get('collection')
|
||||
|
||||
user = request.user
|
||||
print(new_collection)
|
||||
|
||||
if new_collection is not None and new_collection!=instance.collection:
|
||||
# Check if the user is the owner of the new collection
|
||||
if new_collection.user_id != user or instance.user_id != user:
|
||||
raise PermissionDenied("You do not have permission to use this collection.")
|
||||
elif new_collection is None:
|
||||
# Handle the case where the user is trying to set the collection to None
|
||||
if instance.collection is not None and instance.collection.user_id != user:
|
||||
raise PermissionDenied("You cannot remove the collection as you are not the owner.")
|
||||
|
||||
# Perform the update
|
||||
self.perform_update(serializer)
|
||||
|
||||
# Return the updated instance
|
||||
return Response(serializer.data)
|
||||
|
||||
def partial_update(self, request, *args, **kwargs):
|
||||
# Retrieve the current object
|
||||
instance = self.get_object()
|
||||
|
||||
# Partially update the instance with the request data
|
||||
serializer = self.get_serializer(instance, data=request.data, partial=True)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
# Retrieve the collection from the validated data
|
||||
new_collection = serializer.validated_data.get('collection')
|
||||
|
||||
user = request.user
|
||||
print(new_collection)
|
||||
|
||||
if new_collection is not None and new_collection!=instance.collection:
|
||||
# Check if the user is the owner of the new collection
|
||||
if new_collection.user_id != user or instance.user_id != user:
|
||||
raise PermissionDenied("You do not have permission to use this collection.")
|
||||
elif new_collection is None:
|
||||
# Handle the case where the user is trying to set the collection to None
|
||||
if instance.collection is not None and instance.collection.user_id != user:
|
||||
raise PermissionDenied("You cannot remove the collection as you are not the owner.")
|
||||
|
||||
# Perform the update
|
||||
self.perform_update(serializer)
|
||||
|
||||
# Return the updated instance
|
||||
return Response(serializer.data)
|
||||
|
||||
def perform_update(self, serializer):
|
||||
serializer.save()
|
||||
|
||||
# when creating an adventure, make sure the user is the owner of the collection or shared with the collection
|
||||
def perform_create(self, serializer):
|
||||
# Retrieve the collection from the validated data
|
||||
collection = serializer.validated_data.get('collection')
|
||||
|
||||
# Check if a collection is provided
|
||||
if collection:
|
||||
user = self.request.user
|
||||
# Check if the user is the owner or is in the shared_with list
|
||||
if collection.user_id != user and not collection.shared_with.filter(id=user.id).exists():
|
||||
# Return an error response if the user does not have permission
|
||||
raise PermissionDenied("You do not have permission to use this collection.")
|
||||
# if collection the owner of the adventure is the owner of the collection
|
||||
serializer.save(user_id=collection.user_id)
|
||||
return
|
||||
|
||||
# Save the adventure with the current user as the owner
|
||||
serializer.save(user_id=self.request.user)
|
||||
|
||||
class NoteViewSet(viewsets.ModelViewSet):
|
||||
queryset = Note.objects.all()
|
||||
serializer_class = NoteSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
permission_classes = [IsOwnerOrSharedWithFullAccess, IsPublicOrOwnerOrSharedWithFullAccess]
|
||||
filterset_fields = ['is_public', 'collection']
|
||||
|
||||
# return error message if user is not authenticated on the root endpoint
|
||||
|
@ -486,21 +738,108 @@ class NoteViewSet(viewsets.ModelViewSet):
|
|||
|
||||
|
||||
def get_queryset(self):
|
||||
|
||||
"""
|
||||
This view should return a list of all notes
|
||||
for the currently authenticated user.
|
||||
"""
|
||||
user = self.request.user
|
||||
return Note.objects.filter(user_id=user)
|
||||
# if the user is not authenticated return only public transportations for retrieve action
|
||||
if not self.request.user.is_authenticated:
|
||||
if self.action == 'retrieve':
|
||||
return Note.objects.filter(is_public=True)
|
||||
return Note.objects.none()
|
||||
|
||||
|
||||
if self.action == 'retrieve':
|
||||
# For individual adventure retrieval, include public adventures
|
||||
return Note.objects.filter(
|
||||
Q(is_public=True) | Q(user_id=self.request.user.id) | Q(collection__shared_with=self.request.user)
|
||||
)
|
||||
else:
|
||||
# For other actions, include user's own adventures and shared adventures
|
||||
return Note.objects.filter(
|
||||
Q(user_id=self.request.user.id) | Q(collection__shared_with=self.request.user)
|
||||
)
|
||||
|
||||
def partial_update(self, request, *args, **kwargs):
|
||||
# Retrieve the current object
|
||||
instance = self.get_object()
|
||||
|
||||
# Partially update the instance with the request data
|
||||
serializer = self.get_serializer(instance, data=request.data, partial=True)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
# Retrieve the collection from the validated data
|
||||
new_collection = serializer.validated_data.get('collection')
|
||||
|
||||
user = request.user
|
||||
print(new_collection)
|
||||
|
||||
if new_collection is not None and new_collection!=instance.collection:
|
||||
# Check if the user is the owner of the new collection
|
||||
if new_collection.user_id != user or instance.user_id != user:
|
||||
raise PermissionDenied("You do not have permission to use this collection.")
|
||||
elif new_collection is None:
|
||||
# Handle the case where the user is trying to set the collection to None
|
||||
if instance.collection is not None and instance.collection.user_id != user:
|
||||
raise PermissionDenied("You cannot remove the collection as you are not the owner.")
|
||||
|
||||
# Perform the update
|
||||
self.perform_update(serializer)
|
||||
|
||||
# Return the updated instance
|
||||
return Response(serializer.data)
|
||||
|
||||
def partial_update(self, request, *args, **kwargs):
|
||||
# Retrieve the current object
|
||||
instance = self.get_object()
|
||||
|
||||
# Partially update the instance with the request data
|
||||
serializer = self.get_serializer(instance, data=request.data, partial=True)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
# Retrieve the collection from the validated data
|
||||
new_collection = serializer.validated_data.get('collection')
|
||||
|
||||
user = request.user
|
||||
print(new_collection)
|
||||
|
||||
if new_collection is not None and new_collection!=instance.collection:
|
||||
# Check if the user is the owner of the new collection
|
||||
if new_collection.user_id != user or instance.user_id != user:
|
||||
raise PermissionDenied("You do not have permission to use this collection.")
|
||||
elif new_collection is None:
|
||||
# Handle the case where the user is trying to set the collection to None
|
||||
if instance.collection is not None and instance.collection.user_id != user:
|
||||
raise PermissionDenied("You cannot remove the collection as you are not the owner.")
|
||||
|
||||
# Perform the update
|
||||
self.perform_update(serializer)
|
||||
|
||||
# Return the updated instance
|
||||
return Response(serializer.data)
|
||||
|
||||
def perform_update(self, serializer):
|
||||
serializer.save()
|
||||
|
||||
# when creating an adventure, make sure the user is the owner of the collection or shared with the collection
|
||||
def perform_create(self, serializer):
|
||||
# Retrieve the collection from the validated data
|
||||
collection = serializer.validated_data.get('collection')
|
||||
|
||||
# Check if a collection is provided
|
||||
if collection:
|
||||
user = self.request.user
|
||||
# Check if the user is the owner or is in the shared_with list
|
||||
if collection.user_id != user and not collection.shared_with.filter(id=user.id).exists():
|
||||
# Return an error response if the user does not have permission
|
||||
raise PermissionDenied("You do not have permission to use this collection.")
|
||||
# if collection the owner of the adventure is the owner of the collection
|
||||
serializer.save(user_id=collection.user_id)
|
||||
return
|
||||
|
||||
# Save the adventure with the current user as the owner
|
||||
serializer.save(user_id=self.request.user)
|
||||
|
||||
class ChecklistViewSet(viewsets.ModelViewSet):
|
||||
queryset = Checklist.objects.all()
|
||||
serializer_class = ChecklistSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
permission_classes = [IsOwnerOrSharedWithFullAccess, IsPublicOrOwnerOrSharedWithFullAccess]
|
||||
filterset_fields = ['is_public', 'collection']
|
||||
|
||||
# return error message if user is not authenticated on the root endpoint
|
||||
|
@ -521,15 +860,102 @@ class ChecklistViewSet(viewsets.ModelViewSet):
|
|||
|
||||
|
||||
def get_queryset(self):
|
||||
|
||||
"""
|
||||
This view should return a list of all checklists
|
||||
for the currently authenticated user.
|
||||
"""
|
||||
user = self.request.user
|
||||
return Checklist.objects.filter(user_id=user)
|
||||
# if the user is not authenticated return only public transportations for retrieve action
|
||||
if not self.request.user.is_authenticated:
|
||||
if self.action == 'retrieve':
|
||||
return Checklist.objects.filter(is_public=True)
|
||||
return Checklist.objects.none()
|
||||
|
||||
|
||||
if self.action == 'retrieve':
|
||||
# For individual adventure retrieval, include public adventures
|
||||
return Checklist.objects.filter(
|
||||
Q(is_public=True) | Q(user_id=self.request.user.id) | Q(collection__shared_with=self.request.user)
|
||||
)
|
||||
else:
|
||||
# For other actions, include user's own adventures and shared adventures
|
||||
return Checklist.objects.filter(
|
||||
Q(user_id=self.request.user.id) | Q(collection__shared_with=self.request.user)
|
||||
)
|
||||
|
||||
def partial_update(self, request, *args, **kwargs):
|
||||
# Retrieve the current object
|
||||
instance = self.get_object()
|
||||
|
||||
# Partially update the instance with the request data
|
||||
serializer = self.get_serializer(instance, data=request.data, partial=True)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
# Retrieve the collection from the validated data
|
||||
new_collection = serializer.validated_data.get('collection')
|
||||
|
||||
user = request.user
|
||||
print(new_collection)
|
||||
|
||||
if new_collection is not None and new_collection!=instance.collection:
|
||||
# Check if the user is the owner of the new collection
|
||||
if new_collection.user_id != user or instance.user_id != user:
|
||||
raise PermissionDenied("You do not have permission to use this collection.")
|
||||
elif new_collection is None:
|
||||
# Handle the case where the user is trying to set the collection to None
|
||||
if instance.collection is not None and instance.collection.user_id != user:
|
||||
raise PermissionDenied("You cannot remove the collection as you are not the owner.")
|
||||
|
||||
# Perform the update
|
||||
self.perform_update(serializer)
|
||||
|
||||
# Return the updated instance
|
||||
return Response(serializer.data)
|
||||
|
||||
def partial_update(self, request, *args, **kwargs):
|
||||
# Retrieve the current object
|
||||
instance = self.get_object()
|
||||
|
||||
# Partially update the instance with the request data
|
||||
serializer = self.get_serializer(instance, data=request.data, partial=True)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
# Retrieve the collection from the validated data
|
||||
new_collection = serializer.validated_data.get('collection')
|
||||
|
||||
user = request.user
|
||||
print(new_collection)
|
||||
|
||||
if new_collection is not None and new_collection!=instance.collection:
|
||||
# Check if the user is the owner of the new collection
|
||||
if new_collection.user_id != user or instance.user_id != user:
|
||||
raise PermissionDenied("You do not have permission to use this collection.")
|
||||
elif new_collection is None:
|
||||
# Handle the case where the user is trying to set the collection to None
|
||||
if instance.collection is not None and instance.collection.user_id != user:
|
||||
raise PermissionDenied("You cannot remove the collection as you are not the owner.")
|
||||
|
||||
# Perform the update
|
||||
self.perform_update(serializer)
|
||||
|
||||
# Return the updated instance
|
||||
return Response(serializer.data)
|
||||
|
||||
def perform_update(self, serializer):
|
||||
serializer.save()
|
||||
|
||||
# when creating an adventure, make sure the user is the owner of the collection or shared with the collection
|
||||
def perform_create(self, serializer):
|
||||
# Retrieve the collection from the validated data
|
||||
collection = serializer.validated_data.get('collection')
|
||||
|
||||
# Check if a collection is provided
|
||||
if collection:
|
||||
user = self.request.user
|
||||
# Check if the user is the owner or is in the shared_with list
|
||||
if collection.user_id != user and not collection.shared_with.filter(id=user.id).exists():
|
||||
# Return an error response if the user does not have permission
|
||||
raise PermissionDenied("You do not have permission to use this collection.")
|
||||
# if collection the owner of the adventure is the owner of the collection
|
||||
serializer.save(user_id=collection.user_id)
|
||||
return
|
||||
|
||||
# Save the adventure with the current user as the owner
|
||||
serializer.save(user_id=self.request.user)
|
||||
|
||||
class AdventureImageViewSet(viewsets.ModelViewSet):
|
||||
|
@ -555,7 +981,13 @@ class AdventureImageViewSet(viewsets.ModelViewSet):
|
|||
return Response({"error": "Adventure not found"}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
if adventure.user_id != request.user:
|
||||
return Response({"error": "User does not own this adventure"}, status=status.HTTP_403_FORBIDDEN)
|
||||
# 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)
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ from django.views.generic import RedirectView, TemplateView
|
|||
from django.conf import settings
|
||||
from django.conf.urls.static import static
|
||||
from adventures import urls as adventures
|
||||
from users.views import ChangeEmailView, IsRegistrationDisabled
|
||||
from users.views import ChangeEmailView, IsRegistrationDisabled, PublicUserListView, PublicUserDetailView
|
||||
from .views import get_csrf_token
|
||||
from drf_yasg.views import get_schema_view
|
||||
|
||||
|
@ -22,6 +22,8 @@ urlpatterns = [
|
|||
|
||||
path('auth/change-email/', ChangeEmailView.as_view(), name='change_email'),
|
||||
path('auth/is-registration-disabled/', IsRegistrationDisabled.as_view(), name='is_registration_disabled'),
|
||||
path('auth/users/', PublicUserListView.as_view(), name='public-user-list'),
|
||||
path('auth/user/<uuid:user_id>/', PublicUserDetailView.as_view(), name='public-user-detail'),
|
||||
|
||||
path('csrf/', get_csrf_token, name='get_csrf_token'),
|
||||
re_path(r'^$', TemplateView.as_view(
|
||||
|
|
|
@ -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),
|
||||
),
|
||||
]
|
|
@ -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
|
|
@ -1,7 +1,7 @@
|
|||
from rest_framework import serializers
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
from adventures.models import Adventure
|
||||
from adventures.models import Adventure, Collection
|
||||
from users.forms import CustomAllAuthPasswordResetForm
|
||||
from dj_rest_auth.serializers import PasswordResetSerializer
|
||||
from rest_framework.exceptions import PermissionDenied
|
||||
|
@ -133,8 +133,6 @@ class UserDetailsSerializer(serializers.ModelSerializer):
|
|||
@staticmethod
|
||||
def validate_username(username):
|
||||
if 'allauth.account' not in settings.INSTALLED_APPS:
|
||||
# We don't need to call the all-auth
|
||||
# username validator unless it's installed
|
||||
return username
|
||||
|
||||
from allauth.account.adapter import get_adapter
|
||||
|
@ -142,12 +140,9 @@ class UserDetailsSerializer(serializers.ModelSerializer):
|
|||
return username
|
||||
|
||||
class Meta:
|
||||
extra_fields = ['profile_pic']
|
||||
extra_fields = ['profile_pic', 'uuid', 'public_profile']
|
||||
profile_pic = serializers.ImageField(required=False)
|
||||
# see https://github.com/iMerica/dj-rest-auth/issues/181
|
||||
# UserModel.XYZ causing attribute error while importing other
|
||||
# classes from `serializers.py`. So, we need to check whether the auth model has
|
||||
# the attribute or not
|
||||
|
||||
if hasattr(UserModel, 'USERNAME_FIELD'):
|
||||
extra_fields.append(UserModel.USERNAME_FIELD)
|
||||
if hasattr(UserModel, 'EMAIL_FIELD'):
|
||||
|
@ -160,21 +155,38 @@ class UserDetailsSerializer(serializers.ModelSerializer):
|
|||
extra_fields.append('date_joined')
|
||||
if hasattr(UserModel, 'is_staff'):
|
||||
extra_fields.append('is_staff')
|
||||
if hasattr(UserModel, 'public_profile'):
|
||||
extra_fields.append('public_profile')
|
||||
|
||||
class Meta(UserDetailsSerializer.Meta):
|
||||
model = CustomUser
|
||||
fields = UserDetailsSerializer.Meta.fields + ('profile_pic',)
|
||||
|
||||
fields = UserDetailsSerializer.Meta.fields + ('profile_pic', 'uuid', 'public_profile')
|
||||
|
||||
model = UserModel
|
||||
fields = ('pk', *extra_fields)
|
||||
read_only_fields = ('email', 'date_joined', 'is_staff', 'is_superuser', 'is_active', 'pk')
|
||||
|
||||
def handle_public_profile_change(self, instance, validated_data):
|
||||
"""Remove user from `shared_with` if public profile is set to False."""
|
||||
if 'public_profile' in validated_data and not validated_data['public_profile']:
|
||||
for collection in Collection.objects.filter(shared_with=instance):
|
||||
collection.shared_with.remove(instance)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
self.handle_public_profile_change(instance, validated_data)
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
def partial_update(self, instance, validated_data):
|
||||
self.handle_public_profile_change(instance, validated_data)
|
||||
return super().partial_update(instance, validated_data)
|
||||
|
||||
|
||||
class CustomUserDetailsSerializer(UserDetailsSerializer):
|
||||
|
||||
|
||||
class Meta(UserDetailsSerializer.Meta):
|
||||
model = CustomUser
|
||||
fields = UserDetailsSerializer.Meta.fields + ('profile_pic',)
|
||||
fields = UserDetailsSerializer.Meta.fields + ('profile_pic', 'uuid', 'public_profile')
|
||||
|
||||
def to_representation(self, instance):
|
||||
representation = super().to_representation(instance)
|
||||
|
|
|
@ -6,6 +6,11 @@ from .serializers import ChangeEmailSerializer
|
|||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_yasg import openapi
|
||||
from django.conf import settings
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.contrib.auth import get_user_model
|
||||
from .serializers import CustomUserDetailsSerializer as PublicUserSerializer
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
class ChangeEmailView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
@ -41,4 +46,40 @@ class IsRegistrationDisabled(APIView):
|
|||
)
|
||||
def get(self, request):
|
||||
return Response({"is_disabled": settings.DISABLE_REGISTRATION, "message": settings.DISABLE_REGISTRATION_MESSAGE}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
class PublicUserListView(APIView):
|
||||
# Allow the listing of all public users
|
||||
permission_classes = []
|
||||
|
||||
@swagger_auto_schema(
|
||||
responses={
|
||||
200: openapi.Response('List of public users'),
|
||||
400: 'Bad Request'
|
||||
},
|
||||
operation_description="List public users."
|
||||
)
|
||||
def get(self, request):
|
||||
users = User.objects.filter(public_profile=True).exclude(id=request.user.id)
|
||||
# remove the email addresses from the response
|
||||
for user in users:
|
||||
user.email = None
|
||||
serializer = PublicUserSerializer(users, many=True)
|
||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||
|
||||
class PublicUserDetailView(APIView):
|
||||
# Allow the retrieval of a single public user
|
||||
permission_classes = []
|
||||
|
||||
@swagger_auto_schema(
|
||||
responses={
|
||||
200: openapi.Response('Public user information'),
|
||||
400: 'Bad Request'
|
||||
},
|
||||
operation_description="Get public user information."
|
||||
)
|
||||
def get(self, request, user_id):
|
||||
user = get_object_or_404(User, uuid=user_id, public_profile=True)
|
||||
# remove the email address from the response
|
||||
user.email = None
|
||||
serializer = PublicUserSerializer(user)
|
||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue