mirror of
https://github.com/workhardbekind/workout-challenge.git
synced 2026-07-04 01:13:32 -04:00
118 lines
No EOL
4.3 KiB
Python
118 lines
No EOL
4.3 KiB
Python
from rest_framework import serializers
|
|
from django.conf import settings
|
|
from django.contrib.auth.tokens import default_token_generator
|
|
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
|
|
from django.utils.encoding import force_bytes
|
|
from django.template.loader import render_to_string
|
|
|
|
from .models import CustomUser
|
|
from .emails.multipurpose import send_email
|
|
|
|
|
|
class CustomUserSerializer(serializers.ModelSerializer):
|
|
my = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = CustomUser
|
|
fields = ['id', 'my', 'email', 'first_name', 'last_name', 'gender', 'username', 'password', 'is_verified', 'email_mid_week', 'strava_athlete_id', 'strava_allow_follow', 'strava_last_synced_at', 'my_competitions', 'my_teams', 'goal_active_days', 'goal_workout_minutes', 'goal_distance', 'scaling_kcal', 'scaling_distance']
|
|
read_only_fields = ['is_verified', 'strava_athlete_id', 'strava_last_synced_at']
|
|
extra_kwargs = {
|
|
'password': {'write_only': True},
|
|
}
|
|
|
|
def get_my(self, obj):
|
|
user = self.context['request'].user
|
|
return obj.pk == user.pk
|
|
|
|
def create(self, validated_data):
|
|
user = CustomUser.objects.create_user(
|
|
email=validated_data.get('email'),
|
|
first_name=validated_data.get('first_name'),
|
|
last_name=validated_data.get('last_name', None),
|
|
password=validated_data.get('password'),
|
|
gender=validated_data.get('gender', None),
|
|
)
|
|
return user
|
|
|
|
def to_representation(self, instance):
|
|
rep = super().to_representation(instance)
|
|
user = self.context['request'].user
|
|
|
|
# Omit 'secret' fields of other users that this user is not allowed to see
|
|
if instance.pk != user.pk:
|
|
rep.pop('email', None)
|
|
rep.pop('first_name', None)
|
|
rep.pop('last_name', None)
|
|
rep.pop('gender', None)
|
|
rep.pop('password', None)
|
|
rep.pop('strava_last_synced_at', None)
|
|
|
|
if not rep['strava_allow_follow']:
|
|
rep.pop('strava_athlete_id', None)
|
|
|
|
return rep
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
|
|
# If instance exists, it's an update (PUT/PATCH), make fields optional
|
|
if self.instance:
|
|
self.fields['email'].required = False
|
|
self.fields['password'].required = False
|
|
self.fields['first_name'].required = False
|
|
self.fields['last_name'].required = False
|
|
|
|
|
|
class PasswordResetSerializer(serializers.Serializer):
|
|
email = serializers.EmailField()
|
|
|
|
def validate_email(self, value):
|
|
if not CustomUser.objects.filter(email=value).exists():
|
|
# To avoid leaking info
|
|
return value
|
|
return value
|
|
|
|
def save(self, request):
|
|
email = self.validated_data['email']
|
|
users = CustomUser.objects.filter(email=email)
|
|
for user in users:
|
|
uid = urlsafe_base64_encode(force_bytes(user.pk))
|
|
token = default_token_generator.make_token(user)
|
|
reset_url = f"{settings.MAIN_HOST}/password/reset/{uid}/{token}/"
|
|
|
|
email_subject = "Workout Challenge - Reset Your Password"
|
|
email_body = render_to_string(
|
|
"email_password_reset.html",
|
|
{
|
|
'first_name': user.first_name,
|
|
'MAIN_HOST': settings.MAIN_HOST,
|
|
'RESET_URL': reset_url,
|
|
'EMAIL_REPLY_TO': settings.EMAIL_REPLY_TO,
|
|
}
|
|
)
|
|
|
|
send_email(subject=email_subject, body=email_body, to_email=user.email)
|
|
|
|
|
|
|
|
class PasswordResetConfirmSerializer(serializers.Serializer):
|
|
uid = serializers.CharField()
|
|
token = serializers.CharField()
|
|
new_password = serializers.CharField(write_only=True)
|
|
|
|
def validate(self, attrs):
|
|
try:
|
|
uid = urlsafe_base64_decode(attrs['uid']).decode()
|
|
self.user = CustomUser.objects.get(pk=uid)
|
|
except (CustomUser.DoesNotExist, ValueError):
|
|
raise serializers.ValidationError("Invalid user.")
|
|
|
|
if not default_token_generator.check_token(self.user, attrs['token']):
|
|
raise serializers.ValidationError("Invalid or expired token.")
|
|
|
|
return attrs
|
|
|
|
def save(self):
|
|
self.user.set_password(self.validated_data['new_password'])
|
|
self.user.save() |