Skip to content

Commit

Permalink
Merge fabad92 into ea62c3d
Browse files Browse the repository at this point in the history
  • Loading branch information
Estaer committed Sep 17, 2018
2 parents ea62c3d + fabad92 commit 57cf334
Show file tree
Hide file tree
Showing 12 changed files with 199 additions and 48 deletions.
4 changes: 2 additions & 2 deletions authors/apps/articles/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from authors.apps.authentication.models import User
from authors.apps.authentication.serializers import UserSerializer
from authors.apps.profiles.models import UserProfile
from authors.apps.profiles.serializers import RetrieveUserProfileSerializer
from authors.apps.profiles.serializers import UserProfileSerializer


class ArticleSerializer(serializers.ModelSerializer):
Expand Down Expand Up @@ -67,7 +67,7 @@ def to_representation(self, instance):
:return:
"""
response = super().to_representation(instance)
profile = RetrieveUserProfileSerializer(UserProfile.objects.get(user=instance.author)).data
profile = UserProfileSerializer(UserProfile.objects.get(user=instance.author), context=self.context).data

response['author'] = profile
return response
Expand Down
8 changes: 4 additions & 4 deletions authors/apps/articles/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def to_int(val):
if queryset.count() > 0:
queryset = queryset[offset:]

data = self.serializer_class(queryset, many=True).data
data = self.serializer_class(queryset, many=True, context={'request': request}).data

pager_class = PaginatedArticleSerializer()
pager_class.page_size = limit
Expand All @@ -69,7 +69,7 @@ def retrieve(self, request, slug=None):
"""
queryset = Article.objects.all()
article = get_object_or_404(queryset, slug=slug)
serializer = self.serializer_class(article)
serializer = self.serializer_class(article, context={'request': request})
return Response(serializer.data)

def create(self, request):
Expand All @@ -81,7 +81,7 @@ def create(self, request):
article = request.data.get("article", {})
article.update({"author": request.user.pk})

serializer = self.serializer_class(data=article)
serializer = self.serializer_class(data=article, context={'request': request})
serializer.is_valid(raise_exception=True)
serializer.save()

Expand All @@ -99,7 +99,7 @@ def update(self, request, slug=None):
article, article_update = self.serializer_class.validate_for_update(
article_update, request.user, slug)

serializer = self.serializer_class(data=article_update)
serializer = self.serializer_class(data=article_update, context={'request': request})
serializer.instance = article
serializer.is_valid(raise_exception=True)

Expand Down
6 changes: 3 additions & 3 deletions authors/apps/authentication/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from django.shortcuts import get_object_or_404
from authors.apps.profiles.models import UserProfile
from authors.apps.profiles.serializers import RetrieveUserProfileSerializer
from authors.apps.profiles.serializers import UserProfileSerializer


class RegistrationSerializer(serializers.ModelSerializer):
Expand Down Expand Up @@ -233,7 +233,7 @@ def to_representation(self, instance):
"""

user = super().to_representation(instance)
profile = RetrieveUserProfileSerializer(
UserProfile.objects.get(user_id=instance.id)).data
profile = UserProfileSerializer(
UserProfile.objects.get(user_id=instance.id), context=self.context).data
user['profile'] = profile
return user
2 changes: 1 addition & 1 deletion authors/apps/authentication/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,6 @@ def retrieve(self, request):
This method returns a list of users with their profiles.
"""
queryset = User.objects.filter(is_active=True, is_email_verified=True)
serializer = self.serializer_class(queryset, many=True)
serializer = self.serializer_class(queryset, many=True, context={'request': request})

return Response({'users': serializer.data}, status=status.HTTP_200_OK)
4 changes: 2 additions & 2 deletions authors/apps/profiles/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# Generated by Django 2.1 on 2018-09-12 18:34

# Generated by Django 2.1 on 2018-09-17 07:29

