From cba080b644e706aadb3e74bf2a3ab8814b7af71e Mon Sep 17 00:00:00 2001
From: Farhan Azyumardhi Azmi <farhan.azyumardhi@ui.ac.id>
Date: Thu, 1 Oct 2020 12:23:08 +0700
Subject: [PATCH] [GREEN] Change django.contrib.postgres.fields.JSONField usage
 to django.db.models.JSONField for VerificationReport model

---
 .gitignore                                    |  5 +-
 .../migrations/0007_auto_20200929_1218.py     | 18 +++++
 administration/models.py                      |  4 +-
 app/tests.py                                  | 78 +++++++++++++++----
 .../migrations/0006_auto_20200929_2125.py     | 18 +++++
 requirements.txt                              |  6 +-
 6 files changed, 107 insertions(+), 22 deletions(-)
 create mode 100644 administration/migrations/0007_auto_20200929_1218.py
 create mode 100644 authentication/migrations/0006_auto_20200929_2125.py

diff --git a/.gitignore b/.gitignore
index 9298ea6..d318087 100644
--- a/.gitignore
+++ b/.gitignore
@@ -205,4 +205,7 @@ __pycache__/
 db.sqlite3
 .coverage
 htmlcov/
-flowchart/
\ No newline at end of file
+flowchart/
+
+# Pycharm IDE
+.idea
diff --git a/administration/migrations/0007_auto_20200929_1218.py b/administration/migrations/0007_auto_20200929_1218.py
new file mode 100644
index 0000000..735e715
--- /dev/null
+++ b/administration/migrations/0007_auto_20200929_1218.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.1 on 2020-09-29 05:18
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('administration', '0006_merge_20200604_0718'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='verificationreport',
+            name='report',
+            field=models.JSONField(),
+        ),
+    ]
diff --git a/administration/models.py b/administration/models.py
index 8f8246d..ba0756c 100644
--- a/administration/models.py
+++ b/administration/models.py
@@ -1,4 +1,4 @@
-from django.contrib.postgres.fields import JSONField
+from django.db.models import JSONField
 from django.db import models
 from django.utils import timezone
 
@@ -25,4 +25,4 @@ class DeletionHistory(models.Model):
     deleted_user_name = models.CharField(max_length=150)
     deleted_user_role = models.CharField(max_length=150)
     timestamp = models.DateTimeField(default=timezone.now)
-    deletor_admin = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
\ No newline at end of file
+    deletor_admin = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
diff --git a/app/tests.py b/app/tests.py
index f8fff26..9a6e595 100644
--- a/app/tests.py
+++ b/app/tests.py
@@ -1,12 +1,15 @@
 import json
+from io import StringIO
 
 from django.contrib.auth import get_user_model
 from django.core.exceptions import ValidationError
 from django.core.files.uploadedfile import SimpleUploadedFile
+from django.core.management import call_command
+from django.test import Client, RequestFactory, TestCase
 from django.db import IntegrityError
-from django.test import Client, TestCase
 from django.urls import resolve
 
+from administration.models import VerificationSetting, VerificationReport
 from administration.utils import id_generator
 from app.views import UploadMateriView
 from authentication.models import User
@@ -155,7 +158,7 @@ class DetailMateriTest(TestCase):
         self.client.get(deleteURL)
         self.assertEqual(Comment.objects.all().filter(
             comment="This is new comment by Anonymous").count(), 0)
-        
+
 class ViewCommentsTest(TestCase):
     def setUp(self):
         self.client = Client()
@@ -207,7 +210,7 @@ class ViewCommentsTest(TestCase):
         response = self.client.get(self.url)
         self.assertContains(response, "this is contributor comment")
         self.assertNotContains(response, 'bukan comment')
-    
+
     def test_comments_page_only_render_specific_user_comments(self):
         self.client.login(**self.contributor_credential)
         response = self.client.get(self.url)
