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)