From b6ca498120edd9863e60c215992de98b4d273e70 Mon Sep 17 00:00:00 2001 From: AnguleMathias <39617195+AnguleMathias@users.noreply.github.com> Date: Thu, 8 Nov 2018 16:50:23 +0300 Subject: [PATCH] #161255357 Profile creation (#19) * Feature(User Profile):Users should be able to create their profiles - Model for user profile - User relation migrations - Serializer to user profile inputs [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Model for user profile - User relation migrations - Serializer to user profile inputs [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - GET, PUT and PATCH view for profile - Add admin.py with credentials - Profile relations migrations - Update serializer [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - update .gitignore [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Refactor failing test assertion error - remove admin.py [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - View all profiles [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Update profile data [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Model for user profile - User relation migrations - Serializer to user profile inputs [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Model for user profile - User relation migrations - Serializer to user profile inputs [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - GET, PUT and PATCH view for profile - Add admin.py with credentials - Profile relations migrations - Update serializer [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - update .gitignore [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - View all profiles [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Fetch all profiles [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Test User profile [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Refactor test [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Refactor test [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Refactor test [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Refactor test [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Refactor test [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Refactor test [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Refactor test [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Model for user profile - User relation migrations - Serializer to user profile inputs [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Model for user profile - User relation migrations - Serializer to user profile inputs [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - GET, PUT and PATCH view for profile - Add admin.py with credentials - Profile relations migrations - Update serializer [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Refactor failing test assertion error - remove admin.py [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Model for user profile - User relation migrations - Serializer to user profile inputs [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Model for user profile - User relation migrations - Serializer to user profile inputs [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - View all profiles [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Fetch all profiles [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Test User profile [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Refactor test [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Model for user profile - User relation migrations - Serializer to user profile inputs [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Model for user profile - User relation migrations - Serializer to user profile inputs [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - GET, PUT and PATCH view for profile - Add admin.py with credentials - Profile relations migrations - Update serializer [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - update .gitignore [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Refactor failing test assertion error - remove admin.py [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - View all profiles [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Update profile data [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Model for user profile - User relation migrations - Serializer to user profile inputs [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Model for user profile - User relation migrations - Serializer to user profile inputs [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Refactor failing test assertion error - remove admin.py [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Refactor test [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Model for user profile - User relation migrations - Serializer to user profile inputs [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Model for user profile - User relation migrations - Serializer to user profile inputs [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - GET, PUT and PATCH view for profile - Add admin.py with credentials - Profile relations migrations - Update serializer [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - View all profiles [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Update profile data [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Model for user profile - User relation migrations - Serializer to user profile inputs [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Model for user profile - User relation migrations - Serializer to user profile inputs [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - GET, PUT and PATCH view for profile - Add admin.py with credentials - Profile relations migrations - Update serializer [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Refactor failing test assertion error - remove admin.py [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Update profile data [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Test User profile [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Refactor test [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Refactor test [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Refactor test [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Refactor test [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Refactor test [Feature #161255357] Feature(User Profile):Users should be able to create their profiles - Refactor test [Feature #161255357] * Feature(User Profile):Users should be able to create their profiles - Refactor tests [Feature #161255357] * Feature(User Profile):Users should be able to create their profiles - Update urls and profile renderer [Feature #161255357] * Feature(User Profile):Users should be able to create their profiles - Update urls [Feature #161255357] --- .DS_Store | Bin 0 -> 6148 bytes .gitignore | 5 ++ authors/.DS_Store | Bin 0 -> 6148 bytes authors/apps/.DS_Store | Bin 0 -> 6148 bytes authors/apps/authentication/.DS_Store | Bin 0 -> 6148 bytes authors/apps/authentication/serializers.py | 7 ++- .../tests/test_reset_password.py | 2 - authors/apps/core/models.py | 10 ++++ authors/apps/profiles/.DS_Store | Bin 0 -> 6148 bytes authors/apps/profiles/apps.py | 5 ++ authors/apps/profiles/exceptions.py | 6 ++ .../apps/profiles/migrations/0001_initial.py | 33 +++++++++++ .../migrations/0002_auto_20181104_1033.py | 17 ++++++ .../migrations/0003_auto_20181105_0939.py | 21 +++++++ authors/apps/profiles/migrations/__init__.py | 0 authors/apps/profiles/models.py | 16 ++++++ authors/apps/profiles/renderers.py | 25 +++++++++ authors/apps/profiles/serializers.py | 17 ++++++ authors/apps/profiles/tests/__init__.py | 0 authors/apps/profiles/tests/base_test.py | 26 +++++++++ authors/apps/profiles/tests/test_profiles.py | 30 ++++++++++ authors/apps/profiles/urls.py | 10 ++++ authors/apps/profiles/views.py | 53 ++++++++++++++++++ authors/urls.py | 2 +- 24 files changed, 281 insertions(+), 4 deletions(-) create mode 100644 .DS_Store create mode 100644 authors/.DS_Store create mode 100644 authors/apps/.DS_Store create mode 100644 authors/apps/authentication/.DS_Store create mode 100644 authors/apps/core/models.py create mode 100644 authors/apps/profiles/.DS_Store create mode 100644 authors/apps/profiles/apps.py create mode 100644 authors/apps/profiles/exceptions.py create mode 100644 authors/apps/profiles/migrations/0001_initial.py create mode 100644 authors/apps/profiles/migrations/0002_auto_20181104_1033.py create mode 100644 authors/apps/profiles/migrations/0003_auto_20181105_0939.py create mode 100644 authors/apps/profiles/migrations/__init__.py create mode 100644 authors/apps/profiles/models.py create mode 100644 authors/apps/profiles/renderers.py create mode 100644 authors/apps/profiles/serializers.py create mode 100644 authors/apps/profiles/tests/__init__.py create mode 100644 authors/apps/profiles/tests/base_test.py create mode 100644 authors/apps/profiles/tests/test_profiles.py create mode 100644 authors/apps/profiles/urls.py create mode 100644 authors/apps/profiles/views.py diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..d15f9e6282de6466eded955e2f3a0b4705d594f8 GIT binary patch literal 6148 zcmeHK%Wl&^6upy})=7l$0;yekgT$gjDJ^7yDupy%L;_S{1Pef|otVaw;|Z~oP(qM5 zd<6Uf;!9YukwZi_T%c7&afyk3 z;cHgXEj1vMV{jT#+KG8Lh}W`BgHgaJ@UJN#zTHjoX-paQY3cjr0eZx?a1Va-r!+)s z*}*g&2C>Zk8Vuto&Fb~tHY;4+g)vjKxzV!Nh>Sca5PFw!yxu_lcSwGP66VBs{ z*bkmY;q=70e#n!|kCJdC$x$yv%8O@F(&N(>A1A$3j^n8g+pgG^6K8ui+i%?2arbZU z&3D{cqftk^cXvLo*jqPt4?3rV^S85i^Y4+YYhw>KWdqbJp`YxpVjLc=}Dl~x93H*#gaE5fg%3xashE2!VQaN?$6-5+N zSjhiS$gj|2Jk5P-(?j`G1L_qRKMD*73Dg96KgeS!g*;S^{fPql^|!?yV9Y3B6fg=bDDUi~>f1|4IR7wY_!=OVVfS y+Tz4n>%vdr!bD!KP*PCn<5&jbDBgxkL!T=GU{hnR5G^qCBOqlkg;C(ID)0+`!^@HY literal 0 HcmV?d00001 diff --git a/.gitignore b/.gitignore index 8f32ba1..1eab59b 100644 --- a/.gitignore +++ b/.gitignore @@ -93,3 +93,8 @@ cod_venv/ # SQLite3 db.sqlite3 + +# Admin +admin.py + +.DS_Store diff --git a/authors/.DS_Store b/authors/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5e382717dd91c45293e60b10940b8d5a91541794 GIT binary patch literal 6148 zcmeHK!H&}~5FPIp>b4+yK-xX#g2Z8ky6i#^E2OBq9QKA(1P4Ifq^;UWA*q^_sFb2y z_9Nf}koXk7fDhpV;EiooN!q<|KnQuF@f+JScKxQYVm}1r%zGfKnRZc|fxbZ`)uQunhcb4Dh?#Qtxa)5f$Ix<#`wn{V?|7!P~kcU!vN34yuU5z1M+eUF!=v?qv+8y`u#XNC7Br`D`z*vMFM7+ecXf1??4p02GK@UIO17TnX~@*&L3!rV}VnjPai%AJI((Uz70%RrfdU0rSS`Tz9#`+qse z)+_^-f&YpDQ9J9O^{^y!wr(tr&sqn10cByoT%!s>VUA;E@KL-ERf0Z;4WMf<*N7H~ P{SZ(z*upaKR~h&P_QuMk literal 0 HcmV?d00001 diff --git a/authors/apps/.DS_Store b/authors/apps/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..1bcdbd52ec5cf494a2bff12798076fd3098222ee GIT binary patch literal 6148 zcmeHKO>Wab6n@hh>ZJT+fz&R&L1Iy%l$K_JkfKl)-60vl0#IrvhFCJ5$aaX*5abPq zfCC_L6i&cFH~@TaWjMMN%~(P^SM$GDxn zW*er4c|!FOQ$c+kw`p9yU(e3wZx`=AV1O`zNmto*gFoRTf6|f5Y zUj=x6@ZgMHgQZ3_b)ZmN0HA|vWr+D_fjOSRuEA0xT3|v`fto7J7DH${>OGU!HCSrY zbP{IsASwzLXZ1y&W<)Tb?8{~!K-|G!GIXI25Lz=cvkILH2R z4?{9*Yi)46)_U+$I2-4c8WjbFS&mh}OYtsT8QMG!fL(*7M%2LUkARZF7FL0Os=yBg ClJK+u literal 0 HcmV?d00001 diff --git a/authors/apps/authentication/.DS_Store b/authors/apps/authentication/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..a98f4ee2868f581d0c738f6e644825b1c7e5b2a2 GIT binary patch literal 6148 zcmeH~y^a$x6os!Li0o#Cwu5pC3K|F?Q6QRV6$&JvLDZ1HWd}lLl$n6C)ik^c63@p2 zz;}Hun7;*y0wH8a_Vw83*w^QJ#<7UFlil*3$gzkF$!Z6O6g^4%HFwgb(4u7L$4I4= zSN!fs-a*HPs6bTUUsFKe-I0H1Q`t!U{oOxVXN&ndn}bl)Bl4|pK2Z}n>SxKK#rx9Y z*=)J&Wg#>2nXGiACd*xKv4&um@*WR2{_E26&VBkFJ}>7_cSX4c_e@?&!K_=#vAm;p z8$a&KeV*USL%v;0Ih7B1_JIB={ROB}GJ3|;Q~Xfo41_W>@GHtw><--C_i62nR-0u8 zHxDf9S+SCmu~Y@M8P8+9>#P*dp9jx7ec(qj_d4o2Hh56<>hraw&!N}y4c`5ny=cb3 zNBnaw;s5F)scMYEuowA}e<@qnT zsz#lAKm=C!n!{8*h-+K3tgDg&T_Vvon6;;o>G{V;L2Q3N#hCY>&r!{y*j& zzTp1fB*mwwKvdwrQos$SFQz9fDV(jH#pzj_kYAHEDXuc>DHP#2_7y#fZ;*YWFVPBi V5^QCb7E=5p;AMzKRN${F@Evu){muXY literal 0 HcmV?d00001 diff --git a/authors/apps/authentication/serializers.py b/authors/apps/authentication/serializers.py index d7b7efe..bf62efd 100644 --- a/authors/apps/authentication/serializers.py +++ b/authors/apps/authentication/serializers.py @@ -10,8 +10,11 @@ from .models import User from authors.settings import SECRET_KEY +from authors.apps.profiles.models import Profile + from .backends import JWTAuthentication +from authors.apps.profiles.models import Profile class RegistrationSerializer(serializers.ModelSerializer): """Serializers registration requests and creates a new user.""" @@ -55,7 +58,9 @@ class Meta: def create(self, validated_data): # Use the `create_user` method we wrote earlier to create a new user. - return User.objects.create_user(**validated_data) + user = User.objects.create_user(**validated_data) + Profile.objects.create(user=user) + return user class LoginSerializer(serializers.Serializer): diff --git a/authors/apps/authentication/tests/test_reset_password.py b/authors/apps/authentication/tests/test_reset_password.py index 3e16f44..c04f64d 100644 --- a/authors/apps/authentication/tests/test_reset_password.py +++ b/authors/apps/authentication/tests/test_reset_password.py @@ -22,7 +22,6 @@ def test_invalid_email(self): '''Test invalid email''' response = self.client.post(self.FORGOT_URL, {"email": "qw"}, format="json") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual(json.loads(response.content)["email"][0], "Enter a valid email address.") def test_unregistered_user(self): '''Test unregister user''' @@ -104,4 +103,3 @@ def test_reset_password(self): response13 = self.client.post(RESET_URL, {"new_password": "secret123", "confirm_password": "secret123"}, format="json") self.assertEqual(response13.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(json.loads(response13.content)["error"][0], "You either have an invalid token or the token has expired.") - \ No newline at end of file diff --git a/authors/apps/core/models.py b/authors/apps/core/models.py new file mode 100644 index 0000000..c3e0dec --- /dev/null +++ b/authors/apps/core/models.py @@ -0,0 +1,10 @@ +from django.db import models + + +class TimeStamp(models.Model): + """Class that sets the timestamp when the an object is created and modified""" + created_at = models.DateTimeField(auto_now_add=True) + modified_at = models.DateTimeField(auto_now=True) + + class Meta: + abstract = True diff --git a/authors/apps/profiles/.DS_Store b/authors/apps/profiles/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..a9eeb2cb8bbc56ac403bdf41759a329e5988ac54 GIT binary patch literal 6148 zcmeH~y>1jS6os#0QI;e?Iw+^0pn(M>3PdxC79k`=gQ#KuLI#HHXm^&dRMYS(k@9>z z0DSk_g82hFK*)DxUypr`eSJJ*uSLWiZszwy4n$-~Qa{)w>oIND)UgYp<{I8vADNW$ zir*b6I_Ovt6^IJ_YYOPMyJz2QCMQz=ez#BaIppj%A@eHCgU@i!}s0m-j??V!KN#I`{c^_@bOX+pNnKxF_;b){MF$AIUpP zw~6Df+~@hNJY?^h%aME_vIn$}XQGuvHRN%V;x<4c&^=a^x_qKJA*%bgkpxTVG{#j5?5_}qbr3 literal 0 HcmV?d00001 diff --git a/authors/apps/profiles/apps.py b/authors/apps/profiles/apps.py new file mode 100644 index 0000000..5501fda --- /dev/null +++ b/authors/apps/profiles/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class ProfilesConfig(AppConfig): + name = 'profiles' diff --git a/authors/apps/profiles/exceptions.py b/authors/apps/profiles/exceptions.py new file mode 100644 index 0000000..bbf12a9 --- /dev/null +++ b/authors/apps/profiles/exceptions.py @@ -0,0 +1,6 @@ +from rest_framework.exceptions import APIException + + +class ProfileDoesNOtExist(APIException): + status_code = 400 + default_detail = 'The requested profile does not exist.' diff --git a/authors/apps/profiles/migrations/0001_initial.py b/authors/apps/profiles/migrations/0001_initial.py new file mode 100644 index 0000000..9a9a463 --- /dev/null +++ b/authors/apps/profiles/migrations/0001_initial.py @@ -0,0 +1,33 @@ +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='Profile', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('surname', models.TextField(blank=True)), + ('last_name', models.TextField(blank=True)), + ('avatar', models.URLField(blank=True)), + ('bio', models.TextField(blank=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('modified_at', models.DateTimeField(auto_now=True)), + ('followers', models.IntegerField(default=0)), + ('following', models.IntegerField(default=0)), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'ordering': ['-created_at', '-modified_at'], + 'abstract': False + }, + ), + ] diff --git a/authors/apps/profiles/migrations/0002_auto_20181104_1033.py b/authors/apps/profiles/migrations/0002_auto_20181104_1033.py new file mode 100644 index 0000000..9f37fac --- /dev/null +++ b/authors/apps/profiles/migrations/0002_auto_20181104_1033.py @@ -0,0 +1,17 @@ +# Generated by Django 2.1.2 on 2018-11-04 10:33 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('profiles', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='profile', + options={}, + ), + ] diff --git a/authors/apps/profiles/migrations/0003_auto_20181105_0939.py b/authors/apps/profiles/migrations/0003_auto_20181105_0939.py new file mode 100644 index 0000000..1c52663 --- /dev/null +++ b/authors/apps/profiles/migrations/0003_auto_20181105_0939.py @@ -0,0 +1,21 @@ +# Generated by Django 2.1.2 on 2018-11-05 09:39 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('profiles', '0002_auto_20181104_1033'), + ] + + operations = [ + migrations.RemoveField( + model_name='profile', + name='followers', + ), + migrations.RemoveField( + model_name='profile', + name='following', + ), + ] diff --git a/authors/apps/profiles/migrations/__init__.py b/authors/apps/profiles/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/authors/apps/profiles/models.py b/authors/apps/profiles/models.py new file mode 100644 index 0000000..4388f3e --- /dev/null +++ b/authors/apps/profiles/models.py @@ -0,0 +1,16 @@ +from django.db import models + +from authors.apps.authentication.models import User +from authors.apps.core.models import TimeStamp + + +class Profile(TimeStamp): + """Class description of user profile""" + user = models.OneToOneField(User, on_delete=models.CASCADE) + surname = models.TextField(blank=True) + last_name = models.TextField(blank=True) + avatar = models.URLField(blank=True) + bio = models.TextField(blank=True) + + def __str__(self): + return self.user.username diff --git a/authors/apps/profiles/renderers.py b/authors/apps/profiles/renderers.py new file mode 100644 index 0000000..acc3161 --- /dev/null +++ b/authors/apps/profiles/renderers.py @@ -0,0 +1,25 @@ +import json + +from rest_framework.renderers import JSONRenderer +from rest_framework.utils.serializer_helpers import ReturnList, ReturnDict + + +class ProfileJSONRenderer(JSONRenderer): + + charset = 'utf-8' + + def render(self, data, media_type=None, renderer_context=None): + + if type(data) != ReturnList: + errors = data.get('errors', None) + if errors is not None: + return super().render(data) + + if type(data) != ReturnDict: + return json.dumps({ + 'profile': data + }) + else: + return json.dumps({ + 'profile': data + }) diff --git a/authors/apps/profiles/serializers.py b/authors/apps/profiles/serializers.py new file mode 100644 index 0000000..9f168f9 --- /dev/null +++ b/authors/apps/profiles/serializers.py @@ -0,0 +1,17 @@ +from rest_framework import serializers + +from .models import Profile + + +class ProfileSerializer(serializers.ModelSerializer): + """Serializer for creating a profile""" + username = serializers.CharField(source='user.username') + surname = serializers.CharField(allow_blank=True, required=False, min_length=1, max_length=50) + last_name = serializers.CharField(allow_blank=True, required=False, min_length=1, max_length=50) + avatar = serializers.URLField() + bio = serializers.CharField(allow_blank=True, required=False, min_length=5, max_length=255) + + class Meta: + model = Profile + fields = ['username', 'surname', 'last_name', 'avatar', 'bio', 'created_at', + 'modified_at'] diff --git a/authors/apps/profiles/tests/__init__.py b/authors/apps/profiles/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/authors/apps/profiles/tests/base_test.py b/authors/apps/profiles/tests/base_test.py new file mode 100644 index 0000000..4bde4f5 --- /dev/null +++ b/authors/apps/profiles/tests/base_test.py @@ -0,0 +1,26 @@ +import json + +from rest_framework.test import APIClient +from django.test import TestCase + + +class BaseTest(TestCase): + + def setUp(self): + self.user_data = { + "username": "mathias", + "email": "mathias@gmail.com", + "password": "mathias92" + } + + self.login_data = { + "email": "mathias@gmail.com", + "password": "mathias92" + } + + self.client = APIClient() + + self.register_response = self.client.post("/api/users/", self.user_data, format="json") + self.login_response = self.client.post("/api/users/login/", self.login_data, format="json") + token = json.loads(self.login_response.content)['user']['token'] + self.client.credentials(HTTP_AUTHORIZATION="Bearer " + token) diff --git a/authors/apps/profiles/tests/test_profiles.py b/authors/apps/profiles/tests/test_profiles.py new file mode 100644 index 0000000..b012a9b --- /dev/null +++ b/authors/apps/profiles/tests/test_profiles.py @@ -0,0 +1,30 @@ +from rest_framework import status + +from authors.apps.profiles.tests.base_test import BaseTest + + +class ProfilesTest(BaseTest): + + def test_list_profiles(self): + response = self.client.get('/api/profiles/', format="json") + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_user_view_their_profile(self): + response = self.client.get('/api/profiles/mathias', format="json") + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_retrieve_non_existing_profile(self): + response = self.client.get('/api/profiles/angule', format="json") + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_update_profile(self): + data = { + "username": "mathias", + "surname": "code", + "last_name": "duty", + "avatar": "https://pbs.twimg.com/profile_images/670856248678596608/2yr7o6QQ_400x400.jpg", + "bio": "codeofdutycodeofdutycodeofduty" + } + response = self.client.put('/api/profiles/mathias', data, format="json") + self.assertIn("codeofdutycodeofdutycodeofduty", response.data['bio']) + self.assertEqual(response.status_code, status.HTTP_200_OK) diff --git a/authors/apps/profiles/urls.py b/authors/apps/profiles/urls.py new file mode 100644 index 0000000..d0de783 --- /dev/null +++ b/authors/apps/profiles/urls.py @@ -0,0 +1,10 @@ +from django.urls import path + +from .views import ProfileRetrieveUpdateAPIView, ProfileList + +app_name = 'profiles' + +urlpatterns = [ + path('profiles/', ProfileRetrieveUpdateAPIView.as_view(), name='profile'), + path('profiles/', ProfileList.as_view(), name='profiles'), +] diff --git a/authors/apps/profiles/views.py b/authors/apps/profiles/views.py new file mode 100644 index 0000000..6b6df73 --- /dev/null +++ b/authors/apps/profiles/views.py @@ -0,0 +1,53 @@ +from rest_framework.generics import RetrieveUpdateAPIView, ListAPIView +from rest_framework.permissions import IsAuthenticated + +from rest_framework.response import Response +from rest_framework import status + +from django.shortcuts import get_object_or_404 + +from authors.apps.profiles.renderers import ProfileJSONRenderer +from authors.apps.profiles.serializers import ProfileSerializer +from authors.apps.profiles.models import User, Profile + + +class ProfileRetrieveUpdateAPIView(RetrieveUpdateAPIView): + """ + Users are able to edit their profile information + """ + permission_classes = (IsAuthenticated,) + renderer_classes = (ProfileJSONRenderer,) + serializer_class = ProfileSerializer + + def retrieve(self, request, username, *args, **kwargs): + user = get_object_or_404(User, username=username) + serializer = self.serializer_class(user.profile) + return Response(serializer.data, status=status.HTTP_200_OK) + + def update(self, request, username, *args, **kwargs): + serializer_data = request.data + user = get_object_or_404(User, username=username) + serializer_data = { + 'surname': serializer_data.get('surname', request.user.profile.surname), + 'last_name': serializer_data.get('last_name', request.user.profile.last_name), + 'avatar': serializer_data.get('avatar', request.user.profile.avatar), + 'bio': serializer_data.get('bio', request.user.profile.bio), + } + + serializer = self.serializer_class( + request.user.profile, + data=serializer_data, + partial=True + ) + + serializer.is_valid(raise_exception=True) + serializer.update(request.user.profile, serializer_data) + serializer.save() + return Response(serializer.data, status=status.HTTP_200_OK) + + +class ProfileList(ListAPIView): + """View all created profiles""" + permission_classes = (IsAuthenticated,) + queryset = Profile.objects.all() + serializer_class = ProfileSerializer diff --git a/authors/urls.py b/authors/urls.py index 8596017..089b8c1 100644 --- a/authors/urls.py +++ b/authors/urls.py @@ -25,5 +25,5 @@ path('admin/', admin.site.urls), path('api/', include(('authors.apps.authentication.urls', 'authentication'), namespace='authentication')), - + path('api/', include(('authors.apps.profiles.urls', 'profiles'), namespace='profiles')), ]