diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 56c0fe222c91070572fc79fbe4a6e8afe6d12ea4..40af2c49879743f0f0fee25367178727bb23dd1b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,6 +16,32 @@ pylint: paths: - ./pylint/ +.development: + variables: + IMAGE_SCOPE_TAG: "$CI_COMMIT_BRANCH" + except: + - master + environment: development + +.production: + variables: + IMAGE_SCOPE_TAG: stable + only: + - master + environment: production + +.docker-image: + stage: deploy + image: + name: gcr.io/kaniko-project/executor:debug + entrypoint: [ "" ] + variables: + CONTEXT: $CI_PROJECT_DIR + script: + - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json + - /kaniko/executor --context ${CONTEXT} --dockerfile ${CONTEXT}/Dockerfile --destination ${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG} --destination ${CI_REGISTRY_IMAGE}:${IMAGE_SCOPE_TAG} + + UnitTest: services: - postgres:alpine @@ -68,3 +94,14 @@ Deployment: environment: name: staging url: $HEROKU_APP_HOST_STAGING + +Dev Docker Image: + extends: + - .docker-image + - .development + allow_failure: true + +Prod Docker Image: + extends: + - .docker-image + - .production \ No newline at end of file diff --git a/app/migrations/0025_review.py b/app/migrations/0025_review.py index 8a5bf86072e59f8ee86b9a26f6d303ba77a7a6f5..79b7b89a4f655cf6851c7265539222047eef56e1 100644 --- a/app/migrations/0025_review.py +++ b/app/migrations/0025_review.py @@ -1,4 +1,4 @@ -# Generated by Django 3.1 on 2020-10-29 13:03 +# Generated by Django 3.1 on 2020-10-29 11:22 import app.models from django.conf import settings diff --git a/app/services.py b/app/services.py index 538d8f9bf41b7d648a35e7a48b00b2ff202adca3..d83bf00dd30f52daf7129dc26df2bf13068e3db4 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 fb1b1d031eb7d3dc493ca716b83bfafbb1233a78..278c5decd9fd975e8bdac221ee5b7f70777737fa 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 6279d54cf2d6070b5bcd84099e1c80f5f8332c6e..2eaf4475b33125d3a34db7707da0a6db11d6c28f 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, @@ -62,6 +67,7 @@ from .views import ( ) from app.forms import SuntingProfilForm, year_choices from app.utils.fileManagementUtil import get_random_filename, remove_image_exifdata +from app.utils.PasswordValidator import PasswordPolicyValidator ERROR_403_MESSAGE = "Kamu harus login untuk mengakses halaman ini" @@ -277,6 +283,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 +322,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 +726,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): @@ -2886,3 +3003,32 @@ class SeeRatedMateriByUser(TestCase): self.assertEqual(list(response.context['rating_list']), [self.rating_test_2, self.rating_test_1, self.rating_test_3]) +class PasswordValidatorPolicyTest(TestCase): + def setUp(self): + self.password_no_lowercase = "PASSW0RD!" + self.password_no_uppercase = "passw0rd!" + self.password_no_digit = "Password!" + self.password_no_special_char = "Passw0rd" + self.password_length_lower_than_8 = "P4ss!" + self.password_enforcing_policy = "Passw0rd!" + self.validator = PasswordPolicyValidator() + + def test_using_password_no_lowercase(self): + self.assertRaises(ValidationError, self.validator.validate, self.password_no_lowercase) + + def test_using_password_no_upprcase(self): + self.assertRaises(ValidationError, self.validator.validate, self.password_no_uppercase) + + def test_using_password_no_digit(self): + self.assertRaises(ValidationError, self.validator.validate, self.password_no_digit) + + def test_using_password_no_special_char(self): + self.assertRaises(ValidationError, self.validator.validate, self.password_no_special_char) + + def test_using_password_with_length_less_than_8(self): + self.assertRaises(ValidationError, self.validator.validate, self.password_length_lower_than_8) + + def test_using_password_using_correct_policy(self): + self.assertEquals(self.validator.validate(self.password_enforcing_policy), None) + + \ No newline at end of file diff --git a/app/utils/PasswordValidator.py b/app/utils/PasswordValidator.py new file mode 100644 index 0000000000000000000000000000000000000000..4d7a5a3062990f09c99833c7269d77d56f14987f --- /dev/null +++ b/app/utils/PasswordValidator.py @@ -0,0 +1,30 @@ +import string +from django.core.exceptions import ValidationError + + +class PasswordPolicyValidator(object): + def validate(self, password, user=None): + if sum(c.isdigit() for c in password) < 1: + msg = 'Password must contain at least 1 number.' + raise ValidationError(msg) + + if not any(c.isupper() for c in password): + msg = 'Password must contain at least 1 uppercase letter.' + raise ValidationError(msg) + + if not any(c.islower() for c in password): + msg = 'Password must contain at least 1 lowercase letter.' + raise ValidationError(msg) + + if not any(c for c in password if c in string.punctuation): + msg = 'Password must contain at least 1 special letter.' + raise ValidationError(msg) + + if len(password) < 8 : + msg = 'Password must have at least 8 characters.' + raise ValidationError(msg) + + def get_help_text(self): + return ( + "Password must contains at least 8 character with combination of lower case letter, upper case letter, digit, and symbol." + ) diff --git a/app/views.py b/app/views.py index 7e42bb46e3353cbe63f3e5905b3f2ad61038bd04..94700fbb1c8be342b7c10bfb0bb6eca7d6e0fc37 100644 --- a/app/views.py +++ b/app/views.py @@ -113,6 +113,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() diff --git a/digipus/settings.py b/digipus/settings.py index 6f3add23133069c7552d793518bc22cee7e4e116..5294eb2e6338e868549e9be6b835260f0e4ce2d7 100644 --- a/digipus/settings.py +++ b/digipus/settings.py @@ -127,10 +127,7 @@ STATICFILES_DIRS = (os.path.join(BASE_DIR, "staticfiles"),) AUTH_USER_MODEL = "authentication.User" AUTH_PASSWORD_VALIDATORS = [ - {"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, - {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", }, - {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, - {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, + {"NAME": "app.utils.PasswordValidator.PasswordPolicyValidator", }, ] diff --git a/register/services.py b/register/services.py index 7d2b7971869329a0b4edd6f9336334b16fd5b6a7..7f01dd0a499c851a4f323ab8f36bbfdf144473bd 100644 --- a/register/services.py +++ b/register/services.py @@ -1,20 +1,49 @@ from django.contrib.auth.hashers import make_password +from django.contrib.auth.password_validation import validate_password +from django.core.exceptions import ValidationError class RegistrationService: @staticmethod def create_new_contributor(data, form): + create_result = dict() + create_result["success"] = True new_user = form.save(commit=False) - new_user.password = make_password(data["password"]) - new_user.is_contributor = True - new_user.save() - return new_user + + try: + password = form.cleaned_data['password'] + validate_password(password, new_user) + + new_user.password = make_password(data["password"]) + new_user.is_contributor = True + new_user.save() + create_result["user"] = new_user + except ValidationError as e: + create_result["success"] = False + form.add_error('password', e) + create_result["form"] = form + + return create_result @staticmethod def create_new_admin(data, form): + create_result = dict() + create_result["success"] = True new_user = form.save(commit=False) - new_user.password = make_password(data["password"]) - new_user.is_admin = True - new_user.is_active = False - new_user.save() \ No newline at end of file + + try: + password = form.cleaned_data['password'] + validate_password(password, new_user) + + new_user.password = make_password(data["password"]) + new_user.is_admin = True + new_user.is_active = False + new_user.save() + create_result["user"] = new_user + except ValidationError as e: + create_result["success"] = False + form.add_error('password', e) + create_result["form"] = form + + return create_result \ No newline at end of file diff --git a/register/tests.py b/register/tests.py index 895797942b52f7160515d9d81986cb795e7b8809..c4d4a0b73e3af11f4db86f8d05864ca596787d2a 100644 --- a/register/tests.py +++ b/register/tests.py @@ -10,6 +10,7 @@ from register import views class RegisterPageTest(TestCase): def setUp(self): self.client = Client() + self.password = "Passw0rd!" def test_register_url_is_exist(self): # Positive tests @@ -64,8 +65,8 @@ class RegisterPageTest(TestCase): "alamat": "bekasi", "email": "bob@company.com", "nomor_telpon": "087878726602", - "password": "1234", - "password2": "1234", + "password": self.password, + "password2": self.password, }, ) self.assertEqual(User.objects.all().count(), 1) @@ -80,8 +81,8 @@ class RegisterPageTest(TestCase): "alamat": "bekasi", "email": "bob@company.com", "nomor_telpon": "087878726602", - "password": "1234", - "password2": "12345", + "password": self.password, + "password2": "different passwd", }, ) self.assertEqual(User.objects.all().count(), 0) @@ -97,8 +98,8 @@ class RegisterPageTest(TestCase): "alamat": "bekasi", "email": "bob@company.com", "nomor_telpon": "087878726602", - "password": "1234", - "password2": "1234", + "password": self.password, + "password2": self.password, }, ) self.assertEqual(User.objects.all().count(), 1) @@ -111,8 +112,8 @@ class RegisterPageTest(TestCase): "alamat": "bekasi", "email": "bob@company.com", "nomor_telpon": "087878726602", - "password": "1234", - "password2": "1234", + "password": self.password, + "password2": self.password, }, ) self.assertEqual(User.objects.all().count(), 1) @@ -129,8 +130,8 @@ class RegisterPageTest(TestCase): "alamat": "bekasi", "email": "bob@company.com", "nomor_telpon": "087878726601", - "password": "123456", - "password2": "123456", + "password": self.password, + "password2": self.password, }, ) self.assertEqual(User.objects.all().count(), 1) @@ -144,8 +145,8 @@ class RegisterPageTest(TestCase): "alamat": "bekasi", "email": "budi@company.com", "nomor_telpon": "087878726602", - "password": "123456", - "password2": "123456", + "password": self.password, + "password2": self.password, }, ) self.assertEqual(User.objects.all().count(), 1) @@ -162,8 +163,8 @@ class RegisterPageTest(TestCase): "alamat": "bekasi", "email": "bob@company.com", "nomor_telpon": "087878726602", - "password": "123456", - "password2": "123456", + "password": self.password, + "password2": self.password, }, ) self.assertEqual(User.objects.all().count(), 1) @@ -177,8 +178,8 @@ class RegisterPageTest(TestCase): "alamat": "bekasi", "email": "budi@company.com", "nomor_telpon": "087878726602", - "password": "123456", - "password2": "123456", + "password": self.password, + "password2": self.password, }, ) self.assertEqual(User.objects.all().count(), 1) @@ -195,17 +196,102 @@ class RegisterPageTest(TestCase): "alamat": "bekasi", "email": "bob@company.com", "nomor_telpon": "abcdefghijkl", - "password": "1234", - "password2": "12345", + "password": self.password, + "password2": self.password, }, ) self.assertEqual(User.objects.all().count(), 0) self.assertIn(b"Hanya masukkan angka", response.content) + + def test_create_user_weak_password_no_lowercase(self): + response = self.client.post( + "/registrasi/", + { + "name": "bob", + "instansi": "university", + "nik": "3201234567890001", + "alamat": "bekasi", + "email": "bob@company.com", + "nomor_telpon": "087878726602", + "password": "PASSW0RD!", + "password2": "PASSW0RD!", + }, + ) + self.assertEqual(User.objects.all().count(), 0) + self.assertIn(b"Password must contain at least 1 lowercase letter", response.content) + + def test_create_user_weak_password_no_uppercase(self): + response = self.client.post( + "/registrasi/", + { + "name": "bob", + "instansi": "university", + "nik": "3201234567890001", + "alamat": "bekasi", + "email": "bob@company.com", + "nomor_telpon": "087878726602", + "password": "passw0rd!", + "password2": "passw0rd!", + }, + ) + self.assertEqual(User.objects.all().count(), 0) + self.assertIn(b"Password must contain at least 1 uppercase letter", response.content) + + def test_create_user_weak_password_no_special_char(self): + response = self.client.post( + "/registrasi/", + { + "name": "bob", + "instansi": "university", + "nik": "3201234567890001", + "alamat": "bekasi", + "email": "bob@company.com", + "nomor_telpon": "087878726602", + "password": "Passw0rd", + "password2": "Passw0rd", + }, + ) + self.assertEqual(User.objects.all().count(), 0) + self.assertIn(b"Password must contain at least 1 special letter", response.content) + + def test_create_user_weak_password_no_number(self): + response = self.client.post( + "/registrasi/", + { + "name": "bob", + "instansi": "university", + "nik": "3201234567890001", + "alamat": "bekasi", + "email": "bob@company.com", + "nomor_telpon": "087878726602", + "password": "Password!", + "password2": "Password!", + }, + ) + self.assertEqual(User.objects.all().count(), 0) + self.assertIn(b"Password must contain at least 1 number", response.content) + + def test_create_user_weak_password_less_than_8_chars(self): + response = self.client.post( + "/registrasi/", + { + "name": "bob", + "instansi": "university", + "nik": "3201234567890001", + "alamat": "bekasi", + "email": "bob@company.com", + "nomor_telpon": "087878726602", + "password": "P4ss!", + "password2": "P4ss!", + }, + ) + self.assertEqual(User.objects.all().count(), 0) + self.assertIn(b"Password must have at least 8 characters", response.content) class RegisterAdminTest(TestCase): def setUp(self): self.client = Client() - self.random_password = id_generator() + self.password = "Passw0rd!" def test_register_url_is_exist(self): # Positive tests @@ -260,8 +346,8 @@ class RegisterAdminTest(TestCase): "alamat": "bekasi", "email": "bob@company.com", "nomor_telpon": "087878726602", - "password": "1234", - "password2": "1234", + "password": self.password, + "password2": self.password, }, ) self.assertEqual(User.objects.all().count(), 1) @@ -276,8 +362,8 @@ class RegisterAdminTest(TestCase): "alamat": "bekasi", "email": "bob@company.com", "nomor_telpon": "087878726602", - "password": "1234", - "password2": "12345", + "password": self.password, + "password2": "different passwd", }, ) self.assertEqual(User.objects.all().count(), 0) @@ -293,8 +379,8 @@ class RegisterAdminTest(TestCase): "alamat": "bekasi", "email": "bob@company.com", "nomor_telpon": "087878726602", - "password": self.random_password, - "password2": self.random_password, + "password": self.password, + "password2": self.password, }, ) self.assertEqual(User.objects.all().count(), 1) @@ -307,8 +393,8 @@ class RegisterAdminTest(TestCase): "alamat": "bekasi", "email": "bob@company.com", "nomor_telpon": "087878726602", - "password": self.random_password, - "password2": self.random_password, + "password": self.password, + "password2": self.password, }, ) self.assertEqual(User.objects.all().count(), 1) @@ -325,8 +411,8 @@ class RegisterAdminTest(TestCase): "alamat": "bekasi", "email": "bob@company.com", "nomor_telpon": "087878726602", - "password": self.random_password, - "password2": self.random_password, + "password": self.password, + "password2": self.password, }, ) self.assertEqual(User.objects.filter(name="bob").get().is_active, False) @@ -341,8 +427,8 @@ class RegisterAdminTest(TestCase): "alamat": "bekasi", "email": "bob@company.com", "nomor_telpon": "087878726602", - "password": self.random_password, - "password2": self.random_password, + "password": self.password, + "password2": self.password, }, ) self.assertEqual(User.objects.count(), 1) @@ -358,8 +444,8 @@ class RegisterAdminTest(TestCase): "alamat": "bekasi", "email": "bob@company.com", "nomor_telpon": "087878726601", - "password": self.random_password, - "password2": self.random_password, + "password": self.password, + "password2": self.password, }, ) self.assertEqual(User.objects.all().count(), 1) @@ -372,8 +458,8 @@ class RegisterAdminTest(TestCase): "alamat": "bekasi", "email": "bob@company.com", "nomor_telpon": "087878726602", - "password": self.random_password, - "password2": self.random_password, + "password": self.password, + "password2": self.password, }, ) self.assertEqual(User.objects.all().count(), 1) @@ -390,8 +476,8 @@ class RegisterAdminTest(TestCase): "alamat": "bekasi", "email": "bob@company.com", "nomor_telpon": "087878726601", - "password": self.random_password, - "password2": self.random_password, + "password": self.password, + "password2": self.password, }, ) self.assertEqual(User.objects.all().count(), 1) @@ -404,8 +490,8 @@ class RegisterAdminTest(TestCase): "alamat": "bekasi", "email": "bob@company.com", "nomor_telpon": "087878726601", - "password": self.random_password, - "password2": self.random_password, + "password": self.password, + "password2": self.password, }, ) self.assertEqual(User.objects.all().count(), 1) @@ -422,9 +508,94 @@ class RegisterAdminTest(TestCase): "alamat": "bekasi", "email": "bob@company.com", "nomor_telpon": "abcdefghij", - "password": self.random_password, - "password2": self.random_password, + "password": self.password, + "password2": self.password, + }, + ) + self.assertEqual(User.objects.all().count(), 0) + self.assertIn(b"Hanya masukkan angka", response.content) + + def test_create_user_weak_password_no_lowercase(self): + response = self.client.post( + "/registrasi/admin/", + { + "name": "bob", + "instansi": "university", + "nik": "3201234567890001", + "alamat": "bekasi", + "email": "bob@company.com", + "nomor_telpon": "087878726602", + "password": "PASSW0RD!", + "password2": "PASSW0RD!", + }, + ) + self.assertEqual(User.objects.all().count(), 0) + self.assertIn(b"Password must contain at least 1 lowercase letter", response.content) + + def test_create_user_weak_password_no_uppercase(self): + response = self.client.post( + "/registrasi/admin/", + { + "name": "bob", + "instansi": "university", + "nik": "3201234567890001", + "alamat": "bekasi", + "email": "bob@company.com", + "nomor_telpon": "087878726602", + "password": "passw0rd!", + "password2": "passw0rd!", + }, + ) + self.assertEqual(User.objects.all().count(), 0) + self.assertIn(b"Password must contain at least 1 uppercase letter", response.content) + + def test_create_user_weak_password_no_special_char(self): + response = self.client.post( + "/registrasi/admin/", + { + "name": "bob", + "instansi": "university", + "nik": "3201234567890001", + "alamat": "bekasi", + "email": "bob@company.com", + "nomor_telpon": "087878726602", + "password": "Passw0rd", + "password2": "Passw0rd", + }, + ) + self.assertEqual(User.objects.all().count(), 0) + self.assertIn(b"Password must contain at least 1 special letter", response.content) + + def test_create_user_weak_password_no_number(self): + response = self.client.post( + "/registrasi/admin/", + { + "name": "bob", + "instansi": "university", + "nik": "3201234567890001", + "alamat": "bekasi", + "email": "bob@company.com", + "nomor_telpon": "087878726602", + "password": "Password!", + "password2": "Password!", + }, + ) + self.assertEqual(User.objects.all().count(), 0) + self.assertIn(b"Password must contain at least 1 number", response.content) + + def test_create_user_weak_password_less_than_8_chars(self): + response = self.client.post( + "/registrasi/admin/", + { + "name": "bob", + "instansi": "university", + "nik": "3201234567890001", + "alamat": "bekasi", + "email": "bob@company.com", + "nomor_telpon": "087878726602", + "password": "P4ss!", + "password2": "P4ss!", }, ) self.assertEqual(User.objects.all().count(), 0) - self.assertIn(b"Hanya masukkan angka", response.content) \ No newline at end of file + self.assertIn(b"Password must have at least 8 characters", response.content) \ No newline at end of file diff --git a/register/views.py b/register/views.py index d54425ead396c475f3a35d6d8b2b0580fb5a8b7d..e9b3ca41a76600fbc0d5f714997f161cd11741ee 100644 --- a/register/views.py +++ b/register/views.py @@ -18,8 +18,13 @@ class index(TemplateView): data = request.POST.copy() form = UserForm(request.POST) if form.is_valid(): - new_user = RegistrationService.create_new_contributor(data, form) - login(request, new_user) + create_user_service = RegistrationService.create_new_contributor(data, form) + if not create_user_service["success"]: + context = self.get_context_data(**kwargs) + context["form"] = create_user_service["form"] + return self.render_to_response(context) + + login(request, create_user_service["user"]) return HttpResponseRedirect("/sukses-kontributor/") else: context = self.get_context_data(**kwargs) @@ -46,7 +51,12 @@ class RegistrasiAdmin(TemplateView): context = self.get_context_data(**kwargs) context["form"] = form if form.is_valid(): - RegistrationService.create_new_admin(data, form) + create_user_service = RegistrationService.create_new_admin(data, form) + if not create_user_service["success"]: + context = self.get_context_data(**kwargs) + context["form"] = create_user_service["form"] + return self.render_to_response(context) + context["message"] = "Please wait for our internal team to accept your admin account" return self.render_to_response(context) return self.render_to_response(context)