From 91d22c82b05f82a218a1a291a8c6b269931c74aa Mon Sep 17 00:00:00 2001 From: Bimo Iman Smartadi Date: Fri, 24 Apr 2020 01:43:05 +0700 Subject: [PATCH 1/8] Bulk edit. not tested --- informasi_fasilitas/models.py | 14 ++++++- informasi_fasilitas/tests.py | 2 +- informasi_fasilitas/urls.py | 2 + informasi_fasilitas/views.py | 75 ++++++++++++++++++++++++++++++++++- 4 files changed, 89 insertions(+), 4 deletions(-) diff --git a/informasi_fasilitas/models.py b/informasi_fasilitas/models.py index e098910..fc5d573 100644 --- a/informasi_fasilitas/models.py +++ b/informasi_fasilitas/models.py @@ -54,7 +54,7 @@ class Fasilitas(models.Model): deskripsi = models.TextField() like = models.IntegerField(default=0) dislike = models.IntegerField(default=0) - rating = models.IntegerField(default=3) + rating = models.IntegerField(default=3) tag = MultiSelectField(choices=FACILITIES, null=True, default=None) image = models.ImageField(upload_to="static/img", null=True, default=None) is_verified = models.BooleanField(default=False) @@ -63,4 +63,14 @@ class Komentar(models.Model): fasilitas =models.ForeignKey(Fasilitas, on_delete=models.CASCADE) user = models.ForeignKey(User, on_delete=models.CASCADE) date_time = models.DateTimeField(auto_now_add=True) - deskripsi = models.TextField() \ No newline at end of file + deskripsi = models.TextField() + +class Like(models.Model): + user = models.ForeignKey(User) + fasilitas = models.ForeignKey(Fasilitas) + created = models.DateTimeField(auto_now_add=True) + +class Dislike(models.Model): + user = models.ForeignKey(User) + fasilitas = models.ForeignKey(Fasilitas) + created = models.DateTimeField(auto_now_add=True) diff --git a/informasi_fasilitas/tests.py b/informasi_fasilitas/tests.py index 85855ba..10c7f5d 100644 --- a/informasi_fasilitas/tests.py +++ b/informasi_fasilitas/tests.py @@ -73,7 +73,7 @@ class InformasiFasilitasModelTest(TestCase): def test_models_komentar_not_created(self): with self.assertRaises(IntegrityError) as cm: obj = Komentar(fasilitas=None) - obj.save(); + obj.save() self.assertTrue(str(cm.exception).startswith( self.not_null_constraint_failed_message)) diff --git a/informasi_fasilitas/urls.py b/informasi_fasilitas/urls.py index 5439a2d..cfbd1c9 100644 --- a/informasi_fasilitas/urls.py +++ b/informasi_fasilitas/urls.py @@ -9,4 +9,6 @@ urlpatterns = [ path('lokasi/add-fasilitas//', views.add_fasilitas, name='add-fasilitas'), path('lokasi/list-fasilitas//', views.list_fasilitas, name='list-fasilitas'), path('lokasi/detail-fasilitas///', views.detail_fasilitas, name='detail-fasilitas'), + path('lokasi/update-fasilitas///', views.update_fasilitas, name='update-fasilitas'), + path('lokasi/like-fasilitas////', views.update_like_fasilitas, name='update-like-fasilitas'), ] \ No newline at end of file diff --git a/informasi_fasilitas/views.py b/informasi_fasilitas/views.py index 55b47f2..557e6c5 100644 --- a/informasi_fasilitas/views.py +++ b/informasi_fasilitas/views.py @@ -9,7 +9,7 @@ from rest_framework.authentication import TokenAuthentication from rest_framework.permissions import IsAuthenticated from .serializers import LokasiSerializer -from .models import Lokasi, Fasilitas, Komentar +from .models import Lokasi, Fasilitas, Komentar, Like, Dislike def request_error_message(request_kind): return "get {} request instead".format(request_kind) @@ -130,6 +130,8 @@ def detail_fasilitas(request, nama_lokasi, id): lokasi = Lokasi.objects.get(name = nama_lokasi) fasilitas = Fasilitas.objects.get(lokasi=lokasi, id=id) user = fasilitas.user + fasilitas.like = Like.objects.filter(fasilitas = fasilitas).count() + fasilitas.dislike = Dislike.objects.filter(fasilitas = fasilitas).count() return_json = {"nama_lokasi": lokasi.name, "deskripsi":fasilitas.deskripsi, "creator":user.last_name, "date_time":fasilitas.date_time, "like":fasilitas.like, "dislike":fasilitas.dislike, "rating":fasilitas.rating, "tag":fasilitas.tag, "image":str(fasilitas.image), "is_verified":fasilitas.is_verified} return JsonResponse(return_json, status = 200) @@ -137,5 +139,76 @@ def detail_fasilitas(request, nama_lokasi, id): return JsonResponse({'response' : request_error_message("get")}, status = 400) except KeyError as e: return JsonResponse({'response': missing_key_message(str(e))}, status = 500) + except Exception as e: + return JsonResponse({'response': str(e)}, status = 404) + +@api_view(['PUT']) +@authentication_classes([TokenAuthentication]) +@permission_classes([IsAuthenticated]) +def update_fasilitas(request, nama_lokasi, id): + try: + if request.method == "PUT": + lokasi = Lokasi.objects.get(name = nama_lokasi) + fasilitas = Fasilitas.objects.get(lokasi=lokasi, id=id) + user_creator = fasilitas.user + image = fasilitas.image + desc = fasilitas.deskripsi + tag = fasilitas.tag + if user_creator == request.user: + if 'image' in request.PUT.keys(): + image = str(request.PUT['image']) + if 'deskripsi' in request.PUT.keys(): + desc = request.PUT['deskripsi'] + if 'tag' in request.PUT.keys(): + tag = request.PUT['tag'] + fasilitas.image = image + fasilitas.deskripsi = desc + fasilitas.tag = tag + fasilitas.save() + return JsonResponse({'response' : '{} in fasilitas edited'.format(str(request.PUT.keys())), }, status = 200) + return JsonResponse({'response' : 'Authentication failed'}, status = 502) + except KeyError as e: + return JsonResponse({'response': missing_key_message(str(e))}, status = 500) + except Exception as e: + return JsonResponse({'response': str(e)}, status = 404) + +@api_view(['PUT']) +@authentication_classes([TokenAuthentication]) +@permission_classes([IsAuthenticated]) +def update_like_fasilitas(request, nama_lokasi, id, operation): + try: + if request.method == "PUT": + lokasi = Lokasi.objects.get(name = nama_lokasi) + fasilitas = Fasilitas.objects.get(lokasi=lokasi, id=id) + user = request.user + + try: + like = Like.objects.get(fasilitas=fasilitas, user = user) + except Like.DoesNotExist: + like = None + try: + dislike = Dislike.objects.get(fasilitas=fasilitas, user = user) + except Dislike.DoesNotExist: + dislike = None + + if operation == "like": + if like != None: + return JsonResponse({'response': "you've already liked this facility"}) + else: + Like.objects.create(fasilitas = fasilitas, user = user) + if dislike != None: + dislike.delete() + elif operation == "dislike": + if dislike != None: + return JsonResponse({'response': "you've already disliked this facility"}) + else: + Dislike.objects.create(fasilitas = fasilitas, user = user) + if like != None: + like.delete() + fasilitas.like = Like.objects.filter(fasilitas = fasilitas).count() + fasilitas.dislike = Dislike.objects.filter(fasilitas = fasilitas).count() + return JsonResponse({'response': "you've successfuly {}d this facility".format(operation)}, status = 200) + except KeyError as e: + return JsonResponse({'response': missing_key_message(str(e))}, status = 500) except Exception as e: return JsonResponse({'response': str(e)}, status = 404) \ No newline at end of file -- GitLab From f9586ee6cba8d1a5093efc30ffcf8335eceb0a80 Mon Sep 17 00:00:00 2001 From: Bimo Iman Smartadi Date: Fri, 24 Apr 2020 02:20:27 +0700 Subject: [PATCH 2/8] Bulk add. not tested. dirty --- README.md | 14 +++++ .../migrations/0002_dislikes_likes.py | 34 +++++++++++ informasi_fasilitas/models.py | 12 ++-- informasi_fasilitas/urls.py | 1 + informasi_fasilitas/views.py | 57 ++++++++++++------- 5 files changed, 91 insertions(+), 27 deletions(-) create mode 100644 informasi_fasilitas/migrations/0002_dislikes_likes.py diff --git a/README.md b/README.md index c5023c2..76e65f0 100644 --- a/README.md +++ b/README.md @@ -150,4 +150,18 @@ It will return a json with the following key: * `image`: Image for facility * `is_verified`: Verified status +### 10. To update a facility details: +Make `GET` request to API endpoint `/informasi-lokasi/lokasi/detail-fasilitas/*nama-lokasi*/*id-fasilitas*/`.
+It will return a json with the following key: +* `nama_lokasi`: location name of the facility +* `deskripsi`: the description +* `creator`: User's last name who registered the facility +* `date_time`: Date when the facility was made +* `like`: how many people like this facility. default is 0 +* `dislike`: how many people dislike this facility. default is 0 +* `rating`: rating of the facility. Default is 3 +* `tag`: Facility tag +* `image`: Image for facility +* `is_verified`: Verified status + diff --git a/informasi_fasilitas/migrations/0002_dislikes_likes.py b/informasi_fasilitas/migrations/0002_dislikes_likes.py new file mode 100644 index 0000000..d1be358 --- /dev/null +++ b/informasi_fasilitas/migrations/0002_dislikes_likes.py @@ -0,0 +1,34 @@ +# Generated by Django 2.1.5 on 2020-04-23 18:50 + +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), + ('informasi_fasilitas', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Dislikes', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(auto_now_add=True)), + ('fasilitas', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='informasi_fasilitas.Fasilitas')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='Likes', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(auto_now_add=True)), + ('fasilitas', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='informasi_fasilitas.Fasilitas')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/informasi_fasilitas/models.py b/informasi_fasilitas/models.py index fc5d573..6bf4783 100644 --- a/informasi_fasilitas/models.py +++ b/informasi_fasilitas/models.py @@ -65,12 +65,12 @@ class Komentar(models.Model): date_time = models.DateTimeField(auto_now_add=True) deskripsi = models.TextField() -class Like(models.Model): - user = models.ForeignKey(User) - fasilitas = models.ForeignKey(Fasilitas) +class Likes(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + fasilitas = models.ForeignKey(Fasilitas, on_delete=models.CASCADE) created = models.DateTimeField(auto_now_add=True) -class Dislike(models.Model): - user = models.ForeignKey(User) - fasilitas = models.ForeignKey(Fasilitas) +class Dislikes(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + fasilitas = models.ForeignKey(Fasilitas, on_delete=models.CASCADE) created = models.DateTimeField(auto_now_add=True) diff --git a/informasi_fasilitas/urls.py b/informasi_fasilitas/urls.py index cfbd1c9..64bf994 100644 --- a/informasi_fasilitas/urls.py +++ b/informasi_fasilitas/urls.py @@ -5,6 +5,7 @@ from . import views urlpatterns = [ path('lokasi/list/', views.lokasi_list,name='lokasi-list'), path('lokasi/detail//', views.lokasi_details,name='lokasi-details'), + path('lokasi/update-detail//', views.lokasi_details,name='update-lokasi'), path('lokasi/add/', views.add_lokasi,name='add-lokasi'), path('lokasi/add-fasilitas//', views.add_fasilitas, name='add-fasilitas'), path('lokasi/list-fasilitas//', views.list_fasilitas, name='list-fasilitas'), diff --git a/informasi_fasilitas/views.py b/informasi_fasilitas/views.py index 557e6c5..70f5a68 100644 --- a/informasi_fasilitas/views.py +++ b/informasi_fasilitas/views.py @@ -9,7 +9,7 @@ from rest_framework.authentication import TokenAuthentication from rest_framework.permissions import IsAuthenticated from .serializers import LokasiSerializer -from .models import Lokasi, Fasilitas, Komentar, Like, Dislike +from .models import Lokasi, Fasilitas, Komentar, Likes, Dislikes def request_error_message(request_kind): return "get {} request instead".format(request_kind) @@ -64,6 +64,23 @@ def add_lokasi(request): except KeyError as e: return JsonResponse({'response': missing_key_message(str(e))}, status = 500) +@api_view(['POST']) +@authentication_classes([TokenAuthentication]) +@permission_classes([IsAuthenticated]) +def update_lokasi_details(request, name): + try: + if request.method == 'PUT': + lokasi = Lokasi.objects.get(name = name) + if 'no_telp' in request.data.keys(): + lokasi.no_telp = request.data['no_telp'] + lokasi.save() + return JsonResponse({'response' : "phone changed to {}".format(lokasi.no_telp)}, status = 201) + else: + return JsonResponse({'response' : request_error_message("post")}, status = 400) + except KeyError as e: + return JsonResponse({'response': missing_key_message(str(e))}, status = 500) + + @api_view(['GET']) @authentication_classes([]) @permission_classes([]) @@ -130,8 +147,8 @@ def detail_fasilitas(request, nama_lokasi, id): lokasi = Lokasi.objects.get(name = nama_lokasi) fasilitas = Fasilitas.objects.get(lokasi=lokasi, id=id) user = fasilitas.user - fasilitas.like = Like.objects.filter(fasilitas = fasilitas).count() - fasilitas.dislike = Dislike.objects.filter(fasilitas = fasilitas).count() + fasilitas.like = Likes.objects.filter(fasilitas = fasilitas).count() + fasilitas.dislike = Dislikes.objects.filter(fasilitas = fasilitas).count() return_json = {"nama_lokasi": lokasi.name, "deskripsi":fasilitas.deskripsi, "creator":user.last_name, "date_time":fasilitas.date_time, "like":fasilitas.like, "dislike":fasilitas.dislike, "rating":fasilitas.rating, "tag":fasilitas.tag, "image":str(fasilitas.image), "is_verified":fasilitas.is_verified} return JsonResponse(return_json, status = 200) @@ -151,21 +168,18 @@ def update_fasilitas(request, nama_lokasi, id): lokasi = Lokasi.objects.get(name = nama_lokasi) fasilitas = Fasilitas.objects.get(lokasi=lokasi, id=id) user_creator = fasilitas.user - image = fasilitas.image desc = fasilitas.deskripsi tag = fasilitas.tag + print(request.data) if user_creator == request.user: - if 'image' in request.PUT.keys(): - image = str(request.PUT['image']) - if 'deskripsi' in request.PUT.keys(): - desc = request.PUT['deskripsi'] - if 'tag' in request.PUT.keys(): - tag = request.PUT['tag'] - fasilitas.image = image + if 'deskripsi' in request.data.keys(): + desc = request.data['deskripsi'] + if 'tag' in request.data.keys(): + tag = request.data['tag'].split() fasilitas.deskripsi = desc fasilitas.tag = tag fasilitas.save() - return JsonResponse({'response' : '{} in fasilitas edited'.format(str(request.PUT.keys())), }, status = 200) + return JsonResponse({'response' : '{} in fasilitas edited'.format(str(request.data.keys())), }, status = 201) return JsonResponse({'response' : 'Authentication failed'}, status = 502) except KeyError as e: return JsonResponse({'response': missing_key_message(str(e))}, status = 500) @@ -183,31 +197,32 @@ def update_like_fasilitas(request, nama_lokasi, id, operation): user = request.user try: - like = Like.objects.get(fasilitas=fasilitas, user = user) - except Like.DoesNotExist: + like = Likes.objects.get(fasilitas=fasilitas, user = user) + except Likes.DoesNotExist: like = None try: - dislike = Dislike.objects.get(fasilitas=fasilitas, user = user) - except Dislike.DoesNotExist: + dislike = Dislikes.objects.get(fasilitas=fasilitas, user = user) + except Dislikes.DoesNotExist: dislike = None if operation == "like": if like != None: return JsonResponse({'response': "you've already liked this facility"}) else: - Like.objects.create(fasilitas = fasilitas, user = user) + Likes.objects.create(fasilitas = fasilitas, user = user) if dislike != None: dislike.delete() elif operation == "dislike": if dislike != None: return JsonResponse({'response': "you've already disliked this facility"}) else: - Dislike.objects.create(fasilitas = fasilitas, user = user) + Dislikes.objects.create(fasilitas = fasilitas, user = user) if like != None: like.delete() - fasilitas.like = Like.objects.filter(fasilitas = fasilitas).count() - fasilitas.dislike = Dislike.objects.filter(fasilitas = fasilitas).count() - return JsonResponse({'response': "you've successfuly {}d this facility".format(operation)}, status = 200) + + fasilitas.like = Likes.objects.filter(fasilitas = fasilitas).count() + fasilitas.dislike = Dislikes.objects.filter(fasilitas = fasilitas).count() + return JsonResponse({'response': "you've successfuly {}d this facility".format(operation)}, status = 201) except KeyError as e: return JsonResponse({'response': missing_key_message(str(e))}, status = 500) except Exception as e: -- GitLab From 143436d24dcfd4960dbae866e58593229a303f12 Mon Sep 17 00:00:00 2001 From: Bimo Iman Smartadi Date: Mon, 27 Apr 2020 17:18:02 +0700 Subject: [PATCH 3/8] [RED] Added new test for update detail and best practice error code --- informasi_fasilitas/tests.py | 397 +++++++++++++++++++++++------------ 1 file changed, 263 insertions(+), 134 deletions(-) diff --git a/informasi_fasilitas/tests.py b/informasi_fasilitas/tests.py index 10c7f5d..ad115f5 100644 --- a/informasi_fasilitas/tests.py +++ b/informasi_fasilitas/tests.py @@ -1,23 +1,36 @@ from django.test import TestCase, Client from django.db.utils import IntegrityError -from .models import Lokasi, Fasilitas, Komentar, KURSI_RODA, RUNNING_TEXT +from .models import Lokasi, Fasilitas, Komentar, KURSI_RODA, RUNNING_TEXT, Likes, Dislikes from .serializers import LokasiSerializer from registrasi.models import BisaGoUser from django.contrib.auth.models import User from django.urls import reverse, path, include +from http import HTTPStatus import json import tempfile -# Create your tests here. +not_null_constraint_failed_message = 'NOT NULL constraint failed' +user_test = User(username='user@gmail.com', + last_name='name', + email='user@gmail.com', + password='hahagotim' + ) +lokasi_test = Lokasi(name='Mall', + latitude=0.0, + longitude=0.0, + alamat='Jl. Raya Bogor no.1, Jakarta', + no_telp='081212123131', + image= tempfile.NamedTemporaryFile(suffix=".jpg").name + ) + class InformasiFasilitasModelTest(TestCase): - not_null_constraint_failed_message = 'NOT NULL constraint failed' def test_models_lokasi_not_created(self): with self.assertRaises(IntegrityError) as cm: obj = Lokasi(name=None) obj.save() self.assertTrue(str(cm.exception).startswith( - self.not_null_constraint_failed_message)) + not_null_constraint_failed_message)) def test_models_create_new_lokasi(self): image = tempfile.NamedTemporaryFile(suffix=".jpg").name @@ -37,25 +50,13 @@ class InformasiFasilitasModelTest(TestCase): obj = Fasilitas(lokasi=None) obj.save() self.assertTrue(str(cm.exception).startswith( - self.not_null_constraint_failed_message)) + not_null_constraint_failed_message)) def test_models_create_new_fasilitas(self): image = tempfile.NamedTemporaryFile(suffix=".jpg").name - user=User( - username='user@gmail.com', - last_name='name', - email='user@gmail.com', - password='hahagotim' - ) + user=user_test user.save() - lokasi=Lokasi( - name='Mall', - latitude=0.0, - longitude=0.0, - alamat='Jl. Raya Bogor no.1, Jakarta', - no_telp='081212123131', - image=image - ) + lokasi=lokasi_test lokasi.save() Fasilitas.objects.create( lokasi=lokasi, @@ -75,25 +76,13 @@ class InformasiFasilitasModelTest(TestCase): obj = Komentar(fasilitas=None) obj.save() self.assertTrue(str(cm.exception).startswith( - self.not_null_constraint_failed_message)) + not_null_constraint_failed_message)) def test_models_create_new_komentar(self): image = tempfile.NamedTemporaryFile(suffix=".jpg").name - user=User( - username='user', - last_name='name', - email='user@gmail.com', - password='hahagotim' - ) + user=user_test user.save() - lokasi=Lokasi( - name='Mall', - latitude=0.0, - longitude=0.0, - alamat='Jl. Raya Bogor no.1, Jakarta', - no_telp='081212123131', - image=image - ) + lokasi=lokasi_test lokasi.save() fasilitas=Fasilitas( lokasi=lokasi, @@ -113,24 +102,111 @@ class InformasiFasilitasModelTest(TestCase): ) count = Komentar.objects.all().count() self.assertNotEqual(count, 0) + + def test_models_dislikes_not_created(self): + with self.assertRaises(IntegrityError) as cm: + obj = Dislikes(fasilitas=None) + obj.save() + self.assertTrue(str(cm.exception).startswith( + not_null_constraint_failed_message)) + + def test_models_create_new_dislikes(self): + image = tempfile.NamedTemporaryFile(suffix=".jpg").name + user=user_test + user.save() + lokasi=lokasi_test + lokasi.save() + fasilitas=Fasilitas( + lokasi=lokasi, + user=user, + deskripsi="penjelasan panjang", + like=0, + dislike=0, + rating=5, + tag={KURSI_RODA, RUNNING_TEXT}, + image=image + ) + fasilitas.save() + Dislikes.objects.create(user=user, + fasilitas=fasilitas, + ) + count = Dislikes.objects.all().count() + self.assertNotEqual(count, 0) -def test_view_lokasi(self): - image = tempfile.NamedTemporaryFile(suffix=".jpg").name - lokasi=Lokasi( - name='Sekolah', - latitude=0.0, - longitude=0.0, - alamat='Soppeng sentosa', - no_telp='081212123131', - image=image - ) - lokasi.save() + def test_models_likes_not_created(self): + with self.assertRaises(IntegrityError) as cm: + obj = Likes(fasilitas=None) + obj.save() + self.assertTrue(str(cm.exception).startswith( + not_null_constraint_failed_message)) + + def test_models_create_new_likes(self): + image = tempfile.NamedTemporaryFile(suffix=".jpg").name + user=user_test + user.save() + lokasi=lokasi_test + lokasi.save() + fasilitas=Fasilitas( + lokasi=lokasi, + user=user, + deskripsi="penjelasan panjang", + like=0, + dislike=0, + rating=5, + tag={KURSI_RODA, RUNNING_TEXT}, + image=image + ) + fasilitas.save() + Likes.objects.create(user=user, + fasilitas=fasilitas, + ) + count = Likes.objects.all().count() + self.assertNotEqual(count, 0) + class InformasiFasilitasViewTest(TestCase): urlpatterns = [ path('informasi-fasilitas/', include('informasi_fasilitas.urls')), ] + def setUp(self): + email='usersetup@gmail.com' + password='hahagotim' + Client().post('/api/register/', + {'name':'name', + 'email':email, + 'phone_number':1000000, + 'password':password}) + token_response = Client().post('/api-token-auth/', + {'username' : email, 'password' : password}) + content = json.loads(token_response.content.decode('utf-8')) + token = content['token'] + client = Client(HTTP_AUTHORIZATION='token '+token) + + client.post(reverse('add-lokasi'), + {'name' : 'Ma Homie', + 'latitude' : 0.1, + 'longitude' : 0.1, + 'alamat' : 'Jl. Raya Bogor no.2, Jakarta', + 'no_telp' : '081212123132'}) + + client.post(reverse('add-lokasi'), + {'name' : 'Ma Homies', + 'latitude' : 0.2, + 'longitude' : 0.1, + 'alamat' : 'Jl. Raya Bogor no.3, Jakarta', + 'no_telp' : '081212123134'}) + + client.post(reverse('add-fasilitas', kwargs={"nama_lokasi":"Ma Homie"}), + {'deskripsi' : 'kayaknya deskrispi', + 'rating' : 3, + 'tag' : "KR RT", + 'image' : 'gambar.jpg', + }) + + +class LokasiRelatedViewTest(InformasiFasilitasViewTest): + def test_LokasiSerializer_valid(self): serializer = LokasiSerializer(data = { 'name' : 'Mall1', @@ -141,45 +217,61 @@ class InformasiFasilitasViewTest(TestCase): }) self.assertTrue(serializer.is_valid) - def test_can_get_lokasi_list(self): + def test_can_get_lokasi_list_url(self): response = Client().get(reverse('lokasi-list')) - self.assertEqual(response.status_code, 200) + self.assertEqual(response.status_code, HTTPStatus.OK) + + def test_get_lokasi_list_json(self): + response = Client().get(reverse('lokasi-list')) + content = json.loads(response.content.decode('utf-8')) + expected_json = [{'id': 1, + 'name':'Ma Homie', + 'latitude' : 0.1, + 'longitude' : 0.1, + 'alamat' : 'Jl. Raya Bogor no.2, Jakarta', + 'no_telp' : '081212123132', + 'image':None}, + {'id': 2, + 'name':'Ma Homies', + 'latitude' : 0.2, + 'longitude' : 0.1, + 'alamat' : 'Jl. Raya Bogor no.3, Jakarta', + 'no_telp' : '081212123134', + 'image':None} + ] + self.assertEqual(content, expected_json) - def test_cannot_post_lokasi_list(self): + def test_cannot_post_lokasi_list_url(self): response = Client().post(reverse('lokasi-list')) - self.assertEqual(response.status_code, 405) + self.assertEqual(response.status_code, HTTPStatus.METHOD_NOT_ALLOWED) def test_can_get_lokasi_details(self): - image = tempfile.NamedTemporaryFile(suffix=".jpg").name - lokasi=Lokasi( - name='Mall', - latitude=0.0, - longitude=0.0, - alamat='Jl. Raya Bogor no.1, Jakarta', - no_telp='081212123131', - image=image - ) + lokasi=lokasi_test lokasi.save() response = Client().get(reverse('lokasi-details', kwargs={'name':'Mall'})) - self.assertEqual(response.status_code, 200) + self.assertEqual(response.status_code, HTTPStatus.OK) + + def test_can_get_lokasi_details_json(self): + response = Client().get(reverse('lokasi-details', kwargs={'name':'Ma Homie'})) + content = json.loads(response.content.decode('utf-8')) + expected_json = {'id': 1, + 'name':'Ma Homie', + 'latitude' : 0.1, + 'longitude' : 0.1, + 'alamat' : 'Jl. Raya Bogor no.2, Jakarta', + 'no_telp' : '081212123132', + 'image':None} + self.assertEqual(content, expected_json) def test_cannot_post_lokasi_details(self): - image = tempfile.NamedTemporaryFile(suffix=".jpg").name - lokasi=Lokasi( - name='Mall', - latitude=0.0, - longitude=0.0, - alamat='Jl. Raya Bogor no.1, Jakarta', - no_telp='081212123131', - image=image - ) + lokasi=lokasi_test lokasi.save() response = Client().post(reverse('lokasi-details', kwargs={'name':'Mall'})) - self.assertEqual(response.status_code, 405) + self.assertEqual(response.status_code, HTTPStatus.METHOD_NOT_ALLOWED) def test_get_lokasi_details_not_found(self): response = Client().get(reverse('lokasi-details', kwargs={'name':'Mall'})) - self.assertEqual(response.status_code, 404) + self.assertEqual(response.status_code, HTTPStatus.NOT_FOUND) def test_can_post_add_lokasi(self): email='user@gmail.com' @@ -201,7 +293,60 @@ class InformasiFasilitasViewTest(TestCase): 'longitude' : 0.0, 'alamat' : 'Jl. Raya Bogor no.1, Jakarta', 'no_telp' : '081212123131'}) - self.assertEqual(response.status_code, 201) + self.assertEqual(response.status_code, HTTPStatus.CREATED) + + def test_can_post_add_json(self): + email='user@gmail.com' + password='hahagotim' + Client().post('/api/register/', + {'name':'name', + 'email':email, + 'phone_number':000000000, + 'password':password}) + token_response = Client().post('/api-token-auth/', + {'username' : email, 'password' : password}) + content = json.loads(token_response.content.decode('utf-8')) + token = content['token'] + client = Client(HTTP_AUTHORIZATION='token '+token) + + response = client.post(reverse('add-lokasi'), + {'name' : 'Mall', + 'latitude' : 0.0, + 'longitude' : 0.0, + 'alamat' : 'Jl. Raya Bogor no.1, Jakarta', + 'no_telp' : '081212123131'}) + response_json = json.loads(response.content.decode("utf-8")) + + expected_json = {'name' : 'Mall', + 'latitude' : 0.0, + 'longitude' : 0.0, + 'alamat' : 'Jl. Raya Bogor no.1, Jakarta', + 'no_telp' : '081212123131'} + + self.assertEqual(response_json, expected_json) + + def test_put_update_detail_lokasi_success(self): + email='user@gmail.com' + password='hahagotim' + Client().post('/api/register/', + {'name':'name', + 'email':email, + 'phone_number':000000000, + 'password':password}) + token_response = Client().post('/api-token-auth/', + {'username' : email, 'password' : password}) + content = json.loads(token_response.content.decode('utf-8')) + token = content['token'] + client = Client(HTTP_AUTHORIZATION='token '+token) + + lokasi=lokasi_test + lokasi.save() + + response = client.put(reverse('update-lokasi', kwargs={'nama_lokasi':'Mall'}), + data={'no_telp' : '0000000121',}, + content_type="multipart/form-data") + self.assertEqual(response.status_code, HTTPStatus.ACCEPTED) + def test_cannot_get_add_lokasi(self): email='user@gmail.com' @@ -218,25 +363,15 @@ class InformasiFasilitasViewTest(TestCase): client = Client(HTTP_AUTHORIZATION='token '+token) response = client.get(reverse('add-lokasi')) - self.assertEqual(response.status_code, 405) + self.assertEqual(response.status_code, HTTPStatus.METHOD_NOT_ALLOWED) + +class FasilitasRelatedViewTest(InformasiFasilitasViewTest): def test_can_get_list_fasilitas(self): image = tempfile.NamedTemporaryFile(suffix=".jpg").name - user=User( - username='user@gmail.com', - last_name='name', - email='user@gmail.com', - password='hahagotim' - ) + user=user_test user.save() - lokasi=Lokasi( - name='Mall', - latitude=0.0, - longitude=0.0, - alamat='Jl. Raya Bogor no.1, Jakarta', - no_telp='081212123131', - image=image - ) + lokasi=lokasi_test lokasi.save() fasilitas=Fasilitas( lokasi=lokasi, @@ -250,7 +385,7 @@ class InformasiFasilitasViewTest(TestCase): ) fasilitas.save() response = Client().get(reverse('list-fasilitas', kwargs={'nama_lokasi':'Mall'})) - self.assertEqual(response.status_code, 200) + self.assertEqual(response.status_code, HTTPStatus.OK) def test_cannot_post_list_fasilitas(self): image = tempfile.NamedTemporaryFile(suffix=".jpg").name @@ -272,21 +407,9 @@ class InformasiFasilitasViewTest(TestCase): def test_can_get_detail_fasilitas(self): image = tempfile.NamedTemporaryFile(suffix=".jpg").name - user=User( - username='user@gmail.com', - last_name='name', - email='user@gmail.com', - password='hahagotim' - ) + user=user_test user.save() - lokasi=Lokasi( - name='Mall', - latitude=0.0, - longitude=0.0, - alamat='Jl. Raya Bogor no.1, Jakarta', - no_telp='081212123131', - image=image - ) + lokasi=lokasi_test lokasi.save() fasilitas=Fasilitas( lokasi=lokasi, @@ -305,21 +428,9 @@ class InformasiFasilitasViewTest(TestCase): def test_cannot_post_detail_fasilitas(self): image = tempfile.NamedTemporaryFile(suffix=".jpg").name - user=User( - username='user@gmail.com', - last_name='name', - email='user@gmail.com', - password='hahagotim' - ) + user=user_test user.save() - lokasi=Lokasi( - name='Mall', - latitude=0.0, - longitude=0.0, - alamat='Jl. Raya Bogor no.1, Jakarta', - no_telp='081212123131', - image=image - ) + lokasi=lokasi_test lokasi.save() fasilitas=Fasilitas( lokasi=lokasi, @@ -354,15 +465,7 @@ class InformasiFasilitasViewTest(TestCase): token = content['token'] client = Client(HTTP_AUTHORIZATION='token '+token) - image = tempfile.NamedTemporaryFile(suffix=".jpg").name - lokasi=Lokasi( - name='Mall', - latitude=0.0, - longitude=0.0, - alamat='Jl. Raya Bogor no.1, Jakarta', - no_telp='081212123131', - image=image - ) + lokasi=lokasi_test lokasi.save() response = client.post(reverse('add-fasilitas', kwargs={'nama_lokasi':'Mall'}), @@ -385,15 +488,7 @@ class InformasiFasilitasViewTest(TestCase): token = content['token'] client = Client(HTTP_AUTHORIZATION='token '+token) - image = tempfile.NamedTemporaryFile(suffix=".jpg").name - lokasi=Lokasi( - name='Mall', - latitude=0.0, - longitude=0.0, - alamat='Jl. Raya Bogor no.1, Jakarta', - no_telp='081212123131', - image=image - ) + lokasi=lokasi_test lokasi.save() response = client.get(reverse('add-fasilitas', kwargs={'nama_lokasi':'Mall'})) @@ -416,4 +511,38 @@ class InformasiFasilitasViewTest(TestCase): response = client.post(reverse('add-fasilitas', kwargs={'nama_lokasi':'Mall'}), {'deskripsi' : 'penjelasan fasilitas', 'rating' : 2}) - self.assertEqual(response.status_code, 404) \ No newline at end of file + self.assertEqual(response.status_code, HTTPStatus.NOT_FOUND) + + def test_put_update_detail_fasilitas_success(self): + email='user@gmail.com' + password='hahagotim' + Client().post('/api/register/', + {'name':'name', + 'email':email, + 'phone_number':000000000, + 'password':password}) + token_response = Client().post('/api-token-auth/', + {'username' : email, 'password' : password}) + content = json.loads(token_response.content.decode('utf-8')) + token = content['token'] + client = Client(HTTP_AUTHORIZATION='token '+token) + + lokasi=lokasi_test + lokasi.save() + + response = client.post(reverse('add-fasilitas', kwargs={'nama_lokasi':'Mall'}), + {'deskripsi' : 'penjelasan fasilitas', + 'rating' : 2, + 'tag' : 'KR RT'}) + + response_json = json.loads(response.content.decode("utf-8")) + fasilitas_id = response_json["id"] + response = client.put(reverse('update-fasilitas', kwargs={'nama_lokasi':'Mall',"id":fasilitas_id}), + data={'deskripsi' : 'penjelasan fasilitases', + 'rating' : 3, + 'tag' : 'KR'}, content_type="multipart/form-data") + response_json = json.loads(response.content.decode("utf-8")) + self.assertEqual(response.status_code, HTTPStatus.ACCEPTED) + + + \ No newline at end of file -- GitLab From 42ff634a3647c8eb4b18764639881895a94cb9e1 Mon Sep 17 00:00:00 2001 From: Bimo Iman Smartadi Date: Mon, 27 Apr 2020 17:20:21 +0700 Subject: [PATCH 4/8] [RED] Updated tests for consistency --- informasi_fasilitas/tests.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/informasi_fasilitas/tests.py b/informasi_fasilitas/tests.py index ad115f5..fc0f3ea 100644 --- a/informasi_fasilitas/tests.py +++ b/informasi_fasilitas/tests.py @@ -248,11 +248,11 @@ class LokasiRelatedViewTest(InformasiFasilitasViewTest): def test_can_get_lokasi_details(self): lokasi=lokasi_test lokasi.save() - response = Client().get(reverse('lokasi-details', kwargs={'name':'Mall'})) + response = Client().get(reverse('lokasi-details', kwargs={'nama_lokasi':'Mall'})) self.assertEqual(response.status_code, HTTPStatus.OK) def test_can_get_lokasi_details_json(self): - response = Client().get(reverse('lokasi-details', kwargs={'name':'Ma Homie'})) + response = Client().get(reverse('lokasi-details', kwargs={'nama_lokasi':'Ma Homie'})) content = json.loads(response.content.decode('utf-8')) expected_json = {'id': 1, 'name':'Ma Homie', @@ -266,11 +266,11 @@ class LokasiRelatedViewTest(InformasiFasilitasViewTest): def test_cannot_post_lokasi_details(self): lokasi=lokasi_test lokasi.save() - response = Client().post(reverse('lokasi-details', kwargs={'name':'Mall'})) + response = Client().post(reverse('lokasi-details', kwargs={'nama_lokasi':'Mall'})) self.assertEqual(response.status_code, HTTPStatus.METHOD_NOT_ALLOWED) def test_get_lokasi_details_not_found(self): - response = Client().get(reverse('lokasi-details', kwargs={'name':'Mall'})) + response = Client().get(reverse('lokasi-details', kwargs={'nama_lokasi':'Mall'})) self.assertEqual(response.status_code, HTTPStatus.NOT_FOUND) def test_can_post_add_lokasi(self): -- GitLab From 25b4eb9385fb882801914d6c343d3cb3d0bc6188 Mon Sep 17 00:00:00 2001 From: Bimo Iman Smartadi Date: Mon, 27 Apr 2020 17:29:21 +0700 Subject: [PATCH 5/8] [RED] Updated tests to match serializers format --- informasi_fasilitas/tests.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/informasi_fasilitas/tests.py b/informasi_fasilitas/tests.py index fc0f3ea..c4cd4a4 100644 --- a/informasi_fasilitas/tests.py +++ b/informasi_fasilitas/tests.py @@ -317,11 +317,15 @@ class LokasiRelatedViewTest(InformasiFasilitasViewTest): 'no_telp' : '081212123131'}) response_json = json.loads(response.content.decode("utf-8")) - expected_json = {'name' : 'Mall', + expected_json = { + "id": 3, + 'name' : 'Mall', 'latitude' : 0.0, 'longitude' : 0.0, 'alamat' : 'Jl. Raya Bogor no.1, Jakarta', - 'no_telp' : '081212123131'} + 'no_telp' : '081212123131', + "image" : None + } self.assertEqual(response_json, expected_json) -- GitLab From 94e5ce07ac9b676d8f7f20d77c2cb483c39ec3fe Mon Sep 17 00:00:00 2001 From: Bimo Iman Smartadi Date: Mon, 27 Apr 2020 17:30:24 +0700 Subject: [PATCH 6/8] [GREEN] Passed tests --- informasi_fasilitas/urls.py | 4 ++-- informasi_fasilitas/views.py | 30 +++++++++++++++++++----------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/informasi_fasilitas/urls.py b/informasi_fasilitas/urls.py index 64bf994..caf571e 100644 --- a/informasi_fasilitas/urls.py +++ b/informasi_fasilitas/urls.py @@ -4,8 +4,8 @@ from . import views urlpatterns = [ path('lokasi/list/', views.lokasi_list,name='lokasi-list'), - path('lokasi/detail//', views.lokasi_details,name='lokasi-details'), - path('lokasi/update-detail//', views.lokasi_details,name='update-lokasi'), + path('lokasi/detail//', views.lokasi_details,name='lokasi-details'), + path('lokasi/update-detail//', views.update_lokasi_details,name='update-lokasi'), path('lokasi/add/', views.add_lokasi,name='add-lokasi'), path('lokasi/add-fasilitas//', views.add_fasilitas, name='add-fasilitas'), path('lokasi/list-fasilitas//', views.list_fasilitas, name='list-fasilitas'), diff --git a/informasi_fasilitas/views.py b/informasi_fasilitas/views.py index 70f5a68..edf9f58 100644 --- a/informasi_fasilitas/views.py +++ b/informasi_fasilitas/views.py @@ -32,10 +32,10 @@ def lokasi_list(request): @api_view(['GET']) @authentication_classes([]) @permission_classes([]) -def lokasi_details(request,name): +def lokasi_details(request,nama_lokasi): try: if request.method == 'GET': - lokasi = Lokasi.objects.get(name = name) + lokasi = Lokasi.objects.get(name = nama_lokasi) serializer = LokasiSerializer(lokasi) return JsonResponse(serializer.data, safe=False, status = 200) else: @@ -64,19 +64,19 @@ def add_lokasi(request): except KeyError as e: return JsonResponse({'response': missing_key_message(str(e))}, status = 500) -@api_view(['POST']) +@api_view(['PUT']) @authentication_classes([TokenAuthentication]) @permission_classes([IsAuthenticated]) -def update_lokasi_details(request, name): +def update_lokasi_details(request, nama_lokasi): try: if request.method == 'PUT': - lokasi = Lokasi.objects.get(name = name) + lokasi = Lokasi.objects.get(name = nama_lokasi) if 'no_telp' in request.data.keys(): lokasi.no_telp = request.data['no_telp'] lokasi.save() - return JsonResponse({'response' : "phone changed to {}".format(lokasi.no_telp)}, status = 201) + return JsonResponse({'response' : "phone changed to {}".format(lokasi.no_telp)}, status = 202) else: - return JsonResponse({'response' : request_error_message("post")}, status = 400) + return JsonResponse({'response' : request_error_message("put")}, status = 400) except KeyError as e: return JsonResponse({'response': missing_key_message(str(e))}, status = 500) @@ -149,8 +149,17 @@ def detail_fasilitas(request, nama_lokasi, id): user = fasilitas.user fasilitas.like = Likes.objects.filter(fasilitas = fasilitas).count() fasilitas.dislike = Dislikes.objects.filter(fasilitas = fasilitas).count() - return_json = {"nama_lokasi": lokasi.name, "deskripsi":fasilitas.deskripsi, "creator":user.last_name, "date_time":fasilitas.date_time, - "like":fasilitas.like, "dislike":fasilitas.dislike, "rating":fasilitas.rating, "tag":fasilitas.tag, "image":str(fasilitas.image), "is_verified":fasilitas.is_verified} + return_json = {"nama_lokasi": lokasi.name, + "deskripsi":fasilitas.deskripsi, + "creator":user.last_name, + "creator_email": user.email, + "date_time":fasilitas.date_time, + "like":fasilitas.like, + "dislike":fasilitas.dislike, + "rating":fasilitas.rating, + "tag":fasilitas.tag, + "image":str(fasilitas.image), + "is_verified":fasilitas.is_verified} return JsonResponse(return_json, status = 200) else: return JsonResponse({'response' : request_error_message("get")}, status = 400) @@ -170,7 +179,6 @@ def update_fasilitas(request, nama_lokasi, id): user_creator = fasilitas.user desc = fasilitas.deskripsi tag = fasilitas.tag - print(request.data) if user_creator == request.user: if 'deskripsi' in request.data.keys(): desc = request.data['deskripsi'] @@ -179,7 +187,7 @@ def update_fasilitas(request, nama_lokasi, id): fasilitas.deskripsi = desc fasilitas.tag = tag fasilitas.save() - return JsonResponse({'response' : '{} in fasilitas edited'.format(str(request.data.keys())), }, status = 201) + return JsonResponse({'response' : '{} in fasilitas edited'.format(str(request.data.keys())), }, status = 202) return JsonResponse({'response' : 'Authentication failed'}, status = 502) except KeyError as e: return JsonResponse({'response': missing_key_message(str(e))}, status = 500) -- GitLab From f86cd4a05aa6326d0e5a581b77c754bdb9ac8999 Mon Sep 17 00:00:00 2001 From: Bimo Iman Smartadi Date: Mon, 27 Apr 2020 17:31:24 +0700 Subject: [PATCH 7/8] [CHORES] Updated README.md for updated operation --- README.md | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 76e65f0..63ec1cd 100644 --- a/README.md +++ b/README.md @@ -120,13 +120,14 @@ Make `POST` request to API endpoint `/informasi-lokasi/lokasi/add-fasilitas/*nam Make sure you have token it your request header. Add this to your request header. `Authorization` with value `token *your_token_from_request*` -### 8. To see a facility list: +### 8. To see a facility list from a location: Make `GET` request to API endpoint `/informasi-lokasi/lokasi/list-fasilitas/*nama-lokasi*/`.
It will return a json with the following key: * `id`: id of the facility * `nama_lokasi`: location name of the facility * `deskripsi`: the description * `creator`: User's last name who registered the facility +* `creators_email`: User's email who registered the facility * `date_time`: Date when the facility was made * `like`: how many people like this facility. default is 0 * `dislike`: how many people dislike this facility. default is 0 @@ -135,13 +136,13 @@ It will return a json with the following key: * `image`: Image for facility * `is_verified`: Verified status - ### 9. To see a facility details: Make `GET` request to API endpoint `/informasi-lokasi/lokasi/detail-fasilitas/*nama-lokasi*/*id-fasilitas*/`.
It will return a json with the following key: * `nama_lokasi`: location name of the facility * `deskripsi`: the description * `creator`: User's last name who registered the facility +* `creators_email`: User's email who registered the facility * `date_time`: Date when the facility was made * `like`: how many people like this facility. default is 0 * `dislike`: how many people dislike this facility. default is 0 @@ -151,17 +152,32 @@ It will return a json with the following key: * `is_verified`: Verified status ### 10. To update a facility details: -Make `GET` request to API endpoint `/informasi-lokasi/lokasi/detail-fasilitas/*nama-lokasi*/*id-fasilitas*/`.
-It will return a json with the following key: -* `nama_lokasi`: location name of the facility +Make `PUT` request to API endpoint `/informasi-lokasi/lokasi/update-fasilitas/*nama-lokasi*/*id-fasilitas*/`.
+It requires a request with the following key: * `deskripsi`: the description -* `creator`: User's last name who registered the facility -* `date_time`: Date when the facility was made -* `like`: how many people like this facility. default is 0 -* `dislike`: how many people dislike this facility. default is 0 * `rating`: rating of the facility. Default is 3 * `tag`: Facility tag * `image`: Image for facility -* `is_verified`: Verified status - +Make sure you have token it your request header. +Add this to your request header. `Authorization` with value `token *your_token_from_request*` +This token is also used to authorize whether you are the creator of the facility or not, since only the creator +of the facility could update the facility +### 10. To update a location phone_number: +Make `PUT` request to API endpoint `/informasi-lokasi/lokasi/update-lokasi/*nama-lokasi*/`.
+It requires a request with the following key: +* `no_telp`: the description +Make sure you have token it your request header. +Add this to your request header. `Authorization` with value `token *your_token_from_request*` +This token is also used to authorize whether you are the creator of the location or not, since only the creator +of the location could update the location + +### 10. To like / dislike a facility: +Make `PUT` request to API endpoint `/informasi-lokasi/lokasi/like-facility/*nama-lokasi*/*operation*/`.
+Replace the `operation` with: +* `like` : if you want to like the facility +* `dislike` : if you want to dislike the facility +You cannot like/dislike the same model more than once, if you like a facility then you dislike it, +the "like" you give before will be replaced by dislike, and vice-versa. +Make sure you have token it your request header. +Add this to your request header. `Authorization` with value `token *your_token_from_request*` \ No newline at end of file -- GitLab From 373e4352cdb953d43d81f6678278e3bedd3da98b Mon Sep 17 00:00:00 2001 From: Bimo Iman Smartadi Date: Mon, 27 Apr 2020 17:31:58 +0700 Subject: [PATCH 8/8] [REFACTOR] Refactored tests in new_rest_api for reducing code smell --- new_rest_api/tests.py | 1 - 1 file changed, 1 deletion(-) diff --git a/new_rest_api/tests.py b/new_rest_api/tests.py index d70e7b7..5c8807b 100644 --- a/new_rest_api/tests.py +++ b/new_rest_api/tests.py @@ -19,7 +19,6 @@ class UserTests(APITestCase): 'password':'chingchenghanji',} self.client.post(url, data) - def test_create_user(self): """ Ensure we can create a new account object. -- GitLab