Sprint 3, Week — 4: Implementasi decorator pattern + unit testing

Decorator pattern merupakan salah satu dari banyak design pattern, django atau python menerapkan decorator pattern ini. Decorator merupakan suatu fungsi yang dapat memberikan parameter fungsi. Pada project ini, kami gunakan decorator untuk role management dan fitur log.

Tambahkan decorators.py pada app yang berisi semua decorator yang dibutuhkan. Berikut adalah fungsi decorator untuk role management

def sdm_login_required(view_func):
role_login_required = user_passes_test(lambda u: True if is_sdm(u) else False,
login_url=settings.LOGOUT_REDIRECT_URL)
decorated_view_func = login_required(role_login_required(view_func), login_url=settings.LOGOUT_REDIRECT_URL)
return decorated_view_func


def dgb_login_required(view_func):
role_login_required = user_passes_test(lambda u: True if is_dgb(u) else False,
login_url=settings.LOGOUT_REDIRECT_URL)
decorated_view_func = login_required(role_login_required(view_func), login_url=settings.LOGOUT_REDIRECT_URL)
return decorated_view_func


def fakultas_login_required(view_func):
role_login_required = user_passes_test(lambda u: True if is_fakultas(u) else False,
login_url=settings.LOGOUT_REDIRECT_URL)
decorated_view_func = login_required(role_login_required(view_func), login_url=settings.LOGOUT_REDIRECT_URL)
return decorated_view_func

Terdapat tiga decorator role yaitu fakultas_login_required, dgb_login_required, sdm_login_required. Decorator tersebut tersebut memiliki satu parameter fungsi yaitu sebuah view function yang dapat diperoleh user dari request pada view function dengan menggunakan user_passes_test. Isi dari user_pass_test adalah cek role dari user, contoh nya adalah is_sdm(u) akan return True jika u adalah sdm. Berikut adalah fungsi dari is_sdm:

def is_sdm(user):
if str(Admin.objects.get(user_id=user.id).role.name) == 'sdm':
return True
else
:
return False

Contoh penggunaan nya adalah pada fungsi halaman utama sdm berikut ini:

@create_log(log="menampilkan cyd diproses & dibatalkan oleh sdm")
@sdm_login_required
def retrieve_cyd(req):
processed_applications = sdm_controller.get_processed_applications()
canceled_applications = sdm_controller.get_canceled_applications()
processed_applications_pagination = p.pagination(req, "processed_page", processed_applications)
canceled_applications_pagination = p.pagination(req, "canceled_page", canceled_applications)
.
.
.
.

perhatikan bahwa kita tidak perlu lagi menggunakan @login_required karena decorator tersebut sudah include pada sdm_login_required yaitu login_required(role_login_required(view_func), login_url=settings.LOGOUT_REDIRECT_URL).

Log decorator

Perhatikan bahwa terdapat decorator create_log pada fungsi retrieve cyd diatas. Decorator tersebut digunakan untuk menyimpan log pada setiap view function, yaitu sebagai action dari user yang sedang login. Berikut adalah decorator create_log yang mempunya satu parameter yaitu log yang dapat diisi pesan atau catatan log dari suatu view function.

def create_log(log):
def decorator(view_func):
create_log_func = user_passes_test(lambda u: True if is_login_and_cretea_log(u, log) else False,
login_url=settings.LOGOUT_REDIRECT_URL)
decorated_view_func = login_required(create_log_func(view_func), login_url=settings.LOGOUT_REDIRECT_URL)
return decorated_view_func

return decorator


def is_login_and_cretea_log(user, log):
if (user.is_authenticated):
Log.objects.create(user=user, log=user.username + " " + log)
return True
else
:
return False

Berikut ini adalah model log dan contoh penyimpanannya pada admin page.

class Log(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
log = models.TextField()
created_at = models.DateTimeField(default=timezone.now, blank=True)

def __str__(self):
return str(self.id) + " " + self.log
Testing

Berikut adalah unit testing untuk decorator create_log

class AuthTest(TestCase):
def setUp(self):
self.client = Client()
self.factory = RequestFactory()
self.user1 = User.objects.create_user('foo_sdm', 'myemail@test.com1', 'bar_sdm')
self.user2 = User.objects.create_user('foo2', 'myemail@test.com2', 'bar2')
self.user3 = User.objects.create_user('foo3', 'myemail@test.com3', 'bar3')
role_sdm = Role.objects.create(name="sdm")
role_fakultas = Role.objects.create(name="fakultas")
role_dgb = Role.objects.create(name="dgb")
fakultas = Faculty.objects.create(name='Teknik')
self.admin_sdm = Admin.objects.create(user_id=self.user1, nip=1, role=role_sdm, faculty=fakultas)
self.admin_fakultas = Admin.objects.create(user_id=self.user2, nip=2, role=role_fakultas, faculty=fakultas)
self.admin_dgb = Admin.objects.create(user_id=self.user3, nip=3, role=role_dgb, faculty=fakultas)

def test_sdm_log(self):
self.client.login(username='foo_sdm', password='bar_sdm')
url = reverse("sdm:sdm_home")
self.client.get(url)
log = Log.objects.get(user=self.user1)
self.assertEqual(log.user.username, 'foo_sdm')

Perhatikan bahwa sebelumnya, user foo_sdm login, sehingga seharusnya akan bertambah Log pada database oleh user foo_sdm. Sehingga bisa digunakan self.assertEqual(log.user.username, ‘foo_sdm’).