diff --git a/app/forms.py b/app/forms.py index 64a096e421bf1aacaa9b648b8d869f1c0adfb4e3..84facd1f2e25e18920754b7cd44a6396e7e1f4fe 100644 --- a/app/forms.py +++ b/app/forms.py @@ -1,6 +1,6 @@ from django import forms -from app.models import Materi,Category +from app.models import Materi, Category, RatingContributor from authentication.models import User @@ -43,3 +43,21 @@ class SuntingProfilForm(forms.ModelForm): self.fields["email"].widget.attrs["readonly"] = True + + +class RatingContributorForm(forms.ModelForm): + class Meta: + model = RatingContributor + fields = ['score', 'user'] + SCORE_CHOICE = ( + ('', 'Select score'), + ('1', '1'), # First one is the value of select option and second is the displayed value in option + ('2', '2'), + ('3', '3'), + ('4', '4'), + ('5', '5'), + ) + widgets = { + 'score': forms.Select(choices=SCORE_CHOICE, attrs={'class': 'form-control'},), + 'user': forms.HiddenInput() + } diff --git a/app/migrations/0016_ratingcontributor.py b/app/migrations/0016_ratingcontributor.py new file mode 100644 index 0000000000000000000000000000000000000000..86d787f0b6a357456c259f9842dfd7e3b7e49415 --- /dev/null +++ b/app/migrations/0016_ratingcontributor.py @@ -0,0 +1,25 @@ +# Generated by Django 3.1.1 on 2020-10-05 14:41 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('app', '0015_reqmaterial'), + ] + + operations = [ + migrations.CreateModel( + name='RatingContributor', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('timestamp', models.DateTimeField(auto_now=True)), + ('score', models.IntegerField()), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/app/migrations/0017_auto_20201005_2145.py b/app/migrations/0017_auto_20201005_2145.py new file mode 100644 index 0000000000000000000000000000000000000000..732caef72a1b44acef70e15c4d29b91a5df106b2 --- /dev/null +++ b/app/migrations/0017_auto_20201005_2145.py @@ -0,0 +1,19 @@ +# Generated by Django 3.1.1 on 2020-10-05 14:45 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('app', '0016_ratingcontributor'), + ] + + operations = [ + migrations.AlterField( + model_name='ratingcontributor', + name='score', + field=models.PositiveIntegerField(validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(5)]), + ), + ] diff --git a/app/models.py b/app/models.py index 12366f8ed831dff40a63c675c93e5da4d96bfcd8..54e05f404d9b68827b86d9ce247a2f7873caa26c 100644 --- a/app/models.py +++ b/app/models.py @@ -1,6 +1,7 @@ import random from django.core.exceptions import ValidationError +from django.core.validators import MinValueValidator, MaxValueValidator from django.db import models from django.utils import timezone @@ -133,3 +134,15 @@ class Rating(models.Model): class Meta: unique_together = ["materi", "user"] + + +class RatingContributor(models.Model): + timestamp = models.DateTimeField(auto_now=True) + score = models.PositiveIntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)]) + user = models.ForeignKey(User, on_delete=models.CASCADE) + + def save(self, force_insert=False, force_update=False, using=None, update_fields=None): + if 1 <= self.score <= 5: + super().save(force_insert, force_update, using, update_fields) + else: + raise ValidationError("Rating score must be integer between 1-5") \ No newline at end of file diff --git a/app/templates/app/katalog_kontri.html b/app/templates/app/katalog_kontri.html index 3ddaf130261abbbb2ccc0c546f855e93b876f14d..7ccaed1d156846d850f12bae96ae1a935295d6f0 100644 --- a/app/templates/app/katalog_kontri.html +++ b/app/templates/app/katalog_kontri.html @@ -86,6 +86,8 @@ </table> </div> </div> + <div class="row"><form method="post">{{ form_rating }} {% csrf_token %} + <button type="submit" class="form-control" style="margin-top: 1rem">Submit</button></form> </div> </div> </header> diff --git a/app/tests.py b/app/tests.py index adf63c619e866fda2bfc9044834a3dec7961a9d2..5d6b477001e452be1afdb756e04ee6707860c3a2 100644 --- a/app/tests.py +++ b/app/tests.py @@ -6,16 +6,15 @@ from django.contrib.auth import get_user_model from django.core.exceptions import PermissionDenied, ValidationError from django.core.files.uploadedfile import SimpleUploadedFile from django.core.management import call_command -from django.db import IntegrityError -from django.test import Client, TestCase +from django.test import Client, TestCase, TransactionTestCase from django.urls import resolve +from django.db.utils import IntegrityError from administration.models import VerificationSetting, VerificationReport from administration.utils import id_generator -from app.forms import SuntingProfilForm from app.views import UploadMateriView, add_rating_materi from authentication.models import User -from .models import Category, Comment, Materi, Like, Rating, ReqMaterial +from .models import Category, Comment, Materi, Like, Rating, ReqMaterial, RatingContributor from .views import (DaftarKatalog, DashboardKontributorView, DetailMateri, ProfilKontributorView, SuksesLoginAdminView, SuksesLoginKontributorView, SuntingProfilView, @@ -1404,3 +1403,42 @@ class RequestMateriTest(TestCase): self.assertIn('Missing parameter', response.content.decode()) self.client.logout() + + +class RatingContributorTest(TransactionTestCase): + def setUp(self): + self.contributor_credential = { + "email": "kontributor@gov.id", + "password": id_generator() + } + self.contributor = get_user_model().objects.create_user( + **self.contributor_credential, name="Kontributor", is_contributor=True + ) + + def test_add_rating_contributor(self): + RatingContributor.objects.create(score=3, user=self.contributor) + self.assertEqual(1, RatingContributor.objects.count()) + + def test_add_rating_contributor_should_failed_when_negative(self): + with self.assertRaises(ValidationError): + RatingContributor.objects.create(score=-1, user=self.contributor) + self.assertEqual(0, RatingContributor.objects.count()) + + def test_add_rating_contributor_should_failed_when_bigger_than_five(self): + with self.assertRaises(ValidationError): + RatingContributor.objects.create(score=6, user=self.contributor) + self.assertEqual(0, RatingContributor.objects.count()) + + def test_submit_form_correct_rating_contributor_should_added(self): + url = f"/profil/{self.contributor.email}/" + self.client.post(url, data={"user": self.contributor.id, "score": 5}) + self.assertEqual(1, RatingContributor.objects.filter(user=self.contributor.id).count()) + self.client.post(url, data={"user": self.contributor.id, "score": 1}) + self.assertEqual(2, RatingContributor.objects.filter(user=self.contributor.id).count()) + + def test_submit_form_not_correct_rating_contributor_should__not_added(self): + url = f"/profil/{self.contributor.email}/" + self.client.post(url, data={"user": self.contributor.id, "score": 6}) + self.assertEqual(0, RatingContributor.objects.filter(user=self.contributor.id).count()) + self.client.post(url, data={"user": self.contributor.id, "score": 0}) + self.assertEqual(0, RatingContributor.objects.filter(user=self.contributor.id).count()) diff --git a/app/views.py b/app/views.py index 8a5ef310d506b74c73c38bfef6000f9e5b7a1302..13e80ff4df9afb0ea7ed572459776f4f49305de7 100644 --- a/app/views.py +++ b/app/views.py @@ -9,16 +9,18 @@ from django.core.paginator import Paginator from django.db.models import Q, Count from django.http import (Http404, HttpResponse, HttpResponseRedirect, JsonResponse) -from django.shortcuts import get_object_or_404 +from django.shortcuts import get_object_or_404, redirect from django.template import loader from django.views.generic import TemplateView from administration.models import VerificationReport -from app.forms import SuntingProfilForm, UploadMateriForm -from app.models import Category, Comment, Materi, Like, ViewStatistics, DownloadStatistics, ReqMaterial, Rating +from app.forms import SuntingProfilForm, UploadMateriForm, RatingContributorForm +from app.models import Category, Comment, Materi, Like, ViewStatistics, DownloadStatistics, ReqMaterial, Rating, \ + RatingContributor from app.utils.fileManagementUtil import get_random_filename, remove_image_exifdata from authentication.models import User import django +from django.contrib import messages class DaftarKatalog(TemplateView): @@ -95,9 +97,16 @@ class KatalogPerKontributorView(TemplateView): page_number = request.GET.get('page') materi_list_by_page = paginator.get_page(page_number) context["materi_list"] = materi_list_by_page - + contributor = get_object_or_404(User, email=kwargs["email"]) + context["form_rating"] = RatingContributorForm(initial={'user': contributor}) return self.render_to_response(context=context) + def post(self, request, *args, **kwargs): + data = RatingContributorForm(request.POST) + if data.is_valid(): + data.save() + return redirect('katalog-per-kontributor', email=kwargs['email']) + class DetailMateri(TemplateView): template_name = "app/detail_materi.html"