Added profiles page and friends system
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import bcrypt
|
||||
import jwt
|
||||
from django.conf import settings
|
||||
from rest_framework.authentication import (
|
||||
@@ -30,6 +31,13 @@ class JWTAuthentication(BaseAuthentication):
|
||||
)
|
||||
|
||||
user = Profile.objects.get(id=payload["id"])
|
||||
|
||||
if not bcrypt.checkpw(
|
||||
payload["password"].encode("utf-8"),
|
||||
user.password.encode("utf-8"),
|
||||
):
|
||||
error = "Token has expired"
|
||||
raise AuthenticationFailed(error)
|
||||
except Profile.DoesNotExist:
|
||||
error = "Invalid token"
|
||||
raise AuthenticationFailed(error) from None
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Generated by Django 4.2.10 on 2024-03-02 10:14
|
||||
# Generated by Django 4.2.10 on 2024-03-03 06:12
|
||||
|
||||
import api.users.validators
|
||||
import django.core.validators
|
||||
@@ -24,6 +24,7 @@ class Migration(migrations.Migration):
|
||||
('isPublic', models.BooleanField()),
|
||||
('phone', models.CharField(blank=True, max_length=20, null=True, validators=[django.core.validators.MaxLengthValidator(20), django.core.validators.RegexValidator('\\+[\\d]+')])),
|
||||
('image', models.URLField(blank=True, null=True)),
|
||||
('friends', models.ManyToManyField(blank=True, to='users.profile')),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
||||
@@ -32,6 +32,7 @@ class Profile(models.Model):
|
||||
null=True,
|
||||
)
|
||||
image = models.URLField(max_length=200, blank=True, null=True)
|
||||
friends = models.ManyToManyField("self", blank=True, symmetrical=False)
|
||||
|
||||
def __str__(self):
|
||||
return self.login
|
||||
@@ -39,6 +40,16 @@ class Profile(models.Model):
|
||||
def is_authenticated(self):
|
||||
return True
|
||||
|
||||
def add_friend(self, user):
|
||||
if self != user:
|
||||
self.friends.add(user)
|
||||
|
||||
def remove_friend(self, user):
|
||||
self.friends.remove(user)
|
||||
|
||||
def check_for_friendship(self, user):
|
||||
return self.friends.filter(pk=user.pk).exists()
|
||||
|
||||
@classmethod
|
||||
def check_unique(cls, user_id, validated_data):
|
||||
errors = {}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
from rest_framework.permissions import BasePermission
|
||||
|
||||
|
||||
class CanAccessProfile(BasePermission):
|
||||
def has_object_permission(self, request, view, obj):
|
||||
if (
|
||||
obj.isPublic
|
||||
or obj.check_for_friendship(request.user)
|
||||
or obj == request.user
|
||||
):
|
||||
return True
|
||||
|
||||
return False
|
||||
@@ -28,3 +28,24 @@ class UpdateProfileSerializer(serializers.ModelSerializer):
|
||||
"phone",
|
||||
"image",
|
||||
]
|
||||
|
||||
|
||||
class PublicProfileSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Profile
|
||||
fields = [
|
||||
"login",
|
||||
"email",
|
||||
"countryCode",
|
||||
"isPublic",
|
||||
"phone",
|
||||
"image",
|
||||
]
|
||||
|
||||
def to_representation(self, instance):
|
||||
data = super().to_representation(instance)
|
||||
if data["image"] is None:
|
||||
del data["image"]
|
||||
if data["phone"] is None:
|
||||
del data["phone"]
|
||||
return data
|
||||
|
||||
@@ -16,5 +16,21 @@ urlpatterns = [
|
||||
path(
|
||||
"me/profile",
|
||||
api.users.views.ProfileMeApiView.as_view(),
|
||||
)
|
||||
name="profile-me",
|
||||
),
|
||||
path(
|
||||
"profiles/<str:login>",
|
||||
api.users.views.ProfileAPIView.as_view(),
|
||||
name="profiles",
|
||||
),
|
||||
path(
|
||||
"friends/add",
|
||||
api.users.views.AddFriendAPIView.as_view(),
|
||||
name="add-friend",
|
||||
),
|
||||
path(
|
||||
"friends/remove",
|
||||
api.users.views.RemoveFriendAPIView.as_view(),
|
||||
name="remove-friend",
|
||||
),
|
||||
]
|
||||
|
||||
@@ -10,7 +10,12 @@ from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from api.users.models import Profile
|
||||
from api.users.serializers import ProfileSerializer, UpdateProfileSerializer
|
||||
from api.users.permissions import CanAccessProfile
|
||||
from api.users.serializers import (
|
||||
ProfileSerializer,
|
||||
PublicProfileSerializer,
|
||||
UpdateProfileSerializer,
|
||||
)
|
||||
|
||||
|
||||
class RegisterUserApiView(APIView):
|
||||
@@ -116,3 +121,57 @@ class ProfileMeApiView(APIView):
|
||||
profile["image"] = user.image
|
||||
|
||||
return profile
|
||||
|
||||
|
||||
class ProfileAPIView(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:
|
||||
return Response(
|
||||
{"detail": "Profile not found."},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
|
||||
|
||||
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:
|
||||
return Response(
|
||||
{"detail": "Profile not found."},
|
||||
status=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
|
||||
|
||||
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:
|
||||
return Response(
|
||||
{"detail": "Profile not found."},
|
||||
status=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user