diff --git a/app/templates/app/includes/sidebar.html b/app/templates/app/includes/sidebar.html index ff0bb3adb420af54f491adcdc994bd422f1991d6..69425f3e24b473e9953c78d53353d3d128c23dda 100644 --- a/app/templates/app/includes/sidebar.html +++ b/app/templates/app/includes/sidebar.html @@ -27,7 +27,7 @@ </li> <li class="nav-item"> - <a class="nav-link" href="#"> + <a class="nav-link" href="{% url 'stats' %}"> <span>Statisik Materi</span> </a> </li> diff --git a/app/templates/statistik.html b/app/templates/statistik.html new file mode 100644 index 0000000000000000000000000000000000000000..839895c7ddb791c8f492088381767aa6560d70de --- /dev/null +++ b/app/templates/statistik.html @@ -0,0 +1,72 @@ +{% extends 'app/base_dashboard.html' %} +{% load static %} + +{% block title %} +<title>Unggah Materi dari Excel | Digipus</title> +{% endblock %} + +{% block stylesheets %} +<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js" + integrity="sha512-d9xgZrVZpmmQlfonhQUvTR7lMPtO7NkZMkA0ABN3PHCbKA5nqylQ/yWlFAyY6hYgdF1Qh6nYiuADWwKB4C2WSw==" + crossorigin="anonymous"></script> +<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.css" + integrity="sha512-/zs32ZEJh+/EO2N1b0PEdoA10JkdC3zJ8L5FTiQu82LR9S/rOQNfQN7U59U9BC12swNeRAz3HSzIL2vpp4fv3w==" + crossorigin="anonymous" /> +{% endblock %} + +{% block content %} + + +<div class="container"> + + <h1 class="h3 mb-2 text-gray-800">Summary Materi per Kategori</h1> + + <div class="card-body"> + <div class="table-responsive"> + <table class="table table-bordered"> + <thead> + <th>Kategori</th> + <th>Jumlah Materi</th> + </thead> + <tbody> + {% for s in stats %} + <tr> + <td>{{s.name}}</td> + <td>{{s.num}}</td> + </tr> + {% endfor %} + </tbody> + </table> + </div> + </div> + + <div class="col-lg-6 mx-auto"> + <canvas id="myChart" width="400" height="400"></canvas> + </div> + +</div> + +<script type="text/javascript"> + + function displayChart(data) { + var ctx = document.getElementById('myChart').getContext('2d'); + + var myChart = new Chart(ctx, { + type: 'pie', + data: data + }); + } + + + document.addEventListener("DOMContentLoaded", function(){ + fetch('/stats?data=json') + .then(function(response) { + return response.json() + }) + .then(function(json) { + displayChart(json) + }) + }); + +</script> +{% endblock %} \ No newline at end of file diff --git a/app/tests.py b/app/tests.py index 9f10c73f27f528bd814fb834b1084391f60514d9..f69dc13a9ac0415d172b9a9e351395877fa5ae98 100644 --- a/app/tests.py +++ b/app/tests.py @@ -3,6 +3,7 @@ import pandas as pd from io import StringIO import re import time +import random from django.test import override_settings from bs4 import BeautifulSoup @@ -3443,3 +3444,53 @@ class MateriRecommendationTest(TestCase): list = [int(id) for id in re.findall(r"Materi\s(\d+)[^\d]", response.content.decode())] self.assertEqual(list, [1, 2]) +class MateriStatsTest(TestCase): + + def setUp(self): + self.credential = { + 'email':"kontributor@gov.id", + 'password':"P@ssw0rd", + } + + self.path = '/stats/' + self.path_json = '/stats/?data=json' + self.header = 'Summary Materi per Kategori' + + self.contributor = User.objects.create_contributor(**self.credential, name="kontributor") + self.client = Client() + + categories = [] + for i in range(10): + cat = Category(name=f'Cat{i}', description=f'Cat{i} description') + cat.save() + categories.append(cat) + + for i in range(10): + for j in range(random.randint(1, 10)): + m = Materi(title=f'Title{i}-{j}') + m.save() + m.categories.add(categories[i]) + m.save() + + + def test_stats_has_correct_template(self): + self.client.login(**self.credential) + response = self.client.get(self.path) + self.assertTemplateUsed(response, 'statistik.html') + + def test_stats_as_authenticated(self): + self.client.login(**self.credential) + response = self.client.get(self.path) + self.assertContains(response, self.header) + + def test_stats_as_anonymous(self): + response = self.client.get(self.path) + self.assertEqual(response.status_code, 302) #redirect + response = self.client.get(self.path_json) + self.assertEqual(response.status_code, 302) #redirect + + def test_stats_api_correct_data(self): + self.client.login(**self.credential) + response = self.client.get(self.path_json) + jobj = json.loads(response.content) + self.assertEqual(len(jobj['labels']), 6) diff --git a/app/urls.py b/app/urls.py index a8c7281cbdd6821bf7eace5f939520e099f53ad5..3e0df237fcb184cf4884b2f39c0245bb54542825 100644 --- a/app/urls.py +++ b/app/urls.py @@ -2,7 +2,7 @@ from django.contrib.auth import views as auth_views from django.urls import path, re_path from app import views -from app.views import (DashboardKontributorView, ProfilView, +from app.views import (DashboardKontributorView, ProfilView, StatisticsView, SuksesLoginAdminView, SuksesLoginKontributorView, DownloadHistoryView, SuntingProfilView, UploadMateriHTML, UploadMateriView, UploadMateriExcelView, PostsView, ReqMateriView, KatalogPerKontributorView, MateriFavorite, PasswordChangeViews, password_success, SubmitVisitorView) @@ -41,4 +41,5 @@ urlpatterns = [ path("password_success/", views.password_success, name="password_success"), path("given-rating/", views.see_given_rating, name="see_given_rating"), path("submit-visitor/", SubmitVisitorView.as_view(), name="submit-visitor"), + path("stats/", StatisticsView.as_view(), name="stats"), ] diff --git a/app/views.py b/app/views.py index a0062ed070c2065cc77c3e37757c749b70f470d1..d0dd5bb0206e04485f95cd88142d1b5d67827030 100644 --- a/app/views.py +++ b/app/views.py @@ -12,7 +12,7 @@ from django.contrib.auth.views import PasswordChangeView from django.core.exceptions import PermissionDenied, FieldError from django.core.mail import send_mail from django.core.paginator import Paginator -from django.db.models import Q, Avg +from django.db.models import Q, Avg, Count from django.http import (Http404, HttpResponse, HttpResponseRedirect, JsonResponse) from django.shortcuts import get_object_or_404, redirect @@ -780,3 +780,60 @@ class SubmitVisitorView(TemplateView): return JsonResponse({"success": False, "msg": "Missing parameter"}) SubmitVisitor(msg=title, user_id=user_id, email=email).save() return JsonResponse({"success": True, "msg": "Buku tamu berhasil ditambahkan"}) + +class StatisticsView(TemplateView): + template_name = "statistik.html" + + def dispatch(self, request, *args, **kwargs): + if request.user.is_authenticated == False: + return HttpResponseRedirect("/login/") + return super(StatisticsView, self).dispatch(request, *args, **kwargs) + + def get_stat_json(self): + query = Category.objects.annotate(num=Count('materi')).order_by('-num') + + # Take maximum 10 Category + result = [] + for e in query: + if len(result) >= 6: + break + else: + result.append(e) + + chart_data = { + 'labels': [e.name for e in result], + 'datasets': [{ + 'label': 'Jumlah Materi per Kategori', + 'data': [e.num for e in result], + 'backgroundColor': [ + 'rgba(255, 99, 132, 0.2)', + 'rgba(54, 162, 235, 0.2)', + 'rgba(255, 206, 86, 0.2)', + 'rgba(75, 192, 192, 0.2)', + 'rgba(153, 102, 255, 0.2)', + 'rgba(255, 159, 64, 0.2)' + ], + 'borderColor': [ + 'rgba(255, 99, 132, 1)', + 'rgba(54, 162, 235, 1)', + 'rgba(255, 206, 86, 1)', + 'rgba(75, 192, 192, 1)', + 'rgba(153, 102, 255, 1)', + 'rgba(255, 159, 64, 1)' + ], + 'borderWidth': 1 + }] + } + return chart_data + + def get(self, request, *args, **kwargs): + if request.GET.get('data') == 'json': + return JsonResponse(self.get_stat_json()) + + else: + context = self.get_context_data(**kwargs) + + query = Category.objects.annotate(num=Count('materi')) + context['stats'] = query + + return self.render_to_response(context)