Fakultas Ilmu Komputer UI

Commit 5b62333e authored by Reyhan Alhafizal Hamidi's avatar Reyhan Alhafizal Hamidi
Browse files

Merge branch '1706040082-55' into 'master'

[#55] Homepage: Hottest Material List

Closes #55

See merge request !103
parents 8d5a308e ee80a2d7
Pipeline #60145 passed with stages
in 32 minutes and 56 seconds
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_earliest_materi(self):
return self.date_created.timestamp() - Materi.earliest_materi_timestamp()
@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_earliest_materi / 604800 # 1 week
return round(view_score + time_score, 7)
@property
def is_like(self):
like = False
......
......@@ -63,6 +63,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"):
......
......@@ -135,6 +135,9 @@
<li>
<a href="?sort=terpopuler">terpopuler</a>
</li>
<li>
<a href="?sort=terhangat">terhangat</a>
</li>
<li>
<a href="?sort=judul">judul</a>
</li>
......
......@@ -6,6 +6,8 @@ import random
import re
import tempfile
import time
import itertools
from django.test import override_settings
from datetime import datetime
from io import StringIO
from time import sleep
......@@ -27,6 +29,7 @@ from django.core.files import File
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.management import call_command
from django.db.utils import IntegrityError
from pytz import timezone, UTC
from django.test import (Client, RequestFactory, TestCase, TransactionTestCase,
override_settings)
from django.urls import resolve, reverse
......@@ -207,6 +210,163 @@ class DaftarKatalogSortingByJumlahTampilanTest(TestCase):
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 DaftarKatalogSortingByJumlahKomentarTest(TestCase):
def setUp(self):
self.client = Client()
......@@ -3470,7 +3630,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 = {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment