Files
AdventureLog/backend/server/users/serializers.py
Sean Morley 59a103ea8c Cloud (#1170)
* Add new default light and dark themes to match AdventureLog styles

* Allow different theme for site and maps
Fixes #1130

* Update settings page to use translation keys for currency and map style descriptions

* Add global flag to CollectionItineraryItemSerializer and implement map view persistence in frontend

* Update appVersion to v0.12.0-main-052126

* Enhance permissions for shared collections and restrict publicity changes to owners only

* Update appVersion to v0.12.1-beta-052126

* Add new localization strings and descriptions for various languages

- Updated Spanish (es.json) with new map style and preferred currency descriptions.
- Enhanced French (fr.json) with additional details for Strava activities and currency descriptions.
- Added new strings in Hungarian (hu.json) for map style and preferred currency.
- Included additional details in Italian (it.json) for Strava activities and currency descriptions.
- Updated Japanese (ja.json) with new strings for map style and preferred currency.
- Enhanced Korean (ko.json) with additional details for Strava activities and currency descriptions.
- Added new strings in Dutch (nl.json) for map style and preferred currency.
- Updated Norwegian (no.json) with new strings for map style and preferred currency.
- Enhanced Polish (pl.json) with additional details for Strava activities and currency descriptions.
- Updated Brazilian Portuguese (pt-br.json) with new map style and preferred currency descriptions.
- Added new strings in Romanian (ro.json) for additional details and currency descriptions.
- Enhanced Russian (ru.json) with new strings for map style and preferred currency.
- Updated Slovak (sk.json) with additional details for map style and preferred currency.
- Enhanced Swedish (sv.json) with new strings for map style and preferred currency.
- Added new strings in Turkish (tr.json) for map style and preferred currency.
- Updated Ukrainian (uk.json) with new strings for map style and preferred currency.
- Enhanced Chinese (zh.json) with additional details for map style and preferred currency.

* feat: Implement cloud billing system with subscription management

- Added billing app with models, serializers, views, and admin configuration for Subscription.
- Integrated Stripe for payment processing and subscription management.
- Created middleware for cloud access control based on user subscriptions.
- Developed frontend components for subscription status and billing management.
- Updated settings to include cloud mode and Stripe configuration.
- Added routes for billing and subscription management in the API.
- Implemented user subscription creation and management on user registration and checkout.

* feat: Implement media storage limit and usage tracking

- Added media storage limit configuration in settings.
- Introduced utility functions for managing media storage limits and usage.
- Updated models to delete media files using storage backend.
- Enhanced serializers to build media URLs dynamically.
- Implemented media usage tracking in user views and added endpoint for fetching media usage.
- Updated frontend to display media storage usage and limits.
- Added translations for media storage related strings in multiple languages.

* feat: Implement conditional throttling for various external services and update settings for rate limits
2026-05-30 11:02:44 -04:00

153 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from rest_framework import serializers
from django.contrib.auth import get_user_model
from adventures.models import Collection
User = get_user_model()
from django.contrib.auth import get_user_model
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
class ChangeEmailSerializer(serializers.Serializer):
new_email = serializers.EmailField(required=True)
def validate_new_email(self, value):
user = self.context['request'].user
if User.objects.filter(email=value).exclude(pk=user.pk).exists():
raise serializers.ValidationError("This email is already in use.")
return value
from django.conf import settings
from django.contrib.auth import get_user_model
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
UserModel = get_user_model()
# from dj_rest_auth.serializers import UserDetailsSerializer
from .models import CustomUser
from rest_framework import serializers
from django.conf import settings
from main.utils import build_media_url
class UserDetailsSerializer(serializers.ModelSerializer):
"""
User model without exposing the password.
"""
@staticmethod
def validate_username(username):
if 'allauth.account' not in settings.INSTALLED_APPS:
return username
from allauth.account.adapter import get_adapter
username = get_adapter().clean_username(username.lower()) # Convert username to lowercase
return username
class Meta:
model = CustomUser
extra_fields = ['profile_pic', 'uuid', 'public_profile']
if hasattr(UserModel, 'USERNAME_FIELD'):
extra_fields.append(UserModel.USERNAME_FIELD)
if hasattr(UserModel, 'EMAIL_FIELD'):
extra_fields.append(UserModel.EMAIL_FIELD)
if hasattr(UserModel, 'first_name'):
extra_fields.append('first_name')
if hasattr(UserModel, 'last_name'):
extra_fields.append('last_name')
if hasattr(UserModel, 'date_joined'):
extra_fields.append('date_joined')
if hasattr(UserModel, 'is_staff'):
extra_fields.append('is_staff')
if hasattr(UserModel, 'disable_password'):
extra_fields.append('disable_password')
if hasattr(UserModel, 'measurement_system'):
extra_fields.append('measurement_system')
if hasattr(UserModel, 'default_currency'):
extra_fields.append('default_currency')
if hasattr(UserModel, 'map_style'):
extra_fields.append('map_style')
fields = ['pk', *extra_fields]
read_only_fields = ('email', 'date_joined', 'is_staff', 'is_superuser', 'is_active', 'pk', 'disable_password')
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):
"""
Custom serializer to add additional fields and logic for the user details.
"""
has_password = serializers.SerializerMethodField()
class Meta(UserDetailsSerializer.Meta):
model = CustomUser
fields = UserDetailsSerializer.Meta.fields + ['has_password', 'disable_password']
read_only_fields = UserDetailsSerializer.Meta.read_only_fields + ('uuid', 'has_password', 'disable_password')
@staticmethod
def get_has_password(instance):
"""
Computes whether the user has a usable password set.
"""
return instance.has_usable_password()
def to_representation(self, instance):
"""
Customizes the serialized output to modify `profile_pic` URL and add computed fields.
"""
representation = super().to_representation(instance)
# Construct profile picture URL if it exists
if instance.profile_pic:
representation['profile_pic'] = build_media_url(instance.profile_pic.name)
# Remove `pk` field from the response
representation.pop('pk', None)
# Remove the email field
representation.pop('email', None)
return representation
from .models import APIKey
class APIKeySerializer(serializers.ModelSerializer):
"""
Read serializer for APIKey never exposes the key_hash or the raw token.
The raw token is injected by the view only at creation time via an extra
``key`` field that is *not* part of the model serializer.
"""
class Meta:
model = APIKey
fields = ['id', 'name', 'key_prefix', 'created_at', 'last_used_at']
read_only_fields = ['id', 'key_prefix', 'created_at', 'last_used_at']
class APIKeyCreateSerializer(serializers.Serializer):
"""Write serializer only accepts a ``name`` for the new key."""
name = serializers.CharField(max_length=100, required=True)