Skip to content

Commit

Permalink
feat: can send friend request
Browse files Browse the repository at this point in the history
  • Loading branch information
Akay7 committed Jun 6, 2024
1 parent 182023f commit 7ccf805
Show file tree
Hide file tree
Showing 16 changed files with 250 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"python.envFile": "${workspaceFolder}/env/local.env",
"python.testing.pytestArgs": [
"."
"backend"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
Expand Down
3 changes: 3 additions & 0 deletions backend/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pytest_plugins = [
"user.tests.fixtures",
]
Empty file.
1 change: 1 addition & 0 deletions backend/friend_request/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Register your models here.
6 changes: 6 additions & 0 deletions backend/friend_request/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class FriendRequestConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "friend_request"
53 changes: 53 additions & 0 deletions backend/friend_request/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Generated by Django 5.0.6 on 2024-06-06 08:16

import django.db.models.deletion
import uuid
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):
initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name="FriendRequest",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("accepted_at", models.DateTimeField(null=True)),
("rejected_at", models.DateTimeField(null=True)),
(
"from_user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="friend_requests_sent",
to=settings.AUTH_USER_MODEL,
),
),
(
"to_user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="friend_requests_received",
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"unique_together": {("from_user", "to_user")},
},
),
]
Empty file.
25 changes: 25 additions & 0 deletions backend/friend_request/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import uuid
from django.db import models


class FriendRequest(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
from_user = models.ForeignKey(
"user.User",
on_delete=models.CASCADE,
related_name="friend_requests_sent",
)
to_user = models.ForeignKey(
"user.User",
on_delete=models.CASCADE,
related_name="friend_requests_received",
)
created_at = models.DateTimeField(auto_now_add=True)
accepted_at = models.DateTimeField(null=True)
rejected_at = models.DateTimeField(null=True)

class Meta:
unique_together = ("from_user", "to_user")

def __str__(self):
return f"{self.from_user} -> {self.to_user}"
29 changes: 29 additions & 0 deletions backend/friend_request/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from rest_framework import serializers
from .models import FriendRequest


class FriendRequestSerializer(serializers.ModelSerializer):
def validate_to_user(self, to_user):
if to_user == self.context["request"].user:
raise serializers.ValidationError(
"You can't send a friend request to yourself."
)
return to_user

class Meta:
model = FriendRequest
fields = (
"id",
"from_user",
"to_user",
"created_at",
"accepted_at",
"rejected_at",
)
read_only_fields = (
"id",
"from_user",
"created_at",
"accepted_at",
"rejected_at",
)
94 changes: 94 additions & 0 deletions backend/friend_request/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import pytest
from user.tests.fixtures import UserFactory
from friend_request.models import FriendRequest
import factory


class FriendRequestFactory(factory.django.DjangoModelFactory):
from_user = factory.SubFactory(UserFactory)
to_user = factory.SubFactory(UserFactory)

class Meta:
model = FriendRequest


@pytest.fixture
def another_user():
return UserFactory()


def test_review_friend_requests(authenticated_client, user):
response = authenticated_client.get("/api/friend-request/")

assert response.status_code == 200
assert response.data["count"] == 0
assert len(response.data["results"]) == 0


def test_cant_review_friend_requests_of_other_users(authenticated_client, user):
FriendRequestFactory.create_batch(3)

response = authenticated_client.get("/api/friend-request/")

assert response.status_code == 200
assert response.data["count"] == 0
assert len(response.data["results"]) == 0


def test_can_create_friend_request(authenticated_client, user, another_user):
response = authenticated_client.post(
"/api/friend-request/",
{
"to_user": another_user.id,
},
)

assert response.status_code == 201
assert response.data["from_user"] == user.id
assert response.data["to_user"] == another_user.id
assert response.data["created_at"]
assert response.data["rejected_at"] is None
assert response.data["accepted_at"] is None


def test_can_review_created_requests(authenticated_client, user, another_user):
friend_request = FriendRequestFactory(from_user=user, to_user=another_user)

response = authenticated_client.get("/api/friend-request/")

assert response.status_code == 200
assert response.data["count"] == 1
assert len(response.data["results"]) == 1
assert response.data["results"][0]["from_user"] == user.id
assert response.data["results"][0]["id"] == str(friend_request.id)


def test_can_review_request_to_user(authenticated_client, user, another_user):
friend_request = FriendRequestFactory(from_user=another_user, to_user=user)

response = authenticated_client.get("/api/friend-request/")

assert response.status_code == 200
assert response.data["count"] == 1
assert len(response.data["results"]) == 1
assert response.data["results"][0]["to_user"] == user.id
assert response.data["results"][0]["id"] == str(friend_request.id)


def test_cant_create_request_to_user_itself(authenticated_client, user):
response = authenticated_client.post(
"/api/friend-request/",
{
"to_user": user.id,
},
)

assert response.status_code == 400
assert response.data == {
"to_user": ["You can't send a friend request to yourself."]
}


# test cant create request to user that already has a request
# test cant create request to user that already friend
# test cant create request to user that already rejected request
19 changes: 19 additions & 0 deletions backend/friend_request/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from rest_framework import viewsets
from django.db.models import Q
from .models import FriendRequest
from .serializers import FriendRequestSerializer


class FriendRequestViewSet(viewsets.ModelViewSet):
queryset = FriendRequest.objects.all()
serializer_class = FriendRequestSerializer

def get_queryset(self):
return (
super()
.get_queryset()
.filter(Q(from_user=self.request.user) | Q(to_user=self.request.user))
)

def perform_create(self, serializer):
serializer.save(from_user=self.request.user)
File renamed without changes.
1 change: 1 addition & 0 deletions backend/social_network/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"dj_rest_auth.registration",
# local
"user",
"friend_request",
]

