From cfc739c11620add802de7e77cccdb4f0a2632ccf Mon Sep 17 00:00:00 2001 From: Reyhan Alhafizal Date: Sat, 31 Oct 2020 21:35:01 +0700 Subject: [PATCH 1/3] [RED] Create Sort By Hottest Test --- app/tests.py | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 161 insertions(+), 3 deletions(-) diff --git a/app/tests.py b/app/tests.py index 5b83a94..fc9611f 100644 --- a/app/tests.py +++ b/app/tests.py @@ -4,6 +4,7 @@ from io import StringIO import re import time import random +import itertools from django.test import override_settings from bs4 import BeautifulSoup @@ -20,7 +21,7 @@ from django.test import Client, TestCase, TransactionTestCase from django.urls import resolve, reverse from django.db.utils import IntegrityError from django.test import Client, RequestFactory, TestCase, TransactionTestCase -from pytz import timezone +from pytz import timezone, UTC from time import sleep import datetime as dt @@ -228,7 +229,164 @@ class DaftarKatalogSortingByJumlahTampilanTest(TestCase): self.client.get(self.url) response = self.client.get("/?sort=jumlah_tampilan") self.assertRegex(str(response.content), rf'.*Materi 2.*Materi 1.*') - + + +class DaftarKatalogSortingByTerhangatTest(TestCase): + @classmethod + def generate_view_materi(cls, materi, view_count): + for _ in itertools.repeat(None, view_count): + ViewStatistics.objects.create(materi=materi) + + def get_displayed_materi_in_number(self): + response = self.client.get("/?sort=terhangat") + lst = [int(id) for id in re.findall(r"Materi\s(\d+)[^\d]", + response.content.decode())] + return lst + + def setUp(self): + self.contributor_credential = { + "email": "kontributor@gov.id", + "password": id_generator() + } + self.contributor = get_user_model().objects.create_user( + name="Kontributor", + is_contributor=True, + **self.contributor_credential, + ) + self.client = Client() + content = b"Test file" + self.cover = SimpleUploadedFile( + "cover.jpg", + content + ) + self.content = SimpleUploadedFile( + "content.txt", + content + ) + + self.materi_data = { + "author": "Reyhan", + "uploader": self.contributor, + "publisher": "Publisher", + "descriptions": "Deskripsi Materi", + "status": "APPROVE", + "cover": self.cover, + "content": self.content, + } + + def test_1_week_difference_give_1_hot_score_difference(self): + materi1 = Materi.objects.create( + title='Materi 1', + date_created=datetime(2020, 10, 1, 7, 0, 0, tzinfo=UTC), + **self.materi_data + ) + materi2 = Materi.objects.create( + title='Materi 2', + date_created=datetime(2020, 10, 8, 7, 0, 0, tzinfo=UTC), + **self.materi_data + ) + materi3 = Materi.objects.create( + title='Materi 3', + date_created=datetime(2020, 10, 15, 7, 0, 0, tzinfo=UTC), + **self.materi_data + ) + self.generate_view_materi(materi1, 1) + self.generate_view_materi(materi2, 1) + self.generate_view_materi(materi3, 1) + + self.assertAlmostEqual(materi3.hot_score - materi2.hot_score, 1) + self.assertAlmostEqual(materi2.hot_score - materi1.hot_score, 1) + + def test_10_exponential_view_count_difference_give_1_hot_score_difference(self): + materi1 = Materi.objects.create( + title='Materi 1', + date_created=datetime(2020, 10, 1, 7, 0, 0, tzinfo=UTC), + **self.materi_data + ) + materi2 = Materi.objects.create( + title='Materi 2', + date_created=datetime(2020, 10, 1, 7, 0, 0, tzinfo=UTC), + **self.materi_data + ) + materi3 = Materi.objects.create( + title='Materi 3', + date_created=datetime(2020, 10, 1, 7, 0, 0, tzinfo=UTC), + **self.materi_data + ) + self.generate_view_materi(materi1, 1) + self.generate_view_materi(materi2, 10) + self.generate_view_materi(materi3, 100) + + self.assertAlmostEqual(materi3.hot_score - materi2.hot_score, 1) + self.assertAlmostEqual(materi2.hot_score - materi1.hot_score, 1) + + def test_0_and_1_views_has_the_same_hot_score(self): + materi1 = Materi.objects.create( + title='Materi 1', + date_created=datetime(2020, 10, 1, 7, 0, 0, tzinfo=UTC), + **self.materi_data + ) + materi2 = Materi.objects.create( + title='Materi 2', + date_created=datetime(2020, 10, 1, 7, 0, 0, tzinfo=UTC), + **self.materi_data + ) + self.generate_view_materi(materi1, 0) + self.generate_view_materi(materi2, 1) + + self.assertAlmostEqual(materi1.hot_score, materi2.hot_score) + + def test_page_has_option_sort_by_hottest(self): + response = self.client.get("/") + self.assertIn("terhangat", response.content.decode()) + + def test_page_display_sort_by_hottest(self): + materi1 = Materi.objects.create( + title='Materi 1', + date_created=datetime(2020, 10, 1, 7, 0, 0, tzinfo=UTC), + **self.materi_data + ) + materi2 = Materi.objects.create( + title='Materi 2', + date_created=datetime(2020, 10, 1, 7, 0, 0, tzinfo=UTC), + **self.materi_data + ) + materi3 = Materi.objects.create( + title='Materi 3', + date_created=datetime(2020, 10, 8, 7, 0, 0, tzinfo=UTC), + **self.materi_data + ) + materi4 = Materi.objects.create( + title='Materi 4', + date_created=datetime(2020, 10, 9, 7, 0, 0, tzinfo=UTC), + **self.materi_data + ) + self.generate_view_materi(materi1, 11) + self.generate_view_materi(materi2, 10) + self.generate_view_materi(materi3, 1) + self.generate_view_materi(materi4, 1) + + lst = self.get_displayed_materi_in_number() + self.assertEqual(lst, [4, 1, 3, 2]) + + def test_prefer_newest_materi_if_hot_score_is_same(self): + materi1 = Materi.objects.create( + title='Materi 1', + date_created=datetime(2020, 10, 1, 7, 0, 0, tzinfo=UTC), + **self.materi_data + ) + materi2 = Materi.objects.create( + title='Materi 2', + date_created=datetime(2020, 10, 8, 7, 0, 0, tzinfo=UTC), + **self.materi_data + ) + self.generate_view_materi(materi1, 10) + self.generate_view_materi(materi2, 1) + + lst = self.get_displayed_materi_in_number() + self.assertEqual(lst, [2, 1]) + + class DaftarKatalogPerKontributorTest(TestCase): def setUp(self): self.client = Client() @@ -3444,7 +3602,7 @@ class MateriRecommendationTest(TestCase): response = Client().get("/?recommendation=1") list = [int(id) for id in re.findall(r"Materi\s(\d+)[^\d]", response.content.decode())] self.assertEqual(list, [1, 2]) - + class BacaNantiTest(TestCase): def setUp(self): self.contributor_credential = { -- GitLab From 26c58eb5a5f7e1addf392d2ed0fff9087fd9669b Mon Sep 17 00:00:00 2001 From: Reyhan Alhafizal Date: Sat, 31 Oct 2020 21:37:06 +0700 Subject: [PATCH 2/3] [GREEN] Implement [RED] Create Sort By Hottest --- app/models.py | 20 ++++++++++++++++++++ app/services.py | 3 +++ app/templates/app/katalog_materi.html | 3 +++ 3 files changed, 26 insertions(+) diff --git a/app/models.py b/app/models.py index fb932f7..995e52b 100644 --- a/app/models.py +++ b/app/models.py @@ -1,5 +1,6 @@ import random import datetime +import math from django.contrib.postgres import search from django.core.exceptions import ValidationError @@ -135,6 +136,25 @@ class Materi(SoftDeleteModel): count = Review.objects.filter(materi=self).count() return count + @staticmethod + def earliest_materi_timestamp(): + return Materi.objects.earliest('date_created').date_created.timestamp() + + @property + def seconds_since_project_created(self): + return self.date_created.timestamp() - Materi.earliest_materi_timestamp() #1577811600 + + @property + def view_count(self): + count = ViewStatistics.objects.filter(materi=self).count() + return count + + @property + def hot_score(self): + view_score = math.log(max(self.view_count, 1), 10) + time_score = self.seconds_since_project_created / 604800 #604800 90000 # 1 minggu + return round(view_score + time_score, 7) + @property def is_like(self): like = False diff --git a/app/services.py b/app/services.py index 300dbf4..7ec3e34 100644 --- a/app/services.py +++ b/app/services.py @@ -60,6 +60,9 @@ class DafterKatalogService: lst_materi = lst_materi.order_by('date_created') elif (get_sort == "terpopuler"): lst_materi = lst_materi.annotate(count=Count('like__id')).order_by('-count') + elif (get_sort == "terhangat"): + lst_materi = sorted(lst_materi, + key=lambda t: (t.hot_score, t.date_created), reverse=True) elif (get_sort == "jumlah_unduh"): lst_materi = lst_materi.annotate(count=Count('unduh__id')).order_by('-count') elif (get_sort == "jumlah_tampilan"): diff --git a/app/templates/app/katalog_materi.html b/app/templates/app/katalog_materi.html index 4a06d4c..025690e 100644 --- a/app/templates/app/katalog_materi.html +++ b/app/templates/app/katalog_materi.html @@ -134,6 +134,9 @@
  • terpopuler
  • +
  • + terhangat +
  • judul
  • -- GitLab From a2206d3861483012f7d9f438e68cc30e2cd37fba Mon Sep 17 00:00:00 2001 From: Reyhan Alhafizal Date: Sat, 31 Oct 2020 22:15:30 +0700 Subject: [PATCH 3/3] [REFACTOR] Change seconds_since_project_created method name --- app/models.py | 6 +++--- digipus/__pycache__/settings.cpython-36.pyc | Bin 4178 -> 4184 bytes 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models.py b/app/models.py index 995e52b..b4d3fda 100644 --- a/app/models.py +++ b/app/models.py @@ -141,8 +141,8 @@ class Materi(SoftDeleteModel): return Materi.objects.earliest('date_created').date_created.timestamp() @property - def seconds_since_project_created(self): - return self.date_created.timestamp() - Materi.earliest_materi_timestamp() #1577811600 + def seconds_since_earliest_materi(self): + return self.date_created.timestamp() - Materi.earliest_materi_timestamp() @property def view_count(self): @@ -152,7 +152,7 @@ class Materi(SoftDeleteModel): @property def hot_score(self): view_score = math.log(max(self.view_count, 1), 10) - time_score = self.seconds_since_project_created / 604800 #604800 90000 # 1 minggu + time_score = self.seconds_since_earliest_materi / 604800 # 1 week return round(view_score + time_score, 7) @property diff --git a/digipus/__pycache__/settings.cpython-36.pyc b/digipus/__pycache__/settings.cpython-36.pyc index 43d2d1c4169e7113ebfa287197b9840fd637a652..2e8d5505327c65aad19bcc06e556bd3f737fca54 100644 GIT binary patch delta 49 zcmcbla6^IJn3tF9o%!62?B@J34*D7SxvBa^sg)UtdHOE-$)&lec_qdA0lon~lSBCb F0RWeP5ikG% delta 43 zcmcbia7lsPn3tC;Wci$p?B@JpR{9zFxvBbz8M%om@o9;rRf%~frWTW<`2PU_FSZV^ -- GitLab