-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(profile):Add, read and update user profile (#17)
- create a profile application - Add a user profile - Edit user profile - View your user profile - View other profiles - Add tests to increase coverage [Delivers #165273475]
- Loading branch information
1 parent
d91f09d
commit 8e82eae
Showing
22 changed files
with
426 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -99,5 +99,6 @@ db.sqlite3 | |
|
||
#the coverage file | ||
.coveragerc | ||
.DS_Store | ||
|
||
htmlcov/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Generated by Django 2.1 on 2019-05-02 06:27 | ||
|
||
from django.conf import settings | ||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
initial = True | ||
|
||
dependencies = [ | ||
migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||
('articles', '0001_initial'), | ||
] | ||
|
||
operations = [ | ||
migrations.AddField( | ||
model_name='article', | ||
name='author', | ||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, to_field='username'), | ||
), | ||
] |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 0 additions & 18 deletions
18
authors/apps/authentication/migrations/0002_user_email_verified.py
This file was deleted.
Oops, something went wrong.
26 changes: 0 additions & 26 deletions
26
authors/apps/authentication/migrations/0003_resetpasswordtoken.py
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from django.contrib import admin | ||
|
||
# Register your models here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from django.apps import AppConfig | ||
|
||
|
||
class ProfilesConfig(AppConfig): | ||
name = 'profiles' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Generated by Django 2.1 on 2019-05-02 12:53 | ||
|
||
from django.conf import settings | ||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
initial = True | ||
|
||
dependencies = [ | ||
migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='UserProfile', | ||
fields=[ | ||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('image', models.URLField(blank=True)), | ||
('bio', models.TextField(blank=True, max_length=200)), | ||
('firstname', models.CharField(blank=True, max_length=25)), | ||
('lastname', models.CharField(blank=True, max_length=25)), | ||
('updated_at', models.DateTimeField(auto_now=True)), | ||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, to_field='username')), | ||
], | ||
), | ||
] |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
from django.db import models | ||
from authors.apps.authentication.models import User | ||
from django.dispatch import receiver | ||
from django.db.models.signals import post_save | ||
|
||
|
||
class UserProfile(models.Model): | ||
"""A model that contains different fields.""" | ||
|
||
user = models.OneToOneField(User, to_field="username", on_delete=models.CASCADE) | ||
image = models.URLField(blank=True) | ||
bio = models.TextField(blank=True, max_length=200) | ||
firstname = models.CharField(blank=True, max_length=25) | ||
lastname = models.CharField(blank=True, max_length=25) | ||
updated_at = models.DateTimeField(auto_now=True) | ||
|
||
def __str__(self): | ||
"""Method to return the string representation of an object.""" | ||
return self.user.username | ||
|
||
|
||
@receiver(post_save, sender=User) | ||
def create_user_profile(sender, instance, created, **kwargs): | ||
if created: | ||
UserProfile.objects.create(user=instance) | ||
|
||
@receiver(post_save, sender=User) | ||
def save_profile(sender, instance, **kwargs): | ||
instance.userprofile.save() | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import json | ||
from rest_framework.renderers import JSONRenderer | ||
|
||
|
||
class ProfileJSONRenderer(JSONRenderer): | ||
charset = 'utf-8' | ||
|
||
def render(self, data, media_type=None, renderer_context=None): | ||
# If the view throws an error (such as the user profile can't be found | ||
# or something similar), `data` will contain an `errors` key. We want | ||
# the default JSONRenderer to handle rendering errors, so we need to | ||
# check for this case. | ||
response = json.dumps({'profile': data}) | ||
|
||
errors = data.get('errors', None) | ||
|
||
if errors is not None: | ||
# As mentioned about, we will let the default JSONRenderer handle | ||
# rendering errors. | ||
response = super(ProfileJSONRenderer, self).render(data) | ||
|
||
# Finally, we can render our data under the "profile" namespace. | ||
return response |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
from rest_framework import serializers | ||
from authors.apps.profiles.models import UserProfile | ||
from .models import User | ||
import re | ||
|
||
|
||
class FetchUserProfileSerializer(serializers.ModelSerializer): | ||
class Meta: | ||
model = UserProfile | ||
fields = '__all__' | ||
|
||
|
||
class UpdateProfileSerializer(serializers.ModelSerializer): | ||
username = serializers.ReadOnlyField(source='user.username') | ||
class Meta: | ||
model = UserProfile | ||
fields = ( | ||
'firstname', | ||
'lastname', | ||
'username', | ||
'image', | ||
'bio' | ||
) | ||
|
||
def validate_username(self, username): | ||
username1 = User.objects.filter(username=username) | ||
if username1.exists(): | ||
raise serializers.ValidationError("Username already exists") | ||
if len(username) <= 4: | ||
raise serializers.ValidationError( | ||
"username should be longer than 4 characters") | ||
if re.search(r'[\s]', username): | ||
raise serializers.ValidationError( | ||
"username should not contain spaces") | ||
if not re.search(r'[a-zA-Z]', username): | ||
raise serializers.ValidationError( | ||
"username should contain characters") | ||
return username | ||
|
||
def validate_firstname(self,firstname): | ||
if len(firstname) <= 3: | ||
raise serializers.ValidationError( | ||
"Firstname should be longer than 3 characters") | ||
return firstname | ||
|
||
def validate_lastname(self,lastname): | ||
if len(lastname) <= 4: | ||
raise serializers.ValidationError( | ||
"Lastname should be longer than 4 characters") | ||
return lastname | ||
|
||
|
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
from django.contrib.auth import get_user_model | ||
from django.urls import reverse | ||
from rest_framework.test import APITestCase, APIClient | ||
from authors.apps.profiles.models import UserProfile | ||
|
||
User = get_user_model() | ||
|
||
|
||
class BaseTestCase(APITestCase): | ||
""" | ||
Testcases base for the user profile views. | ||
""" | ||
|
||
def setUp(self): | ||
"""Initialize test client.""" | ||
self.client = APIClient() | ||
self.user = User.objects.create_user( | ||
username='test1', email='test1@example.com', password='12345678' | ||
) | ||
setattr(self.user, 'email_verified', True) | ||
self.user.save() | ||
self.data = { | ||
'user': | ||
{ | ||
'email': 'test1@example.com', 'password': '12345678' | ||
} | ||
} | ||
self.login = reverse('user_login') | ||
self.login_response = self.client.post( | ||
self.login, self.data, format="json") | ||
user_token = self.login_response.data['token'] | ||
self.auth_header = 'Bearer {}'.format(user_token) | ||
|
||
self.profile = { | ||
"profile": { | ||
"firstname": "isaac", | ||
"lastname": "kimbugwe", | ||
"username": "isaac3", | ||
"image": "http://127.0.0.1:8000/api/users/profile/isaac.png", | ||
"bio": "I work at Andela" | ||
} | ||
} | ||
self.profile2 = { | ||
"profile": { | ||
"firstname": "isaac1", | ||
"lastname": "kimbugwe1", | ||
"username": "isaac1", | ||
"image": "http://127.0.0.1:8000/api/users/profile/isaac1.png", | ||
"bio": "I work at Andela uganda" | ||
} | ||
} | ||
self.profile4 = { | ||
"profile": { | ||
"firstname": "isaac1", | ||
"lastname": "kim", | ||
"username": "isaac12", | ||
"image": "http://127.0.0.1:8000/api/users/profile/isaac12.png", | ||
"bio": "I work at Andela uganda..." | ||
} | ||
} | ||
self.profile3 = { | ||
"profile": { | ||
"firstname": "is", | ||
"lastname": "kimbugwe12", | ||
"username": "isaac12", | ||
"image": "http://127.0.0.1:8000/api/users/profile/isaac12.png", | ||
"bio": "I work at Andela uganda..." | ||
} | ||
} | ||
self.profile5 = { | ||
"profile": { | ||
"firstname": "isaac23", | ||
"lastname": "kimbugwe12", | ||
"username": "is", | ||
"image": "http://127.0.0.1:8000/api/users/profile/isaac12.png", | ||
"bio": "I work at Andela uganda..." | ||
} | ||
} | ||
self.user2 = User.objects.create_user( | ||
username='test2', email='test2@example.com', password='12345678' | ||
) | ||
setattr(self.user2, 'email_verified', True) | ||
self.user2.save() | ||
self.data2 = { | ||
'user': { | ||
'email': 'test2@example.com', 'password': '12345678' | ||
} | ||
} |
Oops, something went wrong.