Files
Pulse-API/solution/pulse/api/users/views.py
T
2024-03-03 18:15:03 +03:00

228 lines
6.8 KiB
Python

from datetime import timedelta
import bcrypt
import jwt
from django.conf import settings
from django.utils import timezone
from rest_framework import status
from rest_framework.exceptions import (
NotAuthenticated,
NotFound,
PermissionDenied,
ValidationError,
)
from rest_framework.generics import ListAPIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from api.users.models import Friendship, Profile
from api.users.permissions import CanAccessProfile
from api.users.serializers import (
FriendshipSerializer,
PasswordChangeSerializer,
ProfileSerializer,
PublicProfileSerializer,
UpdateProfileSerializer,
)
class RegisterUserApiView(APIView):
def post(self, request):
serializer = ProfileSerializer(data=request.data)
if serializer.is_valid():
errors = Profile.check_unique(None, serializer.validated_data)
if errors:
return Response(
{"reason:": str(errors)}, status=status.HTTP_409_CONFLICT
)
password = serializer.validated_data["password"]
password_hash = bcrypt.hashpw(
password.encode("utf-8"), bcrypt.gensalt()
).decode("utf-8")
serializer.validated_data["password"] = password_hash
user = serializer.save()
profile = {
"profile": {
"login": user.login,
"email": user.email,
"countryCode": user.countryCode,
"isPublic": user.isPublic,
}
}
if user.phone is not None:
profile["profile"]["phone"] = user.phone
if user.image is not None:
profile["profile"]["image"] = user.image
return Response(profile, status=status.HTTP_201_CREATED)
raise ValidationError(serializer.errors)
class SigninUserApiView(APIView):
def post(self, request):
login = request.data.get("login")
password = request.data.get("password")
user = Profile.objects.filter(login=login).first()
if user is not None:
if not bcrypt.checkpw(
password.encode("utf-8"), user.password.encode("utf-8")
):
raise NotAuthenticated(
{"error": "Invalid credentials"},
)
else:
raise NotAuthenticated(
{"error": "Invalid credentials"},
)
token = jwt.encode(
{
"id": user.id,
"password": password,
"exp": timezone.now() + timedelta(hours=24),
},
settings.SECRET_KEY,
algorithm="HS256",
)
return Response({"token": token})
class ProfileMeApiView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
user = request.user
profile_data = self._get_profile_data(user)
return Response(profile_data)
def patch(self, request):
user = request.user
serializer = UpdateProfileSerializer(
user, data=request.data, partial=True
)
if serializer.is_valid():
errors = Profile.check_unique(user.id, serializer.validated_data)
if errors:
return Response(
{"reason:": str(errors)}, status=status.HTTP_409_CONFLICT
)
serializer.save()
return Response(serializer.data)
raise ValidationError(serializer.errors)
def _get_profile_data(self, user):
profile = {
"login": user.login,
"email": user.email,
"countryCode": user.countryCode,
"isPublic": user.isPublic,
}
if user.phone is not None:
profile["phone"] = user.phone
if user.image is not None:
profile["image"] = user.image
return profile
class ProfilesApiView(APIView):
permission_classes = [IsAuthenticated, CanAccessProfile]
def get(self, request, login):
try:
profile = Profile.objects.get(login=login)
self.check_object_permissions(request, profile)
serializer = PublicProfileSerializer(profile)
return Response(serializer.data)
except Profile.DoesNotExist:
raise PermissionDenied(
{"detail": "Profile not found."},
) from None
class AddFriendApiView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
try:
login = request.data.get("login")
profile = Profile.objects.get(login=login)
request.user.add_friend(profile)
return Response(
{"status": "ok"},
status=status.HTTP_200_OK,
)
except Profile.DoesNotExist:
raise NotFound(
{"detail": "Profile not found."},
) from None
class RemoveFriendApiView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
try:
login = request.data.get("login")
profile = Profile.objects.get(login=login)
request.user.remove_friend(profile)
return Response(
{"status": "ok"},
status=status.HTTP_200_OK,
)
except Profile.DoesNotExist:
raise NotFound(
{"detail": "Profile not found."},
) from None
class FriendsListApiView(ListAPIView):
permission_classes = [IsAuthenticated]
serializer_class = FriendshipSerializer
def get_queryset(self):
limit = int(self.request.query_params.get("limit", 5))
offset = int(self.request.query_params.get("offset", 0))
return Friendship.objects.filter(from_profile=self.request.user)[
offset : offset + limit
]
class PasswordChangeApiView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
serializer = PasswordChangeSerializer(data=request.data)
if serializer.is_valid():
old_password = serializer.validated_data.get("oldPassword")
new_password = serializer.validated_data.get("newPassword")
if bcrypt.checkpw(
old_password.encode("utf-8"),
request.user.password.encode("utf-8"),
):
password_hash = bcrypt.hashpw(
new_password.encode("utf-8"), bcrypt.gensalt()
).decode("utf-8")
request.user.password = password_hash
request.user.save()
return Response({"status": "ok"}, status=status.HTTP_200_OK)
raise PermissionDenied({"error": "Invalid old password"})
raise ValidationError(serializer.errors)