2024-10-30 15:11:00 -04:00
import json
2024-08-16 20:31:39 -04:00
import uuid
2024-07-11 20:59:55 -04:00
import requests
2024-07-15 18:51:05 -04:00
from django . db import transaction
2024-07-08 11:44:39 -04:00
from rest_framework . decorators import action
from rest_framework import viewsets
2024-07-11 20:25:56 -04:00
from django . db . models . functions import Lower
2024-07-08 11:44:39 -04:00
from rest_framework . response import Response
2024-11-14 09:37:35 -05:00
from . models import Adventure , Checklist , Collection , Transportation , Note , AdventureImage , Category
2024-09-02 10:29:51 -04:00
from django . core . exceptions import PermissionDenied
2024-07-10 18:05:12 -04:00
from worldtravel . models import VisitedRegion , Region , Country
2024-11-14 09:37:35 -05:00
from . serializers import AdventureImageSerializer , AdventureSerializer , CategorySerializer , CollectionSerializer , NoteSerializer , TransportationSerializer , ChecklistSerializer
2024-07-08 11:44:39 -04:00
from rest_framework . permissions import IsAuthenticated
2024-09-06 19:50:19 -04:00
from django . db . models import Q
from . permissions import CollectionShared , IsOwnerOrSharedWithFullAccess , IsPublicOrOwnerOrSharedWithFullAccess
2024-07-11 19:27:03 -04:00
from rest_framework . pagination import PageNumberPagination
2024-07-15 19:53:20 -04:00
from django . shortcuts import get_object_or_404
from rest_framework import status
2024-09-06 19:50:19 -04:00
from django . contrib . auth import get_user_model
User = get_user_model ( )
2024-07-11 19:27:03 -04:00
class StandardResultsSetPagination ( PageNumberPagination ) :
2024-08-04 22:19:09 -04:00
page_size = 25
2024-07-11 19:27:03 -04:00
page_size_query_param = ' page_size '
max_page_size = 1000
from rest_framework . pagination import PageNumberPagination
from rest_framework . decorators import action
from rest_framework . response import Response
from django . db . models import Q
2024-07-08 11:44:39 -04:00
class AdventureViewSet ( viewsets . ModelViewSet ) :
serializer_class = AdventureSerializer
2024-09-02 10:29:51 -04:00
permission_classes = [ IsOwnerOrSharedWithFullAccess , IsPublicOrOwnerOrSharedWithFullAccess ]
2024-07-11 19:27:03 -04:00
pagination_class = StandardResultsSetPagination
2024-07-08 11:44:39 -04:00
2024-07-13 10:28:45 -04:00
def apply_sorting ( self , queryset ) :
2024-07-19 09:05:47 -04:00
order_by = self . request . query_params . get ( ' order_by ' , ' updated_at ' )
2024-07-13 10:28:45 -04:00
order_direction = self . request . query_params . get ( ' order_direction ' , ' asc ' )
2024-07-15 18:01:49 -04:00
include_collections = self . request . query_params . get ( ' include_collections ' , ' true ' )
2024-07-13 10:28:45 -04:00
2024-10-21 15:28:45 -04:00
valid_order_by = [ ' name ' , ' type ' , ' start_date ' , ' rating ' , ' updated_at ' ]
2024-07-13 10:28:45 -04:00
if order_by not in valid_order_by :
order_by = ' name '
if order_direction not in [ ' asc ' , ' desc ' ] :
order_direction = ' asc '
# Apply case-insensitive sorting for the 'name' field
if order_by == ' name ' :
queryset = queryset . annotate ( lower_name = Lower ( ' name ' ) )
ordering = ' lower_name '
else :
ordering = order_by
if order_direction == ' desc ' :
ordering = f ' - { ordering } '
2024-07-19 09:05:47 -04:00
# reverse ordering for updated_at field
if order_by == ' updated_at ' :
2024-07-18 15:48:14 -04:00
if order_direction == ' asc ' :
2024-07-19 09:05:47 -04:00
ordering = ' -updated_at '
2024-07-18 15:48:14 -04:00
else :
2024-07-19 09:05:47 -04:00
ordering = ' updated_at '
2024-07-18 15:48:14 -04:00
2024-07-13 10:28:45 -04:00
print ( f " Ordering by: { ordering } " ) # For debugging
2024-07-15 12:09:20 -04:00
if include_collections == ' false ' :
queryset = queryset . filter ( collection = None )
2024-07-13 10:28:45 -04:00
return queryset . order_by ( ordering )
2024-07-08 11:44:39 -04:00
def get_queryset ( self ) :
2024-09-27 22:14:34 -04:00
# if the user is not authenticated return only public adventures for retrieve action
2024-09-02 22:27:07 -04:00
if not self . request . user . is_authenticated :
if self . action == ' retrieve ' :
2024-09-27 22:16:56 -04:00
return Adventure . objects . filter ( is_public = True ) . distinct ( ) . order_by ( ' -updated_at ' )
2024-09-02 22:27:07 -04:00
return Adventure . objects . none ( )
2024-07-15 19:53:20 -04:00
if self . action == ' retrieve ' :
# For individual adventure retrieval, include public adventures
return Adventure . objects . filter (
2024-09-02 10:29:51 -04:00
Q ( is_public = True ) | Q ( user_id = self . request . user . id ) | Q ( collection__shared_with = self . request . user )
2024-09-27 22:16:56 -04:00
) . distinct ( ) . order_by ( ' -updated_at ' )
2024-07-15 19:53:20 -04:00
else :
2024-09-02 10:29:51 -04:00
# 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 )
2024-09-27 22:16:56 -04:00
) . distinct ( ) . order_by ( ' -updated_at ' )
2024-07-15 19:53:20 -04:00
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 )
2024-07-16 09:26:45 -04:00
def perform_update ( self , serializer ) :
adventure = serializer . save ( )
if adventure . collection :
adventure . is_public = adventure . collection . is_public
adventure . save ( )
2024-09-02 10:29:51 -04:00
2024-07-08 11:44:39 -04:00
@action ( detail = False , methods = [ ' get ' ] )
2024-07-11 19:27:03 -04:00
def filtered ( self , request ) :
types = request . query_params . get ( ' types ' , ' ' ) . split ( ' , ' )
2024-10-31 09:59:56 -04:00
is_visited = request . query_params . get ( ' is_visited ' , ' all ' )
# Handle case where types is all
2024-09-30 18:03:10 -04:00
if ' all ' in types :
types = [ t [ 0 ] for t in ADVENTURE_TYPES ]
2024-09-23 18:19:25 -04:00
valid_types = [ t [ 0 ] for t in ADVENTURE_TYPES ]
2024-07-11 19:27:03 -04:00
types = [ t for t in types if t in valid_types ]
2024-07-08 11:44:39 -04:00
2024-07-11 19:27:03 -04:00
if not types :
return Response ( { " error " : " No valid types provided " } , status = 400 )
2024-07-08 11:44:39 -04:00
2024-10-31 09:59:56 -04:00
queryset = Adventure . objects . filter (
type__in = types ,
user_id = request . user . id
)
# Handle is_visited filtering
if is_visited . lower ( ) == ' true ' :
serializer = self . get_serializer ( queryset , many = True )
filtered_ids = [
adventure . id for adventure , serialized_adventure in zip ( queryset , serializer . data )
if serialized_adventure [ ' is_visited ' ]
]
queryset = queryset . filter ( id__in = filtered_ids )
elif is_visited . lower ( ) == ' false ' :
serializer = self . get_serializer ( queryset , many = True )
filtered_ids = [
adventure . id for adventure , serialized_adventure in zip ( queryset , serializer . data )
if not serialized_adventure [ ' is_visited ' ]
]
queryset = queryset . filter ( id__in = filtered_ids )
# If is_visited is 'all' or any other value, we don't apply additional filtering
# Apply sorting
2024-07-13 10:28:45 -04:00
queryset = self . apply_sorting ( queryset )
2024-10-31 09:59:56 -04:00
# Paginate and respond
2024-07-11 20:25:56 -04:00
adventures = self . paginate_and_respond ( queryset , request )
return adventures
2024-10-31 09:59:56 -04:00
2024-07-12 22:07:36 -04:00
@action ( detail = False , methods = [ ' get ' ] )
def all ( self , request ) :
if not request . user . is_authenticated :
return Response ( { " error " : " User is not authenticated " } , status = 400 )
2024-10-04 21:56:43 -04:00
include_collections = request . query_params . get ( ' include_collections ' , ' false ' )
if include_collections not in [ ' true ' , ' false ' ] :
include_collections = ' false '
if include_collections == ' true ' :
queryset = Adventure . objects . filter (
Q ( is_public = True ) | Q ( user_id = request . user . id )
)
else :
queryset = Adventure . objects . filter (
Q ( is_public = True ) | Q ( user_id = request . user . id ) , collection = None
)
2024-07-15 12:09:20 -04:00
queryset = Adventure . objects . filter (
2024-10-04 21:56:43 -04:00
Q ( user_id = request . user . id )
2024-07-15 12:09:20 -04:00
)
queryset = self . apply_sorting ( queryset )
2024-07-13 10:48:51 -04:00
serializer = self . get_serializer ( queryset , many = True )
2024-07-15 12:09:20 -04:00
2024-07-13 10:48:51 -04:00
return Response ( serializer . data )
2024-07-17 17:36:05 -04:00
@action ( detail = False , methods = [ ' get ' ] )
def search ( self , request ) :
query = self . request . query_params . get ( ' query ' , ' ' )
2024-08-01 10:02:00 -04:00
property = self . request . query_params . get ( ' property ' , ' all ' )
2024-07-18 14:55:23 -04:00
if len ( query ) < 2 :
return Response ( { " error " : " Query must be at least 2 characters long " } , status = 400 )
2024-08-01 10:02:00 -04:00
if property not in [ ' name ' , ' type ' , ' location ' , ' description ' , ' activity_types ' ] :
property = ' all '
queryset = Adventure . objects . none ( )
if property == ' name ' :
queryset = Adventure . objects . filter (
( Q ( name__icontains = query ) ) &
( Q ( user_id = request . user . id ) | Q ( is_public = True ) )
)
elif property == ' type ' :
queryset = Adventure . objects . filter (
( Q ( type__icontains = query ) ) &
( Q ( user_id = request . user . id ) | Q ( is_public = True ) )
)
elif property == ' location ' :
queryset = Adventure . objects . filter (
( Q ( location__icontains = query ) ) &
( Q ( user_id = request . user . id ) | Q ( is_public = True ) )
)
elif property == ' description ' :
queryset = Adventure . objects . filter (
( Q ( description__icontains = query ) ) &
( Q ( user_id = request . user . id ) | Q ( is_public = True ) )
)
elif property == ' activity_types ' :
queryset = Adventure . objects . filter (
( Q ( activity_types__icontains = query ) ) &
( Q ( user_id = request . user . id ) | Q ( is_public = True ) )
)
else :
queryset = Adventure . objects . filter (
( Q ( name__icontains = query ) | Q ( description__icontains = query ) | Q ( location__icontains = query ) | Q ( activity_types__icontains = query ) ) &
( Q ( user_id = request . user . id ) | Q ( is_public = True ) )
)
2024-07-17 17:36:05 -04:00
queryset = self . apply_sorting ( queryset )
2024-07-22 10:08:42 -04:00
serializer = self . get_serializer ( queryset , many = True )
return Response ( serializer . data )
2024-09-02 10:29:51 -04:00
2024-09-09 14:29:50 -04:00
def update ( self , request , * args , * * kwargs ) :
2024-09-02 22:27:07 -04:00
# Retrieve the current object
2024-09-02 10:29:51 -04:00
instance = self . get_object ( )
2024-09-02 22:27:07 -04:00
# Partially update the instance with the request data
2024-09-02 10:29:51 -04:00
serializer = self . get_serializer ( instance , data = request . data , partial = True )
serializer . is_valid ( raise_exception = True )
2024-09-02 22:27:07 -04:00
2024-09-09 14:29:50 -04:00
# if the adventure is trying to have is_public changed and its part of a collection return an error
2024-09-09 23:47:09 -04:00
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
2024-09-09 14:29:50 -04:00
2024-09-02 22:27:07 -04:00
# 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
2024-09-02 10:29:51 -04:00
self . perform_update ( serializer )
2024-09-02 22:27:07 -04:00
# Return the updated instance
2024-09-02 10:29:51 -04:00
return Response ( serializer . data )
def partial_update ( self , request , * args , * * kwargs ) :
2024-09-02 22:27:07 -04:00
# Retrieve the current object
2024-09-02 10:29:51 -04:00
instance = self . get_object ( )
2024-09-02 22:27:07 -04:00
# Partially update the instance with the request data
2024-09-02 10:29:51 -04:00
serializer = self . get_serializer ( instance , data = request . data , partial = True )
serializer . is_valid ( raise_exception = True )
2024-09-02 22:27:07 -04:00
# Retrieve the collection from the validated data
new_collection = serializer . validated_data . get ( ' collection ' )
user = request . user
print ( new_collection )
2024-09-09 14:29:50 -04:00
# if the adventure is trying to have is_public changed and its part of a collection return an error
2024-09-09 23:47:09 -04:00
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
2024-09-09 14:29:50 -04:00
2024-09-02 22:27:07 -04:00
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
2024-09-02 10:29:51 -04:00
self . perform_update ( serializer )
2024-09-02 22:27:07 -04:00
# Return the updated instance
2024-09-02 10:29:51 -04:00
return Response ( serializer . data )
2024-09-02 22:27:07 -04:00
2024-09-03 10:24:11 -04:00
def perform_update ( self , serializer ) :
serializer . save ( )
2024-09-02 10:29:51 -04:00
# when creating an adventure, make sure the user is the owner of the collection or shared with the collection
2024-09-27 22:14:34 -04:00
@transaction.atomic
2024-09-02 10:29:51 -04:00
def perform_create ( self , serializer ) :
# Retrieve the collection from the validated data
collection = serializer . validated_data . get ( ' collection ' )
2024-09-09 14:29:50 -04:00
2024-09-02 10:29:51 -04:00
# Check if a collection is provided
if collection :
2024-09-02 17:18:18 -04:00
user = self . request . user
2024-09-02 10:29:51 -04:00
# Check if the user is the owner or is in the shared_with list
2024-09-02 17:18:18 -04:00
if collection . user_id != user and not collection . shared_with . filter ( id = user . id ) . exists ( ) :
2024-09-02 10:29:51 -04:00
# Return an error response if the user does not have permission
raise PermissionDenied ( " You do not have permission to use this collection. " )
2024-09-02 17:18:18 -04:00
# if collection the owner of the adventure is the owner of the collection
2024-09-09 14:29:50 -04:00
# 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 )
2024-09-02 17:18:18 -04:00
return
2024-09-02 10:29:51 -04:00
# Save the adventure with the current user as the owner
2024-09-02 17:18:18 -04:00
serializer . save ( user_id = self . request . user )
2024-07-11 19:27:03 -04:00
def paginate_and_respond ( self , queryset , request ) :
paginator = self . pagination_class ( )
page = paginator . paginate_queryset ( queryset , request )
if page is not None :
serializer = self . get_serializer ( page , many = True )
return paginator . get_paginated_response ( serializer . data )
serializer = self . get_serializer ( queryset , many = True )
2024-07-09 13:26:39 -04:00
return Response ( serializer . data )
2024-07-15 09:36:07 -04:00
class CollectionViewSet ( viewsets . ModelViewSet ) :
serializer_class = CollectionSerializer
2024-09-02 10:29:51 -04:00
permission_classes = [ CollectionShared ]
2024-07-15 09:36:07 -04:00
pagination_class = StandardResultsSetPagination
2024-08-07 13:01:12 -04:00
# def get_queryset(self):
# return Collection.objects.filter(Q(user_id=self.request.user.id) & Q(is_archived=False))
2024-07-30 07:10:41 -04:00
2024-07-15 09:36:07 -04:00
def apply_sorting ( self , queryset ) :
order_by = self . request . query_params . get ( ' order_by ' , ' name ' )
order_direction = self . request . query_params . get ( ' order_direction ' , ' asc ' )
2024-08-05 14:17:41 -04:00
valid_order_by = [ ' name ' , ' upated_at ' ]
2024-07-15 09:36:07 -04:00
if order_by not in valid_order_by :
2024-08-05 14:17:41 -04:00
order_by = ' updated_at '
2024-07-15 09:36:07 -04:00
if order_direction not in [ ' asc ' , ' desc ' ] :
order_direction = ' asc '
# Apply case-insensitive sorting for the 'name' field
if order_by == ' name ' :
queryset = queryset . annotate ( lower_name = Lower ( ' name ' ) )
ordering = ' lower_name '
2024-08-05 14:17:41 -04:00
if order_direction == ' desc ' :
ordering = f ' - { ordering } '
2024-07-15 09:36:07 -04:00
else :
2024-08-05 14:17:41 -04:00
order_by == ' updated_at '
ordering = ' updated_at '
if order_direction == ' asc ' :
ordering = ' -updated_at '
2024-07-15 09:36:07 -04:00
2024-08-05 14:17:41 -04:00
#print(f"Ordering by: {ordering}") # For debugging
2024-07-15 09:36:07 -04:00
return queryset . order_by ( ordering )
2024-07-15 18:51:05 -04:00
2024-07-16 09:12:53 -04:00
def list ( self , request , * args , * * kwargs ) :
# make sure the user is authenticated
if not request . user . is_authenticated :
return Response ( { " error " : " User is not authenticated " } , status = 400 )
2024-09-02 22:27:07 -04:00
queryset = Collection . objects . filter ( user_id = request . user . id )
2024-07-16 09:12:53 -04:00
queryset = self . apply_sorting ( queryset )
collections = self . paginate_and_respond ( queryset , request )
return collections
@action ( detail = False , methods = [ ' get ' ] )
def all ( self , request ) :
if not request . user . is_authenticated :
return Response ( { " error " : " User is not authenticated " } , status = 400 )
queryset = Collection . objects . filter (
Q ( user_id = request . user . id )
)
queryset = self . apply_sorting ( queryset )
serializer = self . get_serializer ( queryset , many = True )
return Response ( serializer . data )
2024-08-07 13:01:12 -04:00
@action ( detail = False , methods = [ ' get ' ] )
def archived ( self , request ) :
if not request . user . is_authenticated :
return Response ( { " error " : " User is not authenticated " } , status = 400 )
queryset = Collection . objects . filter (
Q ( user_id = request . user . id ) & Q ( is_archived = True )
)
queryset = self . apply_sorting ( queryset )
serializer = self . get_serializer ( queryset , many = True )
return Response ( serializer . data )
2024-07-15 18:51:05 -04:00
# this make the is_public field of the collection cascade to the adventures
@transaction.atomic
def update ( self , request , * args , * * kwargs ) :
partial = kwargs . pop ( ' partial ' , False )
instance = self . get_object ( )
serializer = self . get_serializer ( instance , data = request . data , partial = partial )
serializer . is_valid ( raise_exception = True )
2024-09-02 17:18:18 -04:00
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 )
2024-07-15 18:51:05 -04:00
# 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 ' ]
2024-09-09 14:29:50 -04:00
# 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 )
2024-07-15 18:51:05 -04:00
# Update associated adventures to match the collection's is_public status
Adventure . objects . filter ( collection = instance ) . update ( is_public = new_public_status )
2024-07-27 19:04:55 -04:00
# do the same for transportations
Transportation . objects . filter ( collection = instance ) . update ( is_public = new_public_status )
2024-08-03 21:09:49 -04:00
# do the same for notes
Note . objects . filter ( collection = instance ) . update ( is_public = new_public_status )
2024-07-15 18:51:05 -04:00
# Log the action (optional)
action = " public " if new_public_status else " private "
print ( f " Collection { instance . id } and its adventures were set to { action } " )
self . perform_update ( serializer )
if getattr ( instance , ' _prefetched_objects_cache ' , None ) :
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance . _prefetched_objects_cache = { }
return Response ( serializer . data )
2024-09-09 13:44:42 -04:00
# 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 )
2024-09-06 19:50:19 -04:00
# 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 } " } )
2024-07-09 13:26:39 -04:00
def get_queryset ( self ) :
2024-08-07 13:01:12 -04:00
if self . action == ' destroy ' :
return Collection . objects . filter ( user_id = self . request . user . id )
if self . action in [ ' update ' , ' partial_update ' ] :
2024-09-02 10:29:51 -04:00
return Collection . objects . filter (
Q ( user_id = self . request . user . id ) | Q ( shared_with = self . request . user )
) . distinct ( )
2024-07-30 07:10:41 -04:00
if self . action == ' retrieve ' :
2024-09-09 14:29:50 -04:00
if not self . request . user . is_authenticated :
return Collection . objects . filter ( is_public = True )
2024-08-07 13:01:12 -04:00
return Collection . objects . filter (
2024-09-02 10:29:51 -04:00
Q ( is_public = True ) | Q ( user_id = self . request . user . id ) | Q ( shared_with = self . request . user )
) . distinct ( )
2024-07-30 07:10:41 -04:00
2024-09-02 10:29:51 -04:00
# For list action, include collections owned by the user or shared with the user, that are not archived
2024-08-07 13:01:12 -04:00
return Collection . objects . filter (
2024-09-02 10:29:51 -04:00
( Q ( user_id = self . request . user . id ) | Q ( shared_with = self . request . user ) ) & Q ( is_archived = False )
) . distinct ( )
2024-07-09 13:26:39 -04:00
def perform_create ( self , serializer ) :
2024-09-02 10:29:51 -04:00
# This is ok because you cannot share a collection when creating it
2024-07-09 13:26:39 -04:00
serializer . save ( user_id = self . request . user )
2024-07-15 09:36:07 -04:00
def paginate_and_respond ( self , queryset , request ) :
paginator = self . pagination_class ( )
page = paginator . paginate_queryset ( queryset , request )
if page is not None :
serializer = self . get_serializer ( page , many = True )
return paginator . get_paginated_response ( serializer . data )
serializer = self . get_serializer ( queryset , many = True )
2024-07-10 17:27:43 -04:00
return Response ( serializer . data )
class StatsViewSet ( viewsets . ViewSet ) :
permission_classes = [ IsAuthenticated ]
@action ( detail = False , methods = [ ' get ' ] )
def counts ( self , request ) :
2024-10-09 14:48:59 -04:00
adventure_count = Adventure . objects . filter (
user_id = request . user . id ) . count ( )
2024-07-15 09:36:07 -04:00
trips_count = Collection . objects . filter (
2024-07-10 17:27:43 -04:00
user_id = request . user . id ) . count ( )
2024-07-10 18:05:12 -04:00
visited_region_count = VisitedRegion . objects . filter (
2024-07-10 17:27:43 -04:00
user_id = request . user . id ) . count ( )
2024-07-10 18:05:12 -04:00
total_regions = Region . objects . count ( )
2024-07-10 17:27:43 -04:00
country_count = VisitedRegion . objects . filter (
user_id = request . user . id ) . values ( ' region__country ' ) . distinct ( ) . count ( )
2024-07-10 18:05:12 -04:00
total_countries = Country . objects . count ( )
2024-07-10 17:27:43 -04:00
return Response ( {
2024-10-09 14:48:59 -04:00
' adventure_count ' : adventure_count ,
2024-07-10 17:27:43 -04:00
' trips_count ' : trips_count ,
2024-07-10 18:05:12 -04:00
' visited_region_count ' : visited_region_count ,
' total_regions ' : total_regions ,
2024-07-10 17:27:43 -04:00
' country_count ' : country_count ,
2024-07-10 18:05:12 -04:00
' total_countries ' : total_countries
2024-07-11 20:59:55 -04:00
} )
class GenerateDescription ( viewsets . ViewSet ) :
permission_classes = [ IsAuthenticated ]
@action ( detail = False , methods = [ ' get ' ] , )
def desc ( self , request ) :
name = self . request . query_params . get ( ' name ' , ' ' )
# un url encode the name
name = name . replace ( ' % 20 ' , ' ' )
print ( name )
url = ' https://en.wikipedia.org/w/api.php?origin=*&action=query&prop=extracts&exintro&explaintext&format=json&titles= %s ' % name
response = requests . get ( url )
data = response . json ( )
data = response . json ( )
page_id = next ( iter ( data [ " query " ] [ " pages " ] ) )
extract = data [ " query " ] [ " pages " ] [ page_id ]
if extract . get ( ' extract ' ) is None :
return Response ( { " error " : " No description found " } , status = 400 )
return Response ( extract )
@action ( detail = False , methods = [ ' get ' ] , )
def img ( self , request ) :
name = self . request . query_params . get ( ' name ' , ' ' )
# un url encode the name
name = name . replace ( ' % 20 ' , ' ' )
url = ' https://en.wikipedia.org/w/api.php?origin=*&action=query&prop=pageimages&format=json&piprop=original&titles= %s ' % name
response = requests . get ( url )
data = response . json ( )
page_id = next ( iter ( data [ " query " ] [ " pages " ] ) )
extract = data [ " query " ] [ " pages " ] [ page_id ]
if extract . get ( ' original ' ) is None :
return Response ( { " error " : " No image found " } , status = 400 )
return Response ( extract [ " original " ] )
2024-07-17 19:35:02 -04:00
class ActivityTypesView ( viewsets . ViewSet ) :
permission_classes = [ IsAuthenticated ]
@action ( detail = False , methods = [ ' get ' ] )
def types ( self , request ) :
"""
Retrieve a list of distinct activity types for adventures associated with the current user .
Args :
request ( HttpRequest ) : The HTTP request object .
Returns :
Response : A response containing a list of distinct activity types .
"""
types = Adventure . objects . filter ( user_id = request . user . id ) . values_list ( ' activity_types ' , flat = True ) . distinct ( )
allTypes = [ ]
for i in types :
if not i :
continue
for x in i :
if x and x not in allTypes :
allTypes . append ( x )
return Response ( allTypes )
2024-11-14 09:37:35 -05:00
class CategoryViewSet ( viewsets . ViewSet ) :
permission_classes = [ IsAuthenticated ]
@action ( detail = False , methods = [ ' get ' ] )
def categories ( self , request ) :
"""
Retrieve a list of distinct categories for adventures associated with the current user .
Args :
request ( HttpRequest ) : The HTTP request object .
Returns :
Response : A response containing a list of distinct categories .
"""
categories = Category . objects . filter ( user_id = request . user . id ) . distinct ( )
serializer = CategorySerializer ( categories , many = True )
return Response ( serializer . data )
2024-07-27 19:04:55 -04:00
class TransportationViewSet ( viewsets . ModelViewSet ) :
queryset = Transportation . objects . all ( )
serializer_class = TransportationSerializer
2024-09-03 10:24:11 -04:00
permission_classes = [ IsOwnerOrSharedWithFullAccess , IsPublicOrOwnerOrSharedWithFullAccess ]
2024-07-27 19:04:55 -04:00
filterset_fields = [ ' type ' , ' is_public ' , ' collection ' ]
# return error message if user is not authenticated on the root endpoint
def list ( self , request , * args , * * kwargs ) :
# Prevent listing all adventures
2024-08-03 22:03:27 -04:00
return Response ( { " detail " : " Listing all transportations is not allowed. " } ,
2024-07-27 19:04:55 -04:00
status = status . HTTP_403_FORBIDDEN )
2024-07-27 19:22:01 -04:00
@action ( detail = False , methods = [ ' get ' ] )
def all ( self , request ) :
if not request . user . is_authenticated :
return Response ( { " error " : " User is not authenticated " } , status = 400 )
queryset = Transportation . objects . filter (
Q ( user_id = request . user . id )
)
serializer = self . get_serializer ( queryset , many = True )
return Response ( serializer . data )
2024-07-27 19:04:55 -04:00
def get_queryset ( self ) :
2024-09-03 10:24:11 -04:00
# if the user is not authenticated return only public transportations for retrieve action
if not self . request . user . is_authenticated :
if self . action == ' retrieve ' :
2024-09-27 22:21:36 -04:00
return Transportation . objects . filter ( is_public = True ) . distinct ( ) . order_by ( ' -updated_at ' )
2024-09-03 10:24:11 -04:00
return Transportation . objects . none ( )
2024-07-27 19:04:55 -04:00
2024-09-03 10:24:11 -04:00
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 )
2024-09-27 22:21:36 -04:00
) . distinct ( ) . order_by ( ' -updated_at ' )
2024-09-03 10:24:11 -04:00
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 )
2024-09-27 22:21:36 -04:00
) . distinct ( ) . order_by ( ' -updated_at ' )
2024-09-03 10:24:11 -04:00
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 )
2024-07-27 19:04:55 -04:00
2024-09-03 10:24:11 -04:00
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
2024-07-27 19:04:55 -04:00
def perform_create ( self , serializer ) :
2024-09-03 10:24:11 -04:00
# 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
2024-07-27 19:04:55 -04:00
serializer . save ( user_id = self . request . user )
2024-08-03 22:03:27 -04:00
class NoteViewSet ( viewsets . ModelViewSet ) :
queryset = Note . objects . all ( )
serializer_class = NoteSerializer
2024-09-03 10:24:11 -04:00
permission_classes = [ IsOwnerOrSharedWithFullAccess , IsPublicOrOwnerOrSharedWithFullAccess ]
2024-08-03 22:03:27 -04:00
filterset_fields = [ ' is_public ' , ' collection ' ]
# return error message if user is not authenticated on the root endpoint
def list ( self , request , * args , * * kwargs ) :
# Prevent listing all adventures
return Response ( { " detail " : " Listing all notes is not allowed. " } ,
status = status . HTTP_403_FORBIDDEN )
@action ( detail = False , methods = [ ' get ' ] )
def all ( self , request ) :
if not request . user . is_authenticated :
return Response ( { " error " : " User is not authenticated " } , status = 400 )
queryset = Note . objects . filter (
Q ( user_id = request . user . id )
)
serializer = self . get_serializer ( queryset , many = True )
return Response ( serializer . data )
def get_queryset ( self ) :
2024-09-03 10:24:11 -04:00
# if the user is not authenticated return only public transportations for retrieve action
if not self . request . user . is_authenticated :
if self . action == ' retrieve ' :
2024-09-27 22:21:36 -04:00
return Note . objects . filter ( is_public = True ) . distinct ( ) . order_by ( ' -updated_at ' )
2024-09-03 10:24:11 -04:00
return Note . objects . none ( )
2024-08-03 22:03:27 -04:00
2024-09-03 10:24:11 -04:00
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 )
2024-09-27 22:21:36 -04:00
) . distinct ( ) . order_by ( ' -updated_at ' )
2024-09-03 10:24:11 -04:00
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 )
2024-09-27 22:21:36 -04:00
) . distinct ( ) . order_by ( ' -updated_at ' )
2024-09-03 10:24:11 -04:00
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 )
2024-08-03 22:03:27 -04:00
2024-09-03 10:24:11 -04:00
# 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
2024-08-05 18:48:11 -04:00
def perform_create ( self , serializer ) :
2024-09-03 10:24:11 -04:00
# 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
2024-08-05 18:48:11 -04:00
serializer . save ( user_id = self . request . user )
class ChecklistViewSet ( viewsets . ModelViewSet ) :
queryset = Checklist . objects . all ( )
serializer_class = ChecklistSerializer
2024-09-03 10:24:11 -04:00
permission_classes = [ IsOwnerOrSharedWithFullAccess , IsPublicOrOwnerOrSharedWithFullAccess ]
2024-08-05 18:48:11 -04:00
filterset_fields = [ ' is_public ' , ' collection ' ]
# return error message if user is not authenticated on the root endpoint
def list ( self , request , * args , * * kwargs ) :
# Prevent listing all adventures
return Response ( { " detail " : " Listing all checklists is not allowed. " } ,
status = status . HTTP_403_FORBIDDEN )
@action ( detail = False , methods = [ ' get ' ] )
def all ( self , request ) :
if not request . user . is_authenticated :
return Response ( { " error " : " User is not authenticated " } , status = 400 )
queryset = Checklist . objects . filter (
Q ( user_id = request . user . id )
)
serializer = self . get_serializer ( queryset , many = True )
return Response ( serializer . data )
def get_queryset ( self ) :
2024-09-03 10:24:11 -04:00
# if the user is not authenticated return only public transportations for retrieve action
if not self . request . user . is_authenticated :
if self . action == ' retrieve ' :
2024-09-27 22:21:36 -04:00
return Checklist . objects . filter ( is_public = True ) . distinct ( ) . order_by ( ' -updated_at ' )
2024-09-03 10:24:11 -04:00
return Checklist . objects . none ( )
2024-08-05 18:48:11 -04:00
2024-09-03 10:24:11 -04:00
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 )
2024-09-27 22:21:36 -04:00
) . distinct ( ) . order_by ( ' -updated_at ' )
2024-09-03 10:24:11 -04:00
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 )
2024-09-27 22:21:36 -04:00
) . distinct ( ) . order_by ( ' -updated_at ' )
2024-09-03 10:24:11 -04:00
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 )
2024-08-05 18:48:11 -04:00
2024-09-03 10:24:11 -04:00
# 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
2024-08-16 20:31:39 -04:00
def perform_create ( self , serializer ) :
2024-09-03 10:24:11 -04:00
# 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
2024-08-16 20:31:39 -04:00
serializer . save ( user_id = self . request . user )
class AdventureImageViewSet ( viewsets . ModelViewSet ) :
serializer_class = AdventureImageSerializer
2024-08-17 13:30:00 -04:00
permission_classes = [ IsAuthenticated ]
2024-08-17 13:59:49 -04:00
def dispatch ( self , request , * args , * * kwargs ) :
print ( f " Method: { request . method } " )
return super ( ) . dispatch ( request , * args , * * kwargs )
@action ( detail = True , methods = [ ' post ' ] )
def image_delete ( self , request , * args , * * kwargs ) :
return self . destroy ( request , * args , * * kwargs )
2024-08-16 20:31:39 -04:00
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 :
2024-09-09 14:29:50 -04:00
# 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 )
2024-08-16 20:31:39 -04:00
return super ( ) . create ( request , * args , * * kwargs )
def update ( 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 :
return Response ( { " error " : " User does not own this adventure " } , status = status . HTTP_403_FORBIDDEN )
return super ( ) . update ( request , * args , * * kwargs )
2024-08-17 13:59:49 -04:00
def perform_destroy ( self , instance ) :
print ( " perform_destroy " )
return super ( ) . perform_destroy ( instance )
def destroy ( self , request , * args , * * kwargs ) :
print ( " destroy " )
if not request . user . is_authenticated :
return Response ( { " error " : " User is not authenticated " } , status = status . HTTP_401_UNAUTHORIZED )
2024-08-16 20:31:39 -04:00
2024-08-17 13:59:49 -04:00
instance = self . get_object ( )
adventure = instance . adventure
if adventure . user_id != request . user :
return Response ( { " error " : " User does not own this adventure " } , status = status . HTTP_403_FORBIDDEN )
2024-08-16 20:31:39 -04:00
2024-08-17 13:59:49 -04:00
return super ( ) . destroy ( request , * args , * * kwargs )
2024-08-16 20:31:39 -04:00
def partial_update ( self , request , * args , * * kwargs ) :
if not request . user . is_authenticated :
return Response ( { " error " : " User is not authenticated " } , status = status . HTTP_401_UNAUTHORIZED )
instance = self . get_object ( )
adventure = instance . adventure
if adventure . user_id != request . user :
return Response ( { " error " : " User does not own this adventure " } , status = status . HTTP_403_FORBIDDEN )
return super ( ) . partial_update ( request , * args , * * kwargs )
@action ( detail = False , methods = [ ' GET ' ] , url_path = ' (?P<adventure_id>[0-9a-f-]+) ' )
def adventure_images ( self , request , adventure_id = None , * args , * * kwargs ) :
if not request . user . is_authenticated :
return Response ( { " error " : " User is not authenticated " } , status = status . HTTP_401_UNAUTHORIZED )
try :
adventure_uuid = uuid . UUID ( adventure_id )
except ValueError :
return Response ( { " error " : " Invalid adventure ID " } , status = status . HTTP_400_BAD_REQUEST )
queryset = AdventureImage . objects . filter (
Q ( adventure__id = adventure_uuid ) & Q ( user_id = request . user )
)
serializer = self . get_serializer ( queryset , many = True , context = { ' request ' : request } )
return Response ( serializer . data )
def get_queryset ( self ) :
return AdventureImage . objects . filter ( user_id = self . request . user )
2024-08-03 22:03:27 -04:00
def perform_create ( self , serializer ) :
2024-10-21 15:28:45 -04:00
serializer . save ( user_id = self . request . user )
2024-10-30 15:11:00 -04:00
class ReverseGeocodeViewSet ( viewsets . ViewSet ) :
permission_classes = [ IsAuthenticated ]
def extractIsoCode ( self , data ) :
"""
Extract the ISO code from the response data .
Returns a dictionary containing the region name , country name , and ISO code if found .
"""
iso_code = None
2024-10-31 23:47:02 -04:00
town = None
city = None
county = None
display_name = None
country_code = None
2024-10-30 15:11:00 -04:00
if ' address ' in data . keys ( ) :
keys = data [ ' address ' ] . keys ( )
for key in keys :
if key . find ( " ISO " ) != - 1 :
iso_code = data [ ' address ' ] [ key ]
2024-10-31 23:47:02 -04:00
if ' town ' in keys :
town = data [ ' address ' ] [ ' town ' ]
if ' county ' in keys :
county = data [ ' address ' ] [ ' county ' ]
if ' city ' in keys :
city = data [ ' address ' ] [ ' city ' ]
2024-11-01 20:08:23 -04:00
if not iso_code :
return { " error " : " No region found " }
2024-10-30 15:11:00 -04:00
region = Region . objects . filter ( id = iso_code ) . first ( )
visited_region = VisitedRegion . objects . filter ( region = region ) . first ( )
is_visited = False
2024-11-01 20:08:23 -04:00
print ( iso_code )
2024-10-31 23:47:02 -04:00
country_code = iso_code [ : 2 ]
if city :
display_name = f " { city } , { region . name } , { country_code } "
elif town and region . name :
display_name = f " { town } , { region . name } , { country_code } "
elif county and region . name :
display_name = f " { county } , { region . name } , { country_code } "
2024-10-30 15:11:00 -04:00
if visited_region :
is_visited = True
if region :
2024-10-31 23:47:02 -04:00
return { " id " : iso_code , " region " : region . name , " country " : region . country . name , " is_visited " : is_visited , " display_name " : display_name }
2024-10-30 15:11:00 -04:00
return { " error " : " No region found " }
@action ( detail = False , methods = [ ' get ' ] )
def reverse_geocode ( self , request ) :
lat = request . query_params . get ( ' lat ' , ' ' )
lon = request . query_params . get ( ' lon ' , ' ' )
url = f " https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat= { lat } &lon= { lon } "
headers = { ' User-Agent ' : ' AdventureLog Server ' }
response = requests . get ( url , headers = headers )
try :
data = response . json ( )
except requests . exceptions . JSONDecodeError :
return Response ( { " error " : " Invalid response from geocoding service " } , status = 400 )
return Response ( self . extractIsoCode ( data ) )
2024-11-01 20:08:23 -04:00
@action ( detail = False , methods = [ ' post ' ] )
def mark_visited_region ( self , request ) :
# searches through all of the users adventures, if the serialized data is_visited, is true, runs reverse geocode on the adventures and if a region is found, marks it as visited. Use the extractIsoCode function to get the region
new_region_count = 0
new_regions = { }
adventures = Adventure . objects . filter ( user_id = self . request . user )
serializer = AdventureSerializer ( adventures , many = True )
for adventure , serialized_adventure in zip ( adventures , serializer . data ) :
if serialized_adventure [ ' is_visited ' ] == True :
lat = adventure . latitude
lon = adventure . longitude
url = f " https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat= { lat } &lon= { lon } "
headers = { ' User-Agent ' : ' AdventureLog Server ' }
response = requests . get ( url , headers = headers )
try :
data = response . json ( )
except requests . exceptions . JSONDecodeError :
return Response ( { " error " : " Invalid response from geocoding service " } , status = 400 )
region = self . extractIsoCode ( data )
if ' error ' not in region :
region = Region . objects . filter ( id = region [ ' id ' ] ) . first ( )
visited_region = VisitedRegion . objects . filter ( region = region , user_id = self . request . user ) . first ( )
if not visited_region :
visited_region = VisitedRegion ( region = region , user_id = self . request . user )
visited_region . save ( )
new_region_count + = 1
new_regions [ region . id ] = region . name
2024-11-02 21:18:52 -04:00
return Response ( { " new_regions " : new_region_count , " regions " : new_regions } )