@@ -219,7 +222,7 @@ class ViewCommentsTest(TestCase):
         response = self.client.get(self.url)
         self.assertEqual(response.status_code, 403)
         self.assertNotEqual(response.status_code, 200)
-        
+
 class TemplateLoaderTest(TestCase):
     def test_template_loader_url_exist(self):
         url = "/test-page.html"
@@ -684,7 +687,7 @@ class LikeMateriTest(TestCase):
         num_of_likes = Like.objects.filter(materi = self.materi1).count()
         self.assertEqual(num_of_likes, 0)
 
-        # Like a materi 
+        # Like a materi
         response = self.client.get(self.url_materi)
         session_id = response.context["session_id"]
         materi_id = response.context["materi_data"].id
@@ -701,7 +704,7 @@ class LikeMateriTest(TestCase):
         num_of_likes = Like.objects.filter(materi = self.materi1).count()
         self.assertEqual(num_of_likes, 0)
 
-        # Like a materi 
+        # Like a materi
         response = self.client.get(self.url_materi)
         session_id = response.context["session_id"]
         materi_id = response.context["materi_data"].id
@@ -713,7 +716,7 @@ class LikeMateriTest(TestCase):
         num_of_likes = Like.objects.filter(materi = self.materi1).count()
         self.assertEqual(num_of_likes, 1)
 
-        # Unlike a materi 
+        # Unlike a materi
         response = self.client.get(self.url_materi)
         session_id = response.context["session_id"]
         materi_id = response.context["materi_data"].id
@@ -730,7 +733,7 @@ class LikeMateriTest(TestCase):
         num_of_likes = Like.objects.filter(materi = self.materi1).count()
         self.assertEqual(num_of_likes, 0)
 
-        # Client 1 like a materi 
+        # Client 1 like a materi
         response = self.client.get(self.url_materi)
         session_id = response.context["session_id"]
         materi_id = response.context["materi_data"].id
@@ -742,7 +745,7 @@ class LikeMateriTest(TestCase):
         num_of_likes = Like.objects.filter(materi = self.materi1).count()
         self.assertEqual(num_of_likes, 1)
 
-        # Client 2 like a materi 
+        # Client 2 like a materi
         response = Client().get(self.url_materi)
         session_id = response.context["session_id"]
         materi_id = response.context["materi_data"].id
@@ -759,26 +762,26 @@ class LikeMateriTest(TestCase):
         num_of_likes = Like.objects.filter(materi = self.materi1).count()
         self.assertEqual(num_of_likes, 0)
 
-        # missing session id 
+        # missing session id
         response = self.client.get(self.url_materi)
         materi_id = response.context["materi_data"].id
         payload = {
             'materi_id': materi_id,
         }
         ajax_response = Client().post(self.url_like, payload)
-        ajax_response = json.loads(ajax_response.content) 
+        ajax_response = json.loads(ajax_response.content)
         num_of_likes = Like.objects.filter(materi = self.materi1).count()
         self.assertEqual(num_of_likes, 0)
         self.assertEqual(ajax_response.get("success", None), False)
-        
-        # missing materi id 
+
+        # missing materi id
         response = self.client.get(self.url_materi)
         session_id = response.context["session_id"]
         payload = {
             'session_id': session_id
         }
         ajax_response = Client().post(self.url_like, payload)
-        ajax_response = json.loads(ajax_response.content) 
+        ajax_response = json.loads(ajax_response.content)
         num_of_likes = Like.objects.filter(materi = self.materi1).count()
         self.assertEqual(num_of_likes, 0)
         self.assertEqual(ajax_response.get("success", None), False)
@@ -809,7 +812,7 @@ class ViewMateriStatissticsTest(TestCase):
         self.materi1 = Materi.objects.first()
         self.url = f"/materi/{self.materi1.id}/view"
 
-    # Test single view 
+    # Test single view
     def test_count_one_materi_view(self):
         response = self.client.get(self.url)
         num_of_views = self.materi1.baca.all().count()