from django.conf import settings
from django.db import migrations, models
Expand Down Expand Up @@ -27,6 +26,7 @@ class Migration(migrations.Migration):
('birth_date', models.DateField(blank=True, null=True)),
('location', models.CharField(blank=True, max_length=100, null=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('following', models.ManyToManyField(related_name='user_following', to='profiles.UserProfile')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
Expand Down
16 changes: 15 additions & 1 deletion authors/apps/profiles/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,19 @@ class UserProfile(models.Model):
# A timestamp representing when this object was last updated.
updated_at = models.DateTimeField(auto_now=True)

following = models.ManyToManyField('self', related_name='followers', symmetrical=False)

def __str__(self):
return self.first_name
return self.user.username

def follow(self, profile):
"""Following a user"""
self.following.add(profile)

def unfollow(self, profile):
"""Unfollow a user"""
self.following.remove(profile)

def is_following(self, profile):
"""To check if a user is already following the profile"""
return self.following.filter(pk=profile.pk).exists()
23 changes: 17 additions & 6 deletions authors/apps/profiles/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,27 @@
from authors.apps.profiles.models import UserProfile


class RetrieveUserProfileSerializer(serializers.ModelSerializer):
class UserProfileSerializer(serializers.ModelSerializer):

username = serializers.CharField(source='user.username')
bio = serializers.CharField(allow_blank=True, required=False)
first_name = serializers.CharField(allow_blank=True, required=False)
last_name = serializers.CharField(allow_blank=True, required=False)
location = serializers.CharField(allow_blank=True, required='False')
following = serializers.SerializerMethodField()
followers = serializers.SerializerMethodField()

class Meta:
model = UserProfile
fields = ('username', 'bio', 'first_name', 'last_name', 'location')
fields = ('username', 'bio', 'first_name', 'last_name', 'location', 'avatar', 'following', 'followers')
read_only_fields = ('username',)
extra_kwargs = {'token': {'read_only': True}}

def helper(self):
return self.context.get('request', None)

def get_following(self, instance):
request = self.helper()
following_profiles = request.user.userprofile.following.all()
return [following_profile.user.username for following_profile in following_profiles]

def get_followers(self, instance):
user_request = self.helper()
followers_profiles = user_request.user.userprofile.followers.all()
return [followers_profile.user.username for followers_profile in followers_profiles]
4 changes: 1 addition & 3 deletions authors/apps/profiles/tests/base_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ def __init__(self):
}

self.second_user = {"user": {"username": "second_user", "email": "second@exists.com",
"password": self.password,
}
}
"password": self.password, }}


78 changes: 78 additions & 0 deletions authors/apps/profiles/tests/test_follow_unfollow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
from django.test import TestCase
from rest_framework.test import APIClient
from rest_framework import status

from authors.apps.authentication.models import User
from authors.apps.profiles.tests.base_test import BaseTest


class TestFollowUnfollow(TestCase, BaseTest):
def setUp(self):
BaseTest.__init__(self)
self.client = APIClient()
# create a new user
self.user = User.objects.create_user(self.user_name, self.user_email, self.password)
# activate user account and login
self.user.is_active = True
self.user.is_email_verified = True
self.user.save()
self.login_response = self.client.post(
"/api/users/login/",
self.login_data,
format="json")
# create second user
self.second_user = User.objects.create_user('second_user', 'second@exists.com', self.password)
# activate user account and login
self.user.is_active = True
self.user.is_email_verified = True
self.user.save()
# self.login_response = self.client.post(
# "/api/users/login/",
# {"second_username", "second@exists.com", self.password},
# format="json")

def test_follow_user(self):
self.client.credentials(
HTTP_AUTHORIZATION='Token ' + self.login_response.data['token'])
self.response = self.client.post('/api/profile/{}/follow'.format(self.second_user.username))
self.assertEqual(self.response.status_code, status.HTTP_200_OK)

