Fakultas Ilmu Komputer UI

Commit f85ed76f authored by Ahmad Satryaji Aulia's avatar Ahmad Satryaji Aulia
Browse files

Implement custom validator for NPM

We now validate NPM length and checksum for Student's npm field
parent 0c2a62b6
import os
import math
from django.core.exceptions import ValidationError
from kape.settings import MAX_UPLOAD_SIZE
......@@ -18,3 +19,29 @@ def validate_document_file_extension(value):
def validate_image_file_extension(value):
validate_file(value, ['.jpeg', '.jpg', '.png', '.JPG', '.JPEG'])
def validate_npm(value):
'''
NPM UI terdiri dari 10 digit, misalnya: 1234567894. Digit terakhir
(disebut checksum) dapat dihitung dari sembilan digit pertama.
Checksum dipakai untuk deteksi error pada nomor ID seperti NPM.
Digit-digit tersebut diberi indeks: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
sesuai posisinya. Kita asosiasikan digit-digit tersebut dengan
variabel-variabel d[0], d[1], d[2] , ..., d[9].
Checksum C (yaitu d[9]) dihitung dengan rumus sebagai berikut:
1) a = 3* (d[0] + d[2] + d[4] + d[6] + d[8])
2) b = (d[1] + d[3] + d[5] + d[7])
3) C = (a + b) % 7
Sebagai contoh, checksum untuk NPM 1234567894 adalah
C = (3*(1 + 3 + 5 + 7 + 9) + (2 + 4 + 6 + 8)) % 7 = 95 % 7 = 4
yang memang ternyata benar.
Source: Lim Yohanes Stefanus, Drs., M.Math., Ph.D
'''
if math.ceil(math.log(value+1, 10)) != 10:
raise ValidationError(u"NPM must be 10 digits")
val_string = str(value)
if sum([3*int(a) for a in val_string[:-1:2]]+[int(a) for a in val_string[1:-1:2]]) % 7 != int(val_string[-1]):
raise ValidationError(u"NPM {} has invalid checksum".format(value))
\ No newline at end of file
# -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2019-10-04 06:40
from __future__ import unicode_literals
import core.lib.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0013_auto_20170602_1130'),
]
operations = [
migrations.AlterField(
model_name='student',
name='npm',
field=models.IntegerField(unique=True, validators=[core.lib.validators.validate_npm]),
),
]
......@@ -5,7 +5,7 @@ from django.contrib.auth.models import User
from django.core.validators import MinValueValidator, MaxValueValidator
from django.db import models
from core.lib.validators import validate_document_file_extension, validate_image_file_extension
from core.lib.validators import validate_document_file_extension, validate_image_file_extension, validate_npm
def get_student_resume_file_path(instance, filename):
......@@ -53,7 +53,7 @@ class Student(models.Model):
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
user = models.OneToOneField(User)
npm = models.IntegerField(validators=[MinValueValidator(100000000), MaxValueValidator(9999999999)], unique=True)
npm = models.IntegerField(validators=[validate_npm], unique=True)
resume = models.FileField(upload_to=get_student_resume_file_path, null=True, blank=True, validators=[validate_document_file_extension])
phone_number = models.CharField(max_length=100, blank=True, db_index=True, null=True)
bookmarked_vacancies = models.ManyToManyField('core.Vacancy', related_name="bookmarked_vacancies", blank=True)
......
......@@ -2,6 +2,7 @@ import requests_mock
from rest_framework import status
from rest_framework.test import APIClient, APITestCase
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from core.models.accounts import Company, Supervisor, Student
......@@ -103,6 +104,16 @@ class RegisterTests(APITestCase):
response = self.client.post(url, {'username': 'lalala'}, format='multipart')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
def test_npm_validator(self):
new_user = User.objects.create_user('dummy.student2', 'dummy.student@student.com', 'lalala123')
short_npm = Student(user=new_user, npm="123456789")
self.assertRaises(ValidationError, short_npm.full_clean)
wrong_checksum = Student(user=new_user, npm="1234567890")
self.assertRaises(ValidationError, wrong_checksum.full_clean)
right_checksum = Student(user=new_user, npm="1234567894")
right_checksum.full_clean()
class ProfileUpdateTests(APITestCase):
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment