Skip to content

Commit

Permalink
Merge pull request #19 from andela/ft-user-profiles-161967013
Browse files Browse the repository at this point in the history
#161967013 Add Functionality for Creating and Editing User Profiles
  • Loading branch information
mirr254 committed Dec 10, 2018
2 parents 451af4a + cbec545 commit 9421945
Show file tree
Hide file tree
Showing 11 changed files with 281 additions and 25 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ ENV/
# SQLite3
db.sqlite3

# Migrations
authors/apps/*/migrations/*
.DS_Store
.vscode/

# vscode cache files and log files
.vscode/
logfile
4 changes: 4 additions & 0 deletions authors/apps/authentication/backends.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
"""Configure JWT Here"""


import datetime
import logging
import jwt
from django.conf import settings

from django.contrib.auth import get_user_model
from rest_framework import exceptions

from rest_framework.authentication import TokenAuthentication

from django.contrib.auth.tokens import PasswordResetTokenGenerator
Expand Down
3 changes: 1 addition & 2 deletions authors/apps/profiles/admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from django.contrib import admin

# Register your models here.
from .models import Profile

# Register your models here.
admin.site.register(Profile)
26 changes: 14 additions & 12 deletions authors/apps/profiles/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,21 @@ class Profile(models.Model):

# Add fields onto `Profile` model
username = models.CharField(max_length=50, blank=True)
email = models.EmailField(blank=True)
full_name = models.CharField(max_length=50, blank=True)
first_name = models.CharField(max_length=50, blank=True)
last_name = models.CharField(max_length=50, blank=True)
bio = models.CharField(max_length=200, blank=True)
image = models.URLField(blank=True)
profile_photo = models.URLField(blank=True)
country = models.CharField(max_length=3, blank=True)
phone_number = models.CharField(max_length=15, blank=True)
twitter_handle = models.CharField(max_length=15, blank=True)
website = models.URLField(blank=True)

def __str__(self):
"""
Schema for representation of a Profile object in Terminal
"""
return self.email

created = models.DateTimeField(
auto_now_add=True,
help_text="This is the time of creation of this record"
Expand All @@ -38,14 +47,6 @@ class Profile(models.Model):
"any time this record is updated"
)

def __str__(self):
"""
Schema for representation of a Profile object in Terminal
"""
return self.email



def get_followers(self):
"""get all users that follow a user"""
followers = Following.objects.filter(followed=self.user)
Expand Down Expand Up @@ -92,7 +93,8 @@ def init_profile(sender, instance, created, **kwargs):
"""
if created:
Profile.objects.create(
user=instance, username=instance.username, email=instance.email)
user=instance,
username=instance.username, first_name=instance.username)


@receiver(post_save, sender=User)
Expand Down
20 changes: 18 additions & 2 deletions authors/apps/profiles/serializers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import logging
"""
Module serializes `Profile` model
:generates JSON from fields in `Profile` model
"""

import logging
from rest_framework import serializers

from authors.apps.authentication.serializers import UserSerializer
Expand All @@ -13,14 +17,26 @@ class Meta:
model = Profile
fields = ("__all__")

def update(self, instance, prof_data):
"""
Update profile items
"""
# For every item provided in the payload,
# amend the profile accordingly
for(key, value) in prof_data.items():
setattr(instance.profile, key, value)
instance.save()

return instance


class ProfileSerializer2(serializers.ModelSerializer):
user = serializers.SerializerMethodField()
following = serializers.SerializerMethodField()

class Meta:
model = Profile
exclude = ('username', 'email')
exclude = ('username',)

def get_user(self, obj):
"""
Expand Down
Empty file.
157 changes: 157 additions & 0 deletions authors/apps/profiles/tests/test_profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
"""
Module contains the unittests for the `profiles` app
"""
import json
from rest_framework.test import APITestCase
from django.urls import reverse

# local imports
from authors.apps.profiles.models import Profile
from authors.apps.authentication.models import User

# Create your tests here.


class TestProfileModel(APITestCase):
"""
UNITTESTS for Profile Model
"""

def setUp(self):
"""
Set up
"""
# Generate a test client for sending API requests
# Define the endpoints for register, login
self.register_endpoint = reverse('register')
self.login_endpoint = reverse('login')
self.profile_endpoint = reverse('user_profiles')

self.user = {"user": {
"username": "rkemmy69",
"email": "rkemmy69@mymail.com",
"password": "#Strong2-password"
}
}

def register_user_helper(self):
"""
Helper method for registering a user and returning a user
"""
# Register a user to generate a token
register_response = self.client.post(
self.register_endpoint, self.user, format='json')

user = User.objects.get(username=self.user['user']['username'])
user.is_active = True
user.save()
user = User.objects.get(username=self.user['user']['username'])

# Decode response and extract user
user = json.loads(
register_response.content.decode('utf-8'))['user']

return user

def test_profile_auto_created_on_user_creation(self):
"""
Test autocreation of profile for each user
"""
# profile counts before user is saved
prof_count_before = Profile.objects.count()

# Register a user and recount profiles
self.client.post(
self.register_endpoint, self.user, format='json')

prof_count_after = Profile.objects.count()

# assertions
self.assertEqual(prof_count_after - prof_count_before, 1)

def test_unlogged_in_user_cannot_view_profile(self):
"""
Test that an unlogged in user cannot view the profile
"""
# Send a GET request to view profile
view_profile_response = self.client.get(
self.profile_endpoint, format='json')

# extract status code from response
response_message = json.loads(
view_profile_response.content.decode('utf-8'))['detail']

# Assertions
# assert that the response message is as below
self.assertEqual(
response_message, "Authentication credentials were not provided.")

# Check that the reponse status code is 401
self.assertEqual(view_profile_response.status_code, 401)

def test_user_can_view_profile(self):
"""
Test that a logged in user can view the profile
"""
# Register a user to generate a token
# Decode response and extract token
user = self.register_user_helper()
user_token = user['token']

# Send a GET request to view profile with token
self.client.credentials(HTTP_AUTHORIZATION='Token ' + user_token)
view_profile_response = self.client.get(
self.profile_endpoint, format='json')

# extract profile from response
user_profile = json.loads(
view_profile_response.content.decode('utf-8'))['profile']

# Assertions
# assert that the user_profile is not null
self.assertTrue(user_profile)

# assert that the user_profile is not null
self.assertEqual(view_profile_response.status_code, 200)

# assert that profile contains username of signed in user
self.assertEqual(
user_profile['first_name'], user['username']
)

def test_user_can_update_profile(self):
"""
Test that a logged in user can view the profile
"""
# Register a user to generate a token
# Decode response and extract token
user = self.register_user_helper()
user_token = user['token']

# Send a PUT request to update profile with token
changes_to_profile = {
"profile": {
"country": "USB",
"twitter_handle": "@dmithamo2"
}
}
self.client.credentials(HTTP_AUTHORIZATION='Token ' + user_token)
view_profile_response = self.client.put(
self.profile_endpoint, data=changes_to_profile, format='json')

# extract profile from response
user_profile = json.loads(
view_profile_response.content.decode('utf-8'))['profile']

# Assertions
# assert that the status_code is 200 OK
self.assertEqual(view_profile_response.status_code, 200)

# assert that profile contains username of signed in user
self.assertEqual(
user_profile['country'], changes_to_profile['profile']['country'])

# assert that twitter_handle changes as expected
self.assertEqual(
user_profile['twitter_handle'],
changes_to_profile['profile']['twitter_handle'])
4 changes: 4 additions & 0 deletions authors/apps/profiles/urls.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
"""
Define the urls where the views for `profiles` are accessible
"""
from django.urls import path
from . import views
from authors.apps.profiles.views import GetUserProfile, \
Expand All @@ -10,4 +13,5 @@
path('<str:username>/follow', FollowUser.as_view(), name="follow"),
path('followers/', ListAllFollowers.as_view(), name="followers"),
path('followed/', ListAllFollowed.as_view(), name="followed"),
path('users/profiles', views.ProfileView.as_view(), name='user_profiles'),
]
Loading

0 comments on commit 9421945

Please sign in to comment.