def test_follow_self(self):
self.client.credentials(
HTTP_AUTHORIZATION='Token ' + self.login_response.data['token'])
self.response = self.client.post('/api/profile/{}/follow'.format(self.user.username))
self.assertEqual(self.response.status_code, status.HTTP_400_BAD_REQUEST)

def test_follow_user_404(self):
self.client.credentials(
HTTP_AUTHORIZATION='Token ' + self.login_response.data['token'])
self.response = self.client.post('/api/profile/{}/follow'.format('non-user'))
self.assertEqual(self.response.status_code, status.HTTP_404_NOT_FOUND)

def test_already_following(self):
self.client.credentials(
HTTP_AUTHORIZATION='Token ' + self.login_response.data['token'])
self.client.post('/api/profile/{}/follow'.format(self.second_user.username))
self.response = self.client.post('/api/profile/{}/follow'.format(self.second_user.username))
self.assertEqual(self.response.status_code, status.HTTP_400_BAD_REQUEST)

def test_unfollow_user(self):

self.client.credentials(
HTTP_AUTHORIZATION='Token ' + self.login_response.data['token'])
self.client.post('/api/profile/{}/follow'.format(self.second_user.username))
self.response = self.client.delete('/api/profile/{}/unfollow'.format(self.second_user.username))
self.assertEqual(self.response.status_code, status.HTTP_200_OK)

def test_unfollow_user_not_followed(self):
self.client.credentials(
HTTP_AUTHORIZATION='Token ' + self.login_response.data['token'])
self.response = self.client.delete('/api/profile/{}/unfollow'.format(self.second_user.username))
self.assertEqual(self.response.status_code, status.HTTP_400_BAD_REQUEST)

def test_unfollow_user_404(self):
self.client.credentials(
HTTP_AUTHORIZATION='Token ' + self.login_response.data['token'])
self.response = self.client.post('/api/profile/{}/unfollow'.format('non-user'))
self.assertEqual(self.response.status_code, status.HTTP_404_NOT_FOUND)
self.assertEqual(self.response.json(), {'detail': 'Profile with this username was not found.'})
13 changes: 10 additions & 3 deletions authors/apps/profiles/tests/test_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def test_profile_created(self):

self.assertEqual(len(self.queryset), 1)

self.assertEqual(self.get_profile.__str__(), None)
self.assertEqual(self.get_profile.__str__(), self.user_name)

def test_retrieve_profile(self):
self.user.is_active = True
Expand All @@ -86,7 +86,11 @@ def test_retrieve_profile(self):
'first_name': None,
'last_name': None,
'location': None,
'username': self.user_name}}
'username': self.user_name,
'following': [],
'followers': [],
'avatar': None
}}
)

def test_update_profile(self):
Expand All @@ -113,7 +117,10 @@ def test_update_profile(self):
'first_name': self.first_name,
'last_name': self.last_name,
'location': self.location,
'username': self.user_name}}
'username': self.user_name,
'avatar': None,
'following': [],
'followers': []}}
)

def test_update_with_existing_username(self):
Expand Down
10 changes: 5 additions & 5 deletions authors/apps/profiles/urls.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from django.urls import path
from .views import (
RetrieveUserProfileAPIView, UpdateUserProfileAPIView
from .views import (UserProfileAPIView, FollowUnfollowUserAPIView
)

urlpatterns = [
path('profile/<username>/', RetrieveUserProfileAPIView.as_view(), name="view_profile"),
path('user/update/profile/', UpdateUserProfileAPIView.as_view(), name="update_profile"),

path('profile/<username>/', UserProfileAPIView.as_view(), name="view_profile"),
path('user/update/profile/', UserProfileAPIView.as_view(), name="update_profile"),
path('profile/<username>/follow', FollowUnfollowUserAPIView.as_view(), name="follow_user"),
path('profile/<username>/unfollow', FollowUnfollowUserAPIView.as_view(), name="unfollow_user"),
]
Loading

0 comments on commit 57cf334

Please sign in to comment.