diff --git a/new_rest_api/permissions.py b/new_rest_api/permissions.py index 8666c40e1d43a909866a28d8b963387662082398..918eb91ccdd2ae665ce5484207e889fa0c6026af 100644 --- a/new_rest_api/permissions.py +++ b/new_rest_api/permissions.py @@ -4,11 +4,13 @@ class UserViewPermission(permissions.BasePermission): def has_permission(self, request, view): if view.action in ['register', 'retrieve', 'activate']: return True - if view.action == 'update': + if view.action in ['update', 'authorize']: return request.user.is_authenticated return False def has_object_permission(self, request, view, obj): + if view.action == 'retrieve': + return True if view.action == 'update': return request.user.id == obj.user.id - return True + return False diff --git a/new_rest_api/test_permissions.py b/new_rest_api/test_permissions.py index 6569caa6ef48eff33727a27b565cf4c5417566d7..e726f9c8b94b4cfd81cd3d479eb39f7753f12246 100644 --- a/new_rest_api/test_permissions.py +++ b/new_rest_api/test_permissions.py @@ -38,6 +38,7 @@ class TestPermission(TestCase): self.view_retrieve = MockView('retrieve') self.view_update = MockView('update') self.view_delete = MockView('delete') + self.view_authorize = MockView('authorize') # has permission tests def test_permission_authenticated_cant_list(self): @@ -80,6 +81,16 @@ class TestPermission(TestCase): .has_permission(self.not_authenticated_request, self.view_delete) self.assertFalse(ret) + def test_permission_authenticated_can_authorize(self): + ret = self.user_view_permission\ + .has_permission(self.authenticated_request, self.view_authorize) + self.assertTrue(ret) + + def test_permission_authenticated_cant_authorize(self): + ret = self.user_view_permission\ + .has_permission(self.not_authenticated_request, self.view_authorize) + self.assertFalse(ret) + # has object permission tests def test_object_permission_can_update_same_user(self): user = MockUser(id=self.authenticated_request.user.id) @@ -95,9 +106,23 @@ class TestPermission(TestCase): .has_object_permission(self.authenticated_request, self.view_update, obj) self.assertFalse(ret) - def test_object_permission_other_action(self): + def test_object_permission_can_retrieve_same_user(self): + user = MockUser(id=self.authenticated_request.user.id) + obj = MockObject(user) + ret = self.user_view_permission\ + .has_object_permission(self.authenticated_request, self.view_retrieve, obj) + self.assertTrue(ret) + + def test_object_permission_can_retrieve_difference_user(self): user = MockUser(id=self.authenticated_request.user.id + 1) obj = MockObject(user) ret = self.user_view_permission\ - .has_object_permission(self.authenticated_request, self.view_list, obj) + .has_object_permission(self.authenticated_request, self.view_retrieve, obj) self.assertTrue(ret) + + def test_object_permission_other_action_forbidden(self): + user = MockUser(id=self.authenticated_request.user.id + 1) + obj = MockObject(user) + ret = self.user_view_permission\ + .has_object_permission(self.authenticated_request, self.view_list, obj) + self.assertFalse(ret) diff --git a/new_rest_api/test_views.py b/new_rest_api/test_views.py index e2c06a121b2e79c809ec1806fa4583f68f55a246..68615a21bbc2004911e4cc72c9912a60e354964d 100644 --- a/new_rest_api/test_views.py +++ b/new_rest_api/test_views.py @@ -6,7 +6,7 @@ from django.core.files.uploadedfile import SimpleUploadedFile from django.urls import reverse from django.test import TestCase -from pplbackend.utils import response_decode +from pplbackend.utils import response_decode, get_client_login_with_user class TestUserViews(TestCase): @@ -33,6 +33,8 @@ class TestUserViews(TestCase): 'foto': self.image, } + self.authorize_url = reverse('user-authorize') + @patch('registrasi.serializers.send_activation_email') def test_register_and_send_activation_email_is_called_and_user_inactive(self, mock_ativation_email): @@ -67,6 +69,18 @@ class TestUserViews(TestCase): self.assertEqual(data, expected) self.assertEqual(resp.status_code, status.BAD_REQUEST) + def test_authorize_authenticated(self): + client = get_client_login_with_user(self.user) + resp = client.get(self.authorize_url) + self.assertEqual(resp.status_code, 200) + self.assertEqual(resp.content, b'') + + def test_authorize_not_authenticated(self): + resp = self.client.get(self.authorize_url) + self.assertEqual(resp.status_code, 401) + self.assertEqual(resp.content, + b'{"detail":"Authentication credentials were not provided."}') + @patch('new_rest_api.views.account_activation_token.check_token', return_value=True) @patch('new_rest_api.views.force_text') @patch('new_rest_api.views.urlsafe_base64_decode', return_value='someb64') @@ -88,7 +102,8 @@ class TestUserViews(TestCase): resp = self.client.get(activation_url) data = response_decode(resp) - expected = f''' + expected = f'''Aktivasi pengguna bisaGo + Hai {user.last_name},

