added endpoints for user profile

This commit is contained in:
afanasyev.aa 2025-07-15 00:58:31 +09:00
parent dd99c395a0
commit 6f4282d96e
4 changed files with 138 additions and 5 deletions

View file

@ -1,6 +1,10 @@
from rest_framework import serializers
from .models import Prediction, SavedPoint, SavedRateProfile, PreditctionTemplate
from datetime import datetime
from django.contrib.auth.password_validation import validate_password
from django.core.validators import validate_email
from django.core.exceptions import ValidationError as DjangoValidationError
from django.contrib.auth import get_user_model
from .validators import (
validate_custom_curve, rate_clip,
_rfc3339_to_timestamp, base64_to_curve
@ -11,6 +15,7 @@ class PredictionSerializer(serializers.ModelSerializer):
model = Prediction
fields = ['id', 'created_at', 'updated_at', 'result']
User = get_user_model()
PROFILE_STANDARD = "standard_profile"
PROFILE_FLOAT = "float_profile"
@ -151,3 +156,30 @@ class PreditctionTemplateSerializer(serializers.ModelSerializer):
model = PreditctionTemplate
fields = ['id', 'name', 'template_data', 'is_default']
read_only_fields = ['id']
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['username', 'email', 'first_name', 'last_name']
extra_kwargs = {
'username': {'read_only': True}
}
def validate_email(self, value):
try:
validate_email(value)
except DjangoValidationError:
raise serializers.ValidationError("Invalid email format")
return value
class ChangePasswordSerializer(serializers.Serializer):
old_password = serializers.CharField(required=True)
new_password = serializers.CharField(required=True)
def validate_new_password(self, value):
validate_password(value)
return value
class DeleteAccountSerializer(serializers.Serializer):
password = serializers.CharField(required=True)

View file

@ -10,7 +10,12 @@ from .views import (
login_view,
logout_view,
SessionView,
WhoAmIView
WhoAmIView,
UserProfileView,
ChangePasswordView,
TokenManagementView,
DeleteUserDataView,
DeleteAccountView
)
@ -32,7 +37,12 @@ urlpatterns = [
path('csrf/', get_csrf, name='api-csrf'),
path('login/', login_view, name='api-login'),
path('logout/', logout_view, name='api-logout'),
path('session/', SessionView.as_view(), name='api-session'), # new
path('whoami/', WhoAmIView.as_view(), name='api-whoami'), # new
path('session/', SessionView.as_view(), name='api-session'),
path('whoami/', WhoAmIView.as_view(), name='api-whoami'),
path("profile/", UserProfileView.as_view(), name='api-profile'),
path("profile/change-password/", ChangePasswordView.as_view(), name='api-change-password'),
path("profile/token/", TokenManagementView.as_view(), name='api-token'),
path("profile/delete-data/", DeleteUserDataView.as_view(), name='api-delete-data'),
path("profile/delete-account/", DeleteAccountView.as_view(), name='api-delete-account'),
]
urlpatterns += router.urls

View file

@ -9,6 +9,7 @@ from rest_framework.exceptions import APIException
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication
from rest_framework.decorators import api_view, permission_classes, authentication_classes, action
from rest_framework.authtoken.models import Token
from django.utils import timezone
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
@ -18,7 +19,7 @@ from django.middleware.csrf import get_token
from django.core.exceptions import ValidationError
from django.utils.dateparse import parse_datetime
from .models import Prediction, User, Satellite, SavedPoint, SavedRateProfile, PreditctionTemplate, TelemetryPacket
from .serializers import PredictionSerializer, TelemetryPacketSerializer, PredictionRequestSerializer, PredictionListSerializer, PredictionDetailSerializer, SavedPointSerializer, SavedRateProfileSerializer, PreditctionTemplateSerializer
from .serializers import PredictionSerializer, TelemetryPacketSerializer, PredictionRequestSerializer, PredictionListSerializer, PredictionDetailSerializer, SavedPointSerializer, SavedRateProfileSerializer, PreditctionTemplateSerializer, UserSerializer, ChangePasswordSerializer, DeleteAccountSerializer
from .services.tawhiri import TawhiriClient
from drf_spectacular.utils import extend_schema
from .permissions import ReadOnlyOrAuthenticated, IsOwner
@ -248,6 +249,96 @@ class PreditctionTemplateViewset(ModelViewSet):
def perform_create(self, serializer):
serializer.save(user=self.request.user)
class UserProfileView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
serializer = UserSerializer(request.user)
return Response(serializer.data)
def patch(self, request):
user = request.user
serializer = UserSerializer(user, data=request.data, partial=True)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializer.save()
return Response(serializer.data)
class ChangePasswordView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
user = request.user
serializer = ChangePasswordSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
if not user.check_password(serializer.validated_data['old_password']):
return Response({'detail': 'Old password is incorrect'},
status=status.HTTP_400_BAD_REQUEST)
user.set_password(serializer.validated_data['new_password'])
user.save()
return Response({'detail': 'Password changed successfully'})
class DeleteAccountView(APIView):
permission_classes = [IsAuthenticated]
def delete(self, request):
user = request.user
serializer = DeleteAccountSerializer(data=request.data)
if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
if not user.check_password(serializer.validated_data['password']):
return Response({'detail': 'Incorrect password'},
status=status.HTTP_400_BAD_REQUEST)
Prediction.objects.filter(user=user).delete()
SavedPoint.objects.filter(user=user).delete()
PreditctionTemplate.objects.filter(user=user).delete()
user.delete()
return Response({'detail': 'Account deleted successfully'})
class DeleteUserDataView(APIView):
permission_classes = [IsAuthenticated]
def delete(self, request):
user = request.user
Prediction.objects.filter(user=user).delete()
SavedPoint.objects.filter(user=user).delete()
PreditctionTemplate.objects.filter(user=user).delete()
return Response({'detail': 'All user data deleted successfully'})
class TokenManagementView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
token, created = Token.objects.get_or_create(user=request.user)
return Response({"token": token.key})
def post(self, request):
Token.objects.filter(user=request.user).delete()
token = Token.objects.create(user=request.user)
return Response({"token": token.key})
# class PredictionCreateView(APIView):
# permission_classes = [IsAuthenticated]

View file

@ -57,7 +57,7 @@ INSTALLED_APPS = [
'drf_spectacular',
'corsheaders',
'api.apps.ApiConfig',
'channels',
]
MIDDLEWARE = [