mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2026-05-09 07:25:01 -04:00
* Refactor AdventureLog Bot workflow to improve issue validation handling and encapsulate comment and close logic * feat: add API key management to settings page - Implemented API key creation, deletion, and display functionality. - Updated the settings page to fetch and show existing API keys. - Added UI elements for creating new API keys and copying them to clipboard. - Enhanced request handling to ensure proper trailing slashes for API endpoints. * feat: add API Keys documentation and update contributing guidelines * fix: update appVersion to reflect the latest build * fix: update @tailwindcss/typography to version 0.5.19 * fix: update @tailwindcss/typography to version 0.5.19 * chore: update dependencies in pnpm-lock.yaml - dompurify: upgraded from 3.3.1 to 3.3.3 - emoji-picker-element: upgraded from 1.29.0 to 1.29.1 - @sveltejs/adapter-node: updated to use @sveltejs/kit@2.55.0 - @sveltejs/adapter-vercel: updated to use @sveltejs/kit@2.55.0 - @sveltejs/kit: upgraded from 2.53.3 to 2.55.0 - @types/node: upgraded from 22.19.13 to 22.19.15 - autoprefixer: updated postcss version from 8.5.6 to 8.5.8 - baseline-browser-mapping: upgraded from 2.10.0 to 2.10.8 - daisyui: updated postcss version from 8.5.6 to 8.5.8 - prettier-plugin-svelte: upgraded from 3.5.0 to 3.5.1 - svelte-check: updated postcss version from 8.5.6 to 8.5.8 - devalue: upgraded from 5.6.3 to 5.6.4 - electron-to-chromium: upgraded from 1.5.302 to 1.5.313 - caniuse-lite: upgraded from 1.0.30001774 to 1.0.30001780 - mlly: upgraded from 1.8.0 to 1.8.1 - node-releases: upgraded from 2.0.27 to 2.0.36 - tar: upgraded from 7.5.9 to 7.5.11 - tinyexec: upgraded from 1.0.2 to 1.0.4 * fix: update appVersion to include the latest build identifier * fix: enhance authentication fallback for protected media access * feat(auth): add 'mobile-qr' to trailing slash list for URL handling * Translated using Weblate (French) Currently translated at 99.9% (1091 of 1092 strings) Translation: AdventureLog/Web App Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/fr/ * Translated using Weblate (Korean) Currently translated at 100.0% (1092 of 1092 strings) Translation: AdventureLog/Web App Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/ko/ * Translated using Weblate (German) Currently translated at 100.0% (1092 of 1092 strings) Translation: AdventureLog/Web App Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/de/ * Translated using Weblate (Swedish) Currently translated at 100.0% (1092 of 1092 strings) Translation: AdventureLog/Web App Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/sv/ * Added translation using Weblate (Catalan) * Translated using Weblate (Catalan) Currently translated at 1.2% (14 of 1092 strings) Translation: AdventureLog/Web App Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/ca/ * Docs: Reorder immich API permissions to natural order (#1086) * Refactor AdventureLog Bot workflow to improve issue validation handling and encapsulate comment and close logic (#1068) * Reorder immich API permissions to natural order --------- Co-authored-by: Sean Morley <git@seanmorley.com> * Translated using Weblate (Turkish) Currently translated at 100.0% (1093 of 1093 strings) Translation: AdventureLog/Web App Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/tr/ * Translated using Weblate (Swedish) Currently translated at 100.0% (1093 of 1093 strings) Translation: AdventureLog/Web App Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/sv/ * Translated using Weblate (German) Currently translated at 100.0% (1093 of 1093 strings) Translation: AdventureLog/Web App Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/de/ * Add ENABLE_RATE_LIMITS configuration for backend rate limiting * Set tabindex to -1 for dropdown menus to improve accessibility * Refactor settings page: Simplify HTML structure and improve date formatting for API keys * Update DEFAULT_SCHEMA_CLASS to use OpenAPI schema in REST framework settings * fix: update error message for key copying and enhance usage instructions for API key * Implement feature X to enhance user experience and fix bug Y in module Z * feat: add .dockerignore and update Dockerfile for improved build process * fix: add missing svelte-i18n>esbuild override in pnpm-lock and pnpm-workspace files * refactor: update frontend CI workflow for improved quality checks and dependency management * Refactor code structure for improved readability and maintainability * fix: add vite>esbuild override in pnpm-lock and pnpm-workspace files * refactor: enhance accessibility and semantics of button elements across multiple components * feat: update API key deletion confirmation messages in multiple languages and improve server URL configuration * fix: update djangorestframework version constraint and drf-yasg version in requirements * fix: update appVersion to v0.12.0-main-040426 and refactor button elements to improve accessibility in CollectionCard and CollectionItineraryPlanner components * feat: implement developer unlock feature for mobile login in Avatar component --------- Co-authored-by: lesensei <alain-gh@lespeps.eu> Co-authored-by: Hosted Weblate user 141821 <clearstripe@users.noreply.hosted.weblate.org> Co-authored-by: Alex <div@alexe.at> Co-authored-by: AntonPalmqvist <apq@users.noreply.hosted.weblate.org> Co-authored-by: Marc Llopart <marc@medullar.com> Co-authored-by: Stephan Zwicknagl <64196842+stephanzwicknagl@users.noreply.github.com> Co-authored-by: Orhun <orhunavcu@gmail.com> Co-authored-by: bittin1ddc447d824349b2 <bittin@reimu.nl>
153 lines
5.4 KiB
Python
153 lines
5.4 KiB
Python
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
|
||
import os
|
||
|
||
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')
|
||
|
||
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:
|
||
public_url = os.environ.get('PUBLIC_URL', 'http://127.0.0.1:8000').rstrip('/')
|
||
public_url = public_url.replace("'", "") # Sanitize URL
|
||
representation['profile_pic'] = f"{public_url}/media/{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)
|