mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-07-23 06:49:37 +02:00
* 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
207 lines
8.1 KiB
Python
207 lines
8.1 KiB
Python
from os import getenv
|
|
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
|
|
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
|
|
from allauth.socialaccount.models import SocialApp
|
|
from adventures.serializers import LocationSerializer, CollectionSerializer
|
|
from adventures.models import Location, Collection
|
|
from allauth.socialaccount.models import SocialAccount
|
|
|
|
User = get_user_model()
|
|
|
|
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
|
|
# 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)
|
|
user.save()
|
|
return Response({"detail": "Email successfully changed."}, status=status.HTTP_200_OK)
|
|
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):
|
|
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)
|
|
# for every user, remove the field has_password
|
|
for user in serializer.data:
|
|
user.pop('has_password', None)
|
|
user.pop('disable_password', None)
|
|
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, 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)
|
|
# for every user, remove the field has_password
|
|
serializer.data.pop('has_password', None)
|
|
|
|
# remove the email address from the response
|
|
user.email = None
|
|
|
|
# Get the users adventures and collections to include in the response
|
|
adventures = Location.objects.filter(user=user, is_public=True)
|
|
collections = Collection.objects.filter(user=user, is_public=True)
|
|
adventure_serializer = LocationSerializer(adventures, many=True)
|
|
collection_serializer = CollectionSerializer(collections, many=True)
|
|
|
|
return Response({
|
|
'user': serializer.data,
|
|
'adventures': adventure_serializer.data,
|
|
'collections': collection_serializer.data
|
|
}, status=status.HTTP_200_OK)
|
|
|
|
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)
|
|
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)
|
|
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':
|
|
new_provider = f'oidc/{provider.provider_id}'
|
|
else:
|
|
new_provider = provider.provider
|
|
providers.append({
|
|
'provider': provider.provider,
|
|
'url': f"{getenv('PUBLIC_URL')}/accounts/{new_provider}/login/",
|
|
'name': provider.name
|
|
})
|
|
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)
|
|
|