MIDDLEWARE = [
Expand Down
2 changes: 2 additions & 0 deletions backend/social_network/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@
TokenRefreshView,
)
from user.views import UserViewSet
from friend_request.views import FriendRequestViewSet


router = routers.DefaultRouter()
router.register(r"users", UserViewSet)
router.register(r"friend-request", FriendRequestViewSet)


urlpatterns = [
Expand Down
14 changes: 14 additions & 0 deletions backend/user/tests/conftest.py → backend/user/tests/fixtures.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
import pytest
from django.contrib.auth import get_user_model
from rest_framework.test import APIClient
from rest_framework_simplejwt.tokens import RefreshToken
import factory


User = get_user_model()


class UserFactory(factory.django.DjangoModelFactory):
class Meta:
model = User

first_name = factory.Faker("first_name")
last_name = factory.Faker("last_name")
email = factory.Faker("email")


def authenticate_client(client, user):
Expand Down
16 changes: 2 additions & 14 deletions backend/user/tests/users_api_tests.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
import factory

from django.contrib.auth import get_user_model

User = get_user_model()


class UserFactory(factory.django.DjangoModelFactory):
class Meta:
model = User

first_name = factory.Faker("first_name")
last_name = factory.Faker("last_name")
email = factory.Faker("email")
from user.tests.fixtures import UserFactory


def test_search_by_email(user, authenticated_client, email):
Expand Down Expand Up @@ -49,7 +37,7 @@ def test_search_by_name_empty_result(user, authenticated_client):
def test_search_by_name_find_by_part_of_name(authenticated_client):
names = {"Amarendra", "Amar", "aman", "Abhirama"}
UserFactory.create_batch(len(names), first_name=factory.Iterator(names))
UserFactory.create(first_name="Egor")
UserFactory.create(first_name="Egor", last_name="Empty")

response = authenticated_client.get("/api/users/?search=am")

Expand Down

0 comments on commit 7ccf805

Please sign in to comment.