2025-01-06 14:25:57 -05:00
from os import getenv
2024-07-08 11:44:39 -04:00
from rest_framework . views import APIView
from rest_framework . response import Response
from rest_framework import status
from rest_framework . permissions import IsAuthenticated
from . serializers import ChangeEmailSerializer
from drf_yasg . utils import swagger_auto_schema
from drf_yasg import openapi
2024-08-16 12:21:43 -04:00
from django . conf import settings
2024-09-06 23:19:44 -04:00
from django . shortcuts import get_object_or_404
from django . contrib . auth import get_user_model
from . serializers import CustomUserDetailsSerializer as PublicUserSerializer
2025-01-06 14:25:57 -05:00
from allauth . socialaccount . models import SocialApp
Rename Adventures to Locations (#696)
* Refactor user_id to user in adventures and related models, views, and components
- Updated all instances of user_id to user in the adventures app, including models, serializers, views, and frontend components.
- Adjusted queries and filters to reflect the new user field naming convention.
- Ensured consistency across the codebase for user identification in adventures, collections, notes, and transportation entities.
- Modified frontend components to align with the updated data structure, ensuring proper access control and rendering based on user ownership.
* Refactor adventure-related views and components to use "Location" terminology
- Updated GlobalSearchView to replace AdventureSerializer with LocationSerializer.
- Modified IcsCalendarGeneratorViewSet to use LocationSerializer instead of AdventureSerializer.
- Created new LocationImageViewSet for managing location images, including primary image toggling and image deletion.
- Introduced LocationViewSet for managing locations with enhanced filtering, sorting, and sharing capabilities.
- Updated ReverseGeocodeViewSet to utilize LocationSerializer.
- Added ActivityTypesView to retrieve distinct activity types from locations.
- Refactored user views to replace AdventureSerializer with LocationSerializer.
- Updated frontend components to reflect changes from "adventure" to "location", including AdventureCard, AdventureLink, AdventureModal, and others.
- Adjusted API endpoints in frontend routes to align with new location-based structure.
- Ensured all references to adventures are replaced with locations across the codebase.
* refactor: rename adventures to locations across the application
- Updated localization files to replace adventure-related terms with location-related terms.
- Refactored TypeScript types and variables from Adventure to Location in various routes and components.
- Adjusted UI elements and labels to reflect the change from adventures to locations.
- Ensured all references to adventures in the codebase are consistent with the new location terminology.
* Refactor code structure for improved readability and maintainability
* feat: Implement location details page with server-side loading and deletion functionality
- Added +page.server.ts to handle server-side loading of additional location info.
- Created +page.svelte for displaying location details, including images, visits, and maps.
- Integrated GPX file handling and rendering on the map.
- Updated map route to link to locations instead of adventures.
- Refactored profile and search routes to use LocationCard instead of AdventureCard.
* docs: Update terminology from "Adventure" to "Location" and enhance project overview
* docs: Clarify collection examples in usage documentation
* feat: Enable credentials for GPX file fetch and add CORS_ALLOW_CREDENTIALS setting
* Refactor adventure references to locations across the backend and frontend
- Updated CategoryViewSet to reflect location context instead of adventures.
- Modified ChecklistViewSet to include locations in retrieval logic.
- Changed GlobalSearchView to search for locations instead of adventures.
- Adjusted IcsCalendarGeneratorViewSet to handle locations instead of adventures.
- Refactored LocationImageViewSet to remove unused import.
- Updated LocationViewSet to clarify public access for locations.
- Changed LodgingViewSet to reference locations instead of adventures.
- Modified NoteViewSet to prevent listing all locations.
- Updated RecommendationsViewSet to handle locations in parsing and response.
- Adjusted ReverseGeocodeViewSet to search through user locations.
- Updated StatsViewSet to count locations instead of adventures.
- Changed TagsView to reflect activity types for locations.
- Updated TransportationViewSet to reference locations instead of adventures.
- Added new translations for search results related to locations in multiple languages.
- Updated dashboard and profile pages to reflect location counts instead of adventure counts.
- Adjusted search routes to handle locations instead of adventures.
* Update banner image
* style: Update stats component background and border for improved visibility
* refactor: Rename AdventureCard and AdventureModal to LocationCard and LocationModal for consistency
2025-06-25 11:49:34 -04:00
from adventures . serializers import LocationSerializer , CollectionSerializer
from adventures . models import Location , Collection
2025-03-16 21:49:00 -04:00
from allauth . socialaccount . models import SocialAccount
2024-09-06 23:19:44 -04:00
User = get_user_model ( )
2024-07-08 11:44:39 -04:00
class ChangeEmailView ( APIView ) :
permission_classes = [ IsAuthenticated ]
@swagger_auto_schema (
request_body = ChangeEmailSerializer ,
responses = {
200 : openapi . Response ( ' Email successfully changed ' ) ,
400 : ' Bad Request '
} ,
operation_description = " Change the email address for the authenticated user. "
)
def post ( self , request ) :
serializer = ChangeEmailSerializer ( data = request . data , context = { ' request ' : request } )
if serializer . is_valid ( ) :
user = request . user
new_email = serializer . validated_data [ ' new_email ' ]
user . email = new_email
2024-08-16 11:47:53 -04:00
# remove all other email addresses for the user
user . emailaddress_set . exclude ( email = new_email ) . delete ( )
user . emailaddress_set . create ( email = new_email , primary = True , verified = False )
2024-07-08 11:44:39 -04:00
user . save ( )
return Response ( { " detail " : " Email successfully changed. " } , status = status . HTTP_200_OK )
2024-08-16 12:21:43 -04:00
return Response ( serializer . errors , status = status . HTTP_400_BAD_REQUEST )
class IsRegistrationDisabled ( APIView ) :
@swagger_auto_schema (
responses = {
200 : openapi . Response ( ' Registration is disabled ' ) ,
400 : ' Bad Request '
} ,
operation_description = " Check if registration is disabled. "
)
def get ( self , request ) :
2024-08-24 23:20:50 -04:00
return Response ( { " is_disabled " : settings . DISABLE_REGISTRATION , " message " : settings . DISABLE_REGISTRATION_MESSAGE } , status = status . HTTP_200_OK )
2024-09-06 23:19:44 -04:00
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 )
2024-09-10 09:59:59 -04:00
# remove the email addresses from the response
for user in users :
user . email = None
2024-09-06 23:19:44 -04:00
serializer = PublicUserSerializer ( users , many = True )
2025-02-15 19:44:11 -05:00
# for every user, remove the field has_password
for user in serializer . data :
user . pop ( ' has_password ' , None )
2025-03-17 14:38:10 -04:00
user . pop ( ' disable_password ' , None )
2024-09-06 23:19:44 -04:00
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. "
)
2025-01-29 22:50:53 -05:00
def get ( self , request , username ) :
if request . user . username == username :
user = get_object_or_404 ( User , username = username )
else :
user = get_object_or_404 ( User , username = username , public_profile = True )
serializer = PublicUserSerializer ( user )
2025-02-15 19:44:11 -05:00
# for every user, remove the field has_password
serializer . data . pop ( ' has_password ' , None )
2025-01-29 22:50:53 -05:00
2024-09-10 09:59:59 -04:00
# remove the email address from the response
user . email = None
2025-01-29 22:50:53 -05:00
# Get the users adventures and collections to include in the response
Rename Adventures to Locations (#696)
* Refactor user_id to user in adventures and related models, views, and components
- Updated all instances of user_id to user in the adventures app, including models, serializers, views, and frontend components.
- Adjusted queries and filters to reflect the new user field naming convention.
- Ensured consistency across the codebase for user identification in adventures, collections, notes, and transportation entities.
- Modified frontend components to align with the updated data structure, ensuring proper access control and rendering based on user ownership.
* Refactor adventure-related views and components to use "Location" terminology
- Updated GlobalSearchView to replace AdventureSerializer with LocationSerializer.
- Modified IcsCalendarGeneratorViewSet to use LocationSerializer instead of AdventureSerializer.
- Created new LocationImageViewSet for managing location images, including primary image toggling and image deletion.
- Introduced LocationViewSet for managing locations with enhanced filtering, sorting, and sharing capabilities.
- Updated ReverseGeocodeViewSet to utilize LocationSerializer.
- Added ActivityTypesView to retrieve distinct activity types from locations.
- Refactored user views to replace AdventureSerializer with LocationSerializer.
- Updated frontend components to reflect changes from "adventure" to "location", including AdventureCard, AdventureLink, AdventureModal, and others.
- Adjusted API endpoints in frontend routes to align with new location-based structure.
- Ensured all references to adventures are replaced with locations across the codebase.
* refactor: rename adventures to locations across the application
- Updated localization files to replace adventure-related terms with location-related terms.
- Refactored TypeScript types and variables from Adventure to Location in various routes and components.
- Adjusted UI elements and labels to reflect the change from adventures to locations.
- Ensured all references to adventures in the codebase are consistent with the new location terminology.
* Refactor code structure for improved readability and maintainability
* feat: Implement location details page with server-side loading and deletion functionality
- Added +page.server.ts to handle server-side loading of additional location info.
- Created +page.svelte for displaying location details, including images, visits, and maps.
- Integrated GPX file handling and rendering on the map.
- Updated map route to link to locations instead of adventures.
- Refactored profile and search routes to use LocationCard instead of AdventureCard.
* docs: Update terminology from "Adventure" to "Location" and enhance project overview
* docs: Clarify collection examples in usage documentation
* feat: Enable credentials for GPX file fetch and add CORS_ALLOW_CREDENTIALS setting
* Refactor adventure references to locations across the backend and frontend
- Updated CategoryViewSet to reflect location context instead of adventures.
- Modified ChecklistViewSet to include locations in retrieval logic.
- Changed GlobalSearchView to search for locations instead of adventures.
- Adjusted IcsCalendarGeneratorViewSet to handle locations instead of adventures.
- Refactored LocationImageViewSet to remove unused import.
- Updated LocationViewSet to clarify public access for locations.
- Changed LodgingViewSet to reference locations instead of adventures.
- Modified NoteViewSet to prevent listing all locations.
- Updated RecommendationsViewSet to handle locations in parsing and response.
- Adjusted ReverseGeocodeViewSet to search through user locations.
- Updated StatsViewSet to count locations instead of adventures.
- Changed TagsView to reflect activity types for locations.
- Updated TransportationViewSet to reference locations instead of adventures.
- Added new translations for search results related to locations in multiple languages.
- Updated dashboard and profile pages to reflect location counts instead of adventure counts.
- Adjusted search routes to handle locations instead of adventures.
* Update banner image
* style: Update stats component background and border for improved visibility
* refactor: Rename AdventureCard and AdventureModal to LocationCard and LocationModal for consistency
2025-06-25 11:49:34 -04:00
adventures = Location . objects . filter ( user = user , is_public = True )
collections = Collection . objects . filter ( user = user , is_public = True )
adventure_serializer = LocationSerializer ( adventures , many = True )
2025-01-29 22:50:53 -05:00
collection_serializer = CollectionSerializer ( collections , many = True )
return Response ( {
' user ' : serializer . data ,
' adventures ' : adventure_serializer . data ,
' collections ' : collection_serializer . data
} , status = status . HTTP_200_OK )
2024-11-29 14:41:13 -05:00
class UserMetadataView ( APIView ) :
permission_classes = [ IsAuthenticated ]
@swagger_auto_schema (
responses = {
200 : openapi . Response ( ' User metadata ' ) ,
400 : ' Bad Request '
} ,
operation_description = " Get user metadata. "
)
def get ( self , request ) :
user = request . user
serializer = PublicUserSerializer ( user )
2024-11-30 10:24:27 -05:00
return Response ( serializer . data , status = status . HTTP_200_OK )
class UpdateUserMetadataView ( APIView ) :
"""
Update user metadata using fields from the PublicUserSerializer .
Using patch opposed to put allows for partial updates , covers the case where it checks the username and says it ' s already taken. Duplicate uesrname values should not be included in the request to avoid this.
"""
permission_classes = [ IsAuthenticated ]
@swagger_auto_schema (
request_body = PublicUserSerializer ,
responses = {
200 : openapi . Response ( ' User metadata updated ' ) ,
400 : ' Bad Request '
} ,
operation_description = " Update user metadata. "
)
def patch ( self , request ) :
user = request . user
serializer = PublicUserSerializer ( user , data = request . data , partial = True , context = { ' request ' : request } )
if serializer . is_valid ( ) :
serializer . save ( )
return Response ( serializer . data , status = status . HTTP_200_OK )
2025-01-06 14:25:57 -05:00
return Response ( serializer . errors , status = status . HTTP_400_BAD_REQUEST )
class EnabledSocialProvidersView ( APIView ) :
"""
Get enabled social providers for social authentication . This is used to determine which buttons to show on the frontend . Also returns a URL for each to start the authentication flow .
"""
@swagger_auto_schema (
responses = {
200 : openapi . Response ( ' Enabled social providers ' ) ,
400 : ' Bad Request '
} ,
operation_description = " Get enabled social providers. "
)
def get ( self , request ) :
social_providers = SocialApp . objects . filter ( sites = settings . SITE_ID )
providers = [ ]
for provider in social_providers :
if provider . provider == ' openid_connect ' :
2025-04-11 12:35:05 +02:00
new_provider = f ' oidc/ { provider . provider_id } '
2025-01-06 14:25:57 -05:00
else :
new_provider = provider . provider
providers . append ( {
' provider ' : provider . provider ,
' url ' : f " { getenv ( ' PUBLIC_URL ' ) } /accounts/ { new_provider } /login/ " ,
' name ' : provider . name
} )
2025-03-16 21:49:00 -04:00
return Response ( providers , status = status . HTTP_200_OK )
class DisablePasswordAuthenticationView ( APIView ) :
"""
Disable password authentication for a user . This is used when a user signs up with a social provider .
"""
# Allows the user to set the disable_password field to True if they have a social account linked
permission_classes = [ IsAuthenticated ]
@swagger_auto_schema (
responses = {
200 : openapi . Response ( ' Password authentication disabled ' ) ,
400 : ' Bad Request '
} ,
operation_description = " Disable password authentication. "
)
def post ( self , request ) :
user = request . user
if SocialAccount . objects . filter ( user = user ) . exists ( ) :
user . disable_password = True
user . save ( )
return Response ( { " detail " : " Password authentication disabled. " } , status = status . HTTP_200_OK )
return Response ( { " detail " : " No social account linked. " } , status = status . HTTP_400_BAD_REQUEST )
def delete ( self , request ) :
user = request . user
user . disable_password = False
user . save ( )
return Response ( { " detail " : " Password authentication enabled. " } , status = status . HTTP_200_OK )
2025-04-11 12:35:05 +02:00