@@ -850,7 +853,7 @@ class DownloadMateriStatissticsTest(TestCase):
         self.materi1 = Materi.objects.first()
         self.url = f"/materi/{self.materi1.id}/unduh"
 
-    # Test single download 
+    # Test single download
     def test_count_one_materi_download(self):
         response = self.client.get(self.url)
         num_of_downloads = self.materi1.unduh.all().count()
@@ -927,6 +930,49 @@ class RevisiMateriTest(TestCase):
         self.client.logout()
 
 
+class GenerateDummyCommandTest(TestCase):
+
+    def setUp(self):
+        self.material_numbers = [5, 10, 25, 100]
+        self.invalid_material_numbers = [-100, -10, -1, 0, 1, 2, 3, 4]
+        self.stdout = StringIO()
+
+    def test_command_output_with_given_num_of_materi(self):
+        for num_of_materi in self.material_numbers:
+            call_command("generatedummy", num_of_materi, stdout=self.stdout)
+            self.assertIn(
+                f"Successfully created {num_of_materi} materi\n",
+                self.stdout.getvalue()
+            )
+
+    def test_command_should_generate_materi_objects(self):
+        for num_of_materi in self.material_numbers:
+            call_command("generatedummy", num_of_materi, stdout=self.stdout)
+            self.assertEqual(Materi.objects.count(), num_of_materi)
+            Materi.objects.all().delete()
+
+    def test_command_should_raise_exception_if_invalid_values_are_given(self):
+        with self.assertRaises(IndexError):
+            for num_of_materi in self.invalid_material_numbers:
+                call_command("generatedummy", num_of_materi)
+
+
+class RemoveDummyCommandTest(TestCase):
+
+    def test_calling_remove_dummy_command_should_remove_generated_dummy_objects(self):
+        stdout = StringIO()
+        call_command("generatedummy", 50)
+
+        call_command("removedummy", stdout=stdout)
+
+        self.assertEqual("Successfully remove all dummy object\n", stdout.getvalue())
+        self.assertEqual(User.objects.count(), 0)
+        self.assertEqual(Category.objects.count(), 0)
+        self.assertEqual(Materi.objects.count(), 0)
+        self.assertEqual(VerificationSetting.objects.count(), 0)
+        self.assertEqual(VerificationReport.objects.count(), 0)
+
+
 class RatingMateriTest(TestCase):
     def setUp(self):
         self.url = '/administration/'
diff --git a/authentication/migrations/0006_auto_20200929_2125.py b/authentication/migrations/0006_auto_20200929_2125.py
new file mode 100644
index 0000000..a2c2da4
--- /dev/null
+++ b/authentication/migrations/0006_auto_20200929_2125.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.1 on 2020-09-29 14:25
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('authentication', '0005_auto_20200519_1021'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='user',
+            name='first_name',
+            field=models.CharField(blank=True, max_length=150, verbose_name='first name'),
+        ),
+    ]
diff --git a/requirements.txt b/requirements.txt
index 1370f29..49fc52a 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,6 +1,6 @@
 anybadge==1.7.0
 appdirs==1.4.3
-asgiref==3.2.7
+asgiref==3.2.10
 astroid==2.3.3
 atomicwrites==1.3.0
 attrs==19.3.0
@@ -20,7 +20,7 @@ coverage==5.0.4
 cryptography==2.9.2
 distlib==0.3.0
 dj-database-url==0.5.0
-Django==3.0.3
+Django==3.1
 django-crispy-forms==1.9.1
 django-heroku==0.3.1
 django-storages==1.9.1
@@ -82,4 +82,4 @@ virtualenv==20.0.18
 wcwidth==0.1.9
 whitenoise==5.0.1
 wrapt==1.11.2
-zipp==3.1.0
\ No newline at end of file
+zipp==3.1.0
-- 
GitLab