From ec28be65564a04a2d07f1d7276ed6a09fe115b42 Mon Sep 17 00:00:00 2001 From: SAMUEL TUPA FEBRIAN <samuel.tupa@ui.ac.id> Date: Thu, 29 Oct 2020 18:58:51 +0700 Subject: [PATCH] [#107] Material Statistic: Download Count --- app/migrations/0025_review.py | 30 +++++++ app/services.py | 4 + app/templates/app/detail_materi.html | 8 ++ app/tests.py | 124 ++++++++++++++++++++++++++- app/views.py | 1 + 5 files changed, 163 insertions(+), 4 deletions(-) create mode 100644 app/migrations/0025_review.py diff --git a/app/migrations/0025_review.py b/app/migrations/0025_review.py new file mode 100644 index 0000000..79b7b89 --- /dev/null +++ b/app/migrations/0025_review.py @@ -0,0 +1,30 @@ +# Generated by Django 3.1 on 2020-10-29 11:22 + +import app.models +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('app', '0024_merge_20201026_0812'), + ] + + operations = [ + migrations.CreateModel( + name='Review', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('username', models.CharField(max_length=100)), + ('profile', models.CharField(default=app.models.getRandomColor, max_length=100)), + ('review', models.TextField(default='review')), + ('timestamp', models.DateTimeField(default=django.utils.timezone.now)), + ('materi', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='app.materi')), + ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/app/services.py b/app/services.py index 538d8f9..d83bf00 100644 --- a/app/services.py +++ b/app/services.py @@ -134,6 +134,10 @@ class DetailMateriService: user_name = request.user.name return user_name + @staticmethod + def init_materi_download_count(context, materi): + context["materi_download_count"] = materi.unduh.all().count() + class CitationService: @staticmethod diff --git a/app/templates/app/detail_materi.html b/app/templates/app/detail_materi.html index fb1b1d0..278c5de 100644 --- a/app/templates/app/detail_materi.html +++ b/app/templates/app/detail_materi.html @@ -164,6 +164,14 @@ div.review { <p class="info-content">{{materi_data.content.size|filesizeformat}}</p> </dd> </div> + <div class="info" id="1"> + <dl class="col col-4"> + <dt class="info-name">Jumlah Download</dt> + </dl> + <dd> + <p class="info-content">{{materi_download_count}}</p> + </dd> + </div> </div> <div class="buttons d-flex flex-row bd-highlight mb-1"> <a href="{% url 'view-materi' materi_data.id %}" diff --git a/app/tests.py b/app/tests.py index 6279d54..32e9147 100644 --- a/app/tests.py +++ b/app/tests.py @@ -1,6 +1,7 @@ import json, tempfile, os, mock, base64 import pandas as pd from io import StringIO +import re import time from django.test import override_settings @@ -42,6 +43,10 @@ from .models import ( ViewStatistics, ) +from .services import ( + DetailMateriService, +) + from .views import ( DaftarKatalog, DashboardKontributorView, @@ -277,6 +282,20 @@ class DaftarKatalogPerKontributorTest(TestCase): class DetailMateriTest(TestCase): + def _get_materi_info_html(self, info_name, info_value): + info_html = '<div class="info" id="1"><dl class="col col-4">' + info_html += f'<dt class="info-name">{info_name}</dt>' + '</dl><dd>' + info_html += f'<p class="info-content">{info_value}</p>' + '</dd></div>' + return info_html + + def check_materi_info_in_html(self, info_name, info_value, html_content): + expected_content = self._get_materi_info_html(info_name, info_value) + self.assertIn(expected_content, re.sub(">\s*<","><", html_content)) + + def check_materi_info_not_in_html(self, info_name, info_value, html_content): + expected_content = self._get_materi_info_html(info_name, info_value) + self.assertNotIn(expected_content, re.sub(">\s*<","><", html_content)) + def setUp(self): self.client = Client() self.admin_credential = { @@ -302,11 +321,19 @@ class DetailMateriTest(TestCase): "ExampleCover921.jpg", b"Test file") self.content = SimpleUploadedFile("ExampleFile921.pdf", b"Test file") - Materi(title="Materi 1", author="Agas", uploader=self.contributor, - publisher="Kelas SC", descriptions="Deskripsi Materi 1", - status="APPROVE", cover=self.cover, content=self.content).save() - self.materi1 = Materi.objects.first() + self.materi1 = Materi.objects.create(title="Materi 1", author="Agas", + uploader=self.contributor, publisher="Kelas SC", + descriptions="Deskripsi Materi 1", status="APPROVE", + cover=self.cover, content=self.content) + self.materi2 = Materi.objects.create(title="Materi 2", author="Agad", + uploader=self.contributor, publisher="Kelas SM", + descriptions="Deskripsi Materi 2", status="APPROVE", + cover=self.cover, content=self.content) self.url = "/materi/" + str(self.materi1.id) + "/" + self.download_url1 = self.url + "unduh" + self.url2 = "/materi/" + str(self.materi2.id) + "/" + self.download_url2 = self.url2 + "unduh" + self.dcount_info_name = "Jumlah Download" self.materi_with_published_date = Materi.objects.create(title="Materi 1", author="Agas", uploader=self.contributor, publisher="Kelas SC", descriptions="Deskripsi Materi 1", @@ -698,6 +725,95 @@ class DetailMateriTest(TestCase): self.assertEqual(last_url, '/materi/%d/' % self.materi1.id) self.assertEqual(status_code, 302) + def test_download_count_is_in_init_context(self): + context = {} + DetailMateriService.init_materi_download_count(context, self.materi1) + self.assertIn('materi_download_count', context.keys()) + + def test_download_count_is_integer(self): + context = {} + DetailMateriService.init_materi_download_count(context, self.materi1) + self.assertEqual(type(context['materi_download_count']), int) + + def test_download_count_when_no_download(self): + context = {} + DetailMateriService.init_materi_download_count(context, self.materi1) + self.assertEqual(context['materi_download_count'], 0) + + def test_download_count_when_single_download(self): + self.client.get(self.download_url1) + context = {} + DetailMateriService.init_materi_download_count(context, self.materi1) + self.assertEqual(context['materi_download_count'], 1) + + def test_download_count_when_multiple_download(self): + self.client.get(self.download_url1) + self.client.get(self.download_url1) + self.client.get(self.download_url1) + context = {} + DetailMateriService.init_materi_download_count(context, self.materi1) + self.assertEqual(context['materi_download_count'], 3) + + def test_different_material_has_different_download_count(self): + self.client.get(self.download_url1) + self.client.get(self.download_url1) + self.client.get(self.download_url1) + + self.client.get(self.download_url2) + self.client.get(self.download_url2) + + context1 = {} + context2 = {} + DetailMateriService.init_materi_download_count(context1, self.materi1) + DetailMateriService.init_materi_download_count(context2, self.materi2) + self.assertNotEqual(context1['materi_download_count'], context2['materi_download_count']) + self.assertEqual(context1['materi_download_count'], 3) + self.assertEqual(context2['materi_download_count'], 2) + + def test_download_count_displayed_on_template_when_no_download(self): + response = self.client.get(self.url) + html = response.content.decode("utf-8") + self.check_materi_info_in_html(self.dcount_info_name, 0, html) + + def test_download_count_displayed_on_template_when_single_download(self): + self.client.get(self.download_url1) + + response = self.client.get(self.url) + html = response.content.decode("utf-8") + self.check_materi_info_in_html(self.dcount_info_name, 1, html) + + def test_download_count_displayed_on_template_when_multiple_download(self): + self.client.get(self.download_url1) + self.client.get(self.download_url1) + self.client.get(self.download_url1) + self.client.get(self.download_url1) + + response = self.client.get(self.url) + html = response.content.decode("utf-8") + self.check_materi_info_in_html(self.dcount_info_name, 4, html) + + def test_different_material_has_different_download_count_on_templates(self): + self.client.get(self.download_url1) + self.client.get(self.download_url1) + + self.client.get(self.download_url2) + self.client.get(self.download_url2) + self.client.get(self.download_url2) + self.client.get(self.download_url2) + + response = self.client.get(self.url) + response2 = self.client.get(self.url2) + + html = response.content.decode("utf-8") + html2 = response2.content.decode("utf-8") + + dcount_materi1 = self.materi1.unduh.all().count() + dcount_materi2 = self.materi2.unduh.all().count() + + self.check_materi_info_in_html(self.dcount_info_name, dcount_materi1, html) + self.check_materi_info_not_in_html(self.dcount_info_name, dcount_materi2, html) + self.check_materi_info_in_html(self.dcount_info_name, dcount_materi2, html2) + self.check_materi_info_not_in_html(self.dcount_info_name, dcount_materi1, html2) class PostsViewTest(TestCase): diff --git a/app/views.py b/app/views.py index 05a15a9..94a3095 100644 --- a/app/views.py +++ b/app/views.py @@ -112,6 +112,7 @@ class DetailMateri(TemplateView): DetailMateriService.init_context_data(context, materi, self.request.session) published_date = DetailMateriService.set_published_date(materi) DetailMateriService.init_citation_and_materi_rating(context, materi, published_date, self.request) + DetailMateriService.init_materi_download_count(context, materi) if self.request.user.is_authenticated: materi_rating = Rating.objects.filter(materi=materi, user=self.request.user).first() -- GitLab