@@ -127,7 +142,8 @@ bisaGo dev Team resp = self.client.get(activation_url) data = response_decode(resp) - expected = ''' + expected = '''Aktivasi pengguna bisaGo + Terjadi kesalahan atau akun sudah teraktivasi, mohon hubungi tim pengembang bisaGo. ''' @@ -158,7 +174,8 @@ Terjadi kesalahan atau akun sudah teraktivasi, mohon hubungi tim pengembang bisa resp = self.client.get(activation_url) data = response_decode(resp) - expected = ''' + expected = '''Aktivasi pengguna bisaGo + Terjadi kesalahan atau akun sudah teraktivasi, mohon hubungi tim pengembang bisaGo. ''' diff --git a/new_rest_api/views.py b/new_rest_api/views.py index f275220d28692e2f578d3c120f0ea645781ff387..b457fdee4d3c2351a354b564d6946ce9e5bfda3f 100644 --- a/new_rest_api/views.py +++ b/new_rest_api/views.py @@ -5,8 +5,10 @@ from django.utils.encoding import force_text from django.utils.http import urlsafe_base64_decode from rest_framework import viewsets +from rest_framework.authtoken.models import Token from rest_framework.authentication import TokenAuthentication from rest_framework.decorators import action +from rest_framework.exceptions import NotAuthenticated from rest_framework.response import Response from registrasi.models import BisaGoUser @@ -38,11 +40,15 @@ class UserViewSet(viewsets.ModelViewSet): 'email':instance.email, 'name':instance.last_name}, status=status.CREATED) - @action(detail=False, methods=['GET'], url_path=ACTIVATION_URL_REGEX, + @action(detail=False, url_path=ACTIVATION_URL_REGEX, renderer_classes=[AccountActivationHTMLRenderer]) - def activate(self, request, uidb64, token): + def activate(self, _, uidb64, token): return activate(uidb64, token) + @action(detail=False) + def authorize(self, _): + return Response() + def activate(uidb64, token): try: diff --git a/oauth/tests.py b/oauth/tests.py index 18fa16625621b61c8c41a0c0d640a9a23381bedb..931de91789bb8e4e157f6e8f9ba5839630d96336 100644 --- a/oauth/tests.py +++ b/oauth/tests.py @@ -1,12 +1,15 @@ -from django.test import TestCase import json -from .views import validate_google_token, _create_random_phone_number, _create_google_user + from unittest.mock import patch +from django.test import TestCase from django.test import Client -from registrasi.models import BisaGoUser from django.contrib.auth.models import User from rest_framework.exceptions import AuthenticationFailed +from pplbackend.utils import response_decode +from registrasi.models import BisaGoUser +from .views import validate_google_token, _create_random_phone_number, _create_google_user + class TestOauth(TestCase): def setUp(self): @@ -41,9 +44,10 @@ class TestOauth(TestCase): "access_token": "sankdsanlk", 'password': passcode }) - json_response = json.loads(response.content) + json_response = response_decode(response) + user = json_response.get('user') self.assertEqual(200, response.status_code) - self.assertEqual('mock_user@email.com', json_response.get("username")) + self.assertEqual('mock_user@email.com', user.get("username")) def test_request_token_email_not_exists(self): email = 'mock_user1212@email.com' @@ -96,9 +100,10 @@ class TestOauth(TestCase): 'password': passcode, 'google': True, }) - json_response = json.loads(response.content) + json_response = response_decode(response) + user = json_response.get('user') self.assertEqual(200, response.status_code) - self.assertEqual('mock_user@email.com', json_response.get("username")) + self.assertEqual('mock_user@email.com', user.get("username")) @patch('oauth.views.json.loads') @@ -113,9 +118,10 @@ class TestOauth(TestCase): 'password': passcode, 'google': True, }) - json_response = json.loads(response.content) + json_response = response_decode(response) + user = json_response.get('user') self.assertEqual(200, response.status_code) - self.assertEqual('mock_user4545@email.com', json_response.get("username")) + self.assertEqual('mock_user4545@email.com', user.get("username")) @patch('oauth.views.json.loads') def test_google_login_error(self, mock_json_loads): @@ -175,4 +181,4 @@ class TestOauth(TestCase): self.assertEqual('mock_user3434@email.com', user.username) self.assertEqual('mock_user3434@email.com', user.email) self.assertEqual('name', user.last_name) - self.assertEqual('1x1x1x1x1x1x1x1', user.phone_number.phone_number) + self.assertEqual('1x1x1x1x1x1x1x1', user.bisagouser.phone_number) diff --git a/oauth/views.py b/oauth/views.py index 43e1267617e9b7821b05f977cb54d29a70829398..e9e943f632eb86dfe511382cfc9bac2518c15252 100644 --- a/oauth/views.py +++ b/oauth/views.py @@ -11,7 +11,9 @@ from django.contrib.auth.base_user import BaseUserManager from django.contrib.auth.hashers import make_password from django.contrib.auth.models import User from django.conf import settings + from registrasi.models import BisaGoUser +from registrasi.serializers import BisaGoUserSerializer @csrf_exempt @api_view(http_method_names=['POST']) @@ -28,7 +30,7 @@ def request_token(request): result = _check_normal_auth(request, email, password) user = result - return _check_user(user) + return _check_user(user, request) def _google_check(access_token, name): try: @@ -51,10 +53,12 @@ def _check_normal_auth(request, email, password): raise NotFound(detail="User doesn't exist") return user -def _check_user(user): +def _check_user(user, request): if user.is_active: - token, create = Token.objects.get_or_create(user=user) - response = {'username': user.username, 'token': token.key, 'token_type': "token"} + token, _ = Token.objects.get_or_create(user=user) + request.user = user + serializer = BisaGoUserSerializer(user.bisagouser, context={'request':request}) + response = {'user':serializer.data, 'token': token.key, 'token_type': "token"} return JsonResponse(response, status=200) else: raise AuthenticationFailed(detail="Please activate your account") diff --git a/registrasi/migrations/0013_auto_20210601_0748.py b/registrasi/migrations/0013_auto_20210601_0748.py new file mode 100644 index 0000000000000000000000000000000000000000..391e57df575814fb9f68fc5638e286de07e634c9 --- /dev/null +++ b/registrasi/migrations/0013_auto_20210601_0748.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.7 on 2021-06-01 07:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('registrasi', '0012_auto_20210528_1519'), + ] + + operations = [ + migrations.AlterField( + model_name='bisagouser', + name='organisasi_komunitas', + field=models.CharField(blank=True, default='-', max_length=64, null=True, verbose_name='Organisasi / Komunitas'), + ), + ] diff --git a/registrasi/migrations/0014_auto_20210601_0849.py b/registrasi/migrations/0014_auto_20210601_0849.py new file mode 100644 index 0000000000000000000000000000000000000000..4413c5d277981ce9bbd87a0e2ea5591b8373241c --- /dev/null +++ b/registrasi/migrations/0014_auto_20210601_0849.py @@ -0,0 +1,28 @@ +# Generated by Django 3.1.7 on 2021-06-01 08:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('registrasi', '0013_auto_20210601_0748'), + ] + + operations = [ + migrations.AlterField( + model_name='bisagouser', + name='alamat', + field=models.CharField(blank=True, default='-', max_length=255, null=True, verbose_name='Alamat'), + ), + migrations.AlterField( + model_name='bisagouser', + name='disabilitas', + field=models.CharField(blank=True, default='Belum memilih', max_length=64, null=True, verbose_name='Disabilitas'), + ), + migrations.AlterField( + model_name='bisagouser', + name='pekerjaan', + field=models.CharField(blank=True, default='-', max_length=64, null=True, verbose_name='Pekerjaan'), + ), + ] diff --git a/registrasi/migrations/0015_auto_20210601_1755.py b/registrasi/migrations/0015_auto_20210601_1755.py new file mode 100644 index 0000000000000000000000000000000000000000..45b788bffd1d43ad9a6013eec4c47ad6f220fe95 --- /dev/null +++ b/registrasi/migrations/0015_auto_20210601_1755.py @@ -0,0 +1,21 @@ +# Generated by Django 3.1.7 on 2021-06-01 17:55 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('registrasi', '0014_auto_20210601_0849'), + ] + + operations = [ + migrations.AlterField( + model_name='bisagouser', + name='user', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='bisagouser', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/registrasi/models.py b/registrasi/models.py index 1be6d6e13bbc881520abe1dbeb97afcaa6b056ad..9867d9cdd0cec8a7f5f9bba64be787c02948f0b3 100644 --- a/registrasi/models.py +++ b/registrasi/models.py @@ -7,15 +7,15 @@ from pplbackend.custom_model_field import CompressedImageField class BisaGoUser(models.Model): - user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="phone_number") + user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="bisagouser") phone_number = models.CharField('Nomor Telepon', max_length=15, unique=True) tanggal_lahir = models.DateField('Tanggal Lahir', max_length=15, null=False, default=date.today) jenis_kelamin = models.CharField('Jenis Kelamin', max_length=20, default='-') - disabilitas = models.CharField('Disabilitas', max_length=64, null=True, default='Belum memilih') - organisasi_komunitas = models.CharField('Organisasi / Komunitas', max_length=64, null=True, default='-') - pekerjaan = models.CharField('Pekerjaan', max_length=64, default='-') - alamat = models.CharField('Alamat', max_length=255, default='-') - foto = CompressedImageField('Foto', upload_to='user/', blank=True, default=None, null=True, quality=55) + disabilitas = models.CharField('Disabilitas', max_length=64, null=True, blank=True, default='Belum memilih') + organisasi_komunitas = models.CharField('Organisasi / Komunitas', max_length=64, blank=True, null=True, default='-') + pekerjaan = models.CharField('Pekerjaan', max_length=64, blank=True, null=True, default='-') + alamat = models.CharField('Alamat', max_length=255, blank=True, null=True, default='-') + foto = CompressedImageField('Foto', upload_to='user/', blank=True, null=True, default=None, quality=55) seen = models.BooleanField('Seen', blank=True, default=True) class Meta: diff --git a/registrasi/serializers.py b/registrasi/serializers.py index 7fb0c5139a514a8b8ffb081fa9d5d2cb7980c926..73bb95ed97fe20943f260cfaf157d440f9e105e0 100644 --- a/registrasi/serializers.py +++ b/registrasi/serializers.py @@ -11,6 +11,8 @@ class BisaGoUserSerializer(serializers.ModelSerializer): username = serializers.CharField(source='user.username', read_only=True) name = serializers.CharField(source='user.last_name') email = serializers.CharField(source='user.email', read_only=True) + tanggal_lahir = serializers.DateField(format='%d %B %Y', + input_formats=['%d %B %Y', '%Y-%m-%d']) hidden_fields = serializers.SerializerMethodField() @@ -27,7 +29,7 @@ class BisaGoUserSerializer(serializers.ModelSerializer): 'phone_number': 'nomor telepon', 'tanggal_lahir': 'tanggal lahir', } - hidden_replacement_char = '-' + hidden_replacement_char = '({} dirahasiakan)' update_bisago_fields = ( 'phone_number', 'seen', 'alamat', 'jenis_kelamin', 'tanggal_lahir', @@ -45,8 +47,7 @@ class BisaGoUserSerializer(serializers.ModelSerializer): def get_hidden_fields(self, *args): hidden_fields = self.Meta.hidden_fields verbose = self.Meta.hidden_fields_verbose - return [verbose.get(field) if verbose.get(field) else field\ - for field in hidden_fields] + return [verbose.get(field) or field for field in hidden_fields] def can_see_hidden_fields(self, instance): request = self.context['request'] @@ -56,7 +57,10 @@ class BisaGoUserSerializer(serializers.ModelSerializer): representation = super().to_representation(instance) if not self.can_see_hidden_fields(instance): for hidden_field in self.Meta.hidden_fields: - representation[hidden_field] = self.Meta.hidden_replacement_char + verbose_name = self.Meta.hidden_fields_verbose.get(hidden_field)\ + or hidden_field + representation[hidden_field] = self.Meta.hidden_replacement_char\ + .format(verbose_name) return representation def to_internal_value(self, data): diff --git a/registrasi/test_serializers.py b/registrasi/test_serializers.py index a68224c9b3d08ce29909ea766e3d07e12330276b..5fa19170bcd01675ef0149a7a8bc214d777dd22f 100644 --- a/registrasi/test_serializers.py +++ b/registrasi/test_serializers.py @@ -75,7 +75,8 @@ class TestBisaGoUserSerializer(BaseTestSerializer): {'phone_number': 'nomor telepon', 'tanggal_lahir': 'tanggal lahir'}) def test_meta_hidden_replacement_char(self): - self.assertEqual(BisaGoUserSerializer.Meta.hidden_replacement_char, '-') + self.assertEqual(BisaGoUserSerializer.Meta.hidden_replacement_char, + '({} dirahasiakan)') def test_meta_update_bisago_fields(self): self.assertEqual(BisaGoUserSerializer.Meta.update_bisago_fields, ( @@ -145,11 +146,11 @@ class TestBisaGoUserSerializer(BaseTestSerializer): replaced = BisaGoUserSerializer.Meta.hidden_replacement_char expected = { - 'phone_number': replaced, 'tanggal_lahir': replaced, + 'phone_number': '(nomor telepon dirahasiakan)', 'tanggal_lahir': '(tanggal lahir dirahasiakan)', 'jenis_kelamin': '-', 'disabilitas': 'Belum memilih', 'pekerjaan': '-', 'alamat': '-', 'foto': None, 'seen': False, 'username': 'dummy username', 'name': 'dummy lastname', - 'email': replaced, 'alamat': replaced, + 'email': '(email dirahasiakan)', 'alamat': '(alamat dirahasiakan)', 'organisasi_komunitas': '-', 'hidden_fields': self.hidden_fields, } @@ -175,7 +176,7 @@ class TestBisaGoUserSerializer(BaseTestSerializer): serializer.save() expected = { - 'phone_number': '99999999', 'tanggal_lahir': '2000-10-02', + 'phone_number': '99999999', 'tanggal_lahir': '02 October 2000', 'jenis_kelamin': 'laki-laki', 'disabilitas': 'tanpa batas', 'pekerjaan': 'makan', 'alamat': 'dif dummy st', 'seen': False, 'username': 'dummy username', 'name': 'another dummy name', @@ -208,7 +209,7 @@ class TestBisaGoUserSerializer(BaseTestSerializer): serializer.save() expected = { - 'phone_number': '99999999', 'tanggal_lahir': '2000-10-02', + 'phone_number': '99999999', 'tanggal_lahir': '02 October 2000', 'jenis_kelamin': 'laki-laki', 'disabilitas': 'tanpa batas', 'pekerjaan': 'makan', 'alamat': 'dif dummy st', 'seen': False, 'username': 'dummy username', 'name': 'another dummy name', diff --git a/templates/acc_activate_success.html b/templates/acc_activate_success.html index 8f61337c77998544806afed82dee6b0443da9a69..8ecf1760685dfd120a0d723465aee0b396852939 100644 --- a/templates/acc_activate_success.html +++ b/templates/acc_activate_success.html @@ -1,3 +1,4 @@ +Aktivasi pengguna bisaGo {% if success %} Hai {{ user.last_name }},