Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions backend/api/v1/v1_data/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,32 +36,40 @@ def __init__(self, **kwargs):
'question').queryset = Questions.objects.all()

def validate_value(self, value):
if value == '':
raise ValidationError('Value is required')
if isinstance(value, list) and len(value) == 0:
raise ValidationError('Value is required')
return value

def validate(self, attrs):
if attrs.get('value') == '':
raise ValidationError('Value is required for Question:{0}'.format(
attrs.get('question').id))

if isinstance(attrs.get('value'), list) and len(
attrs.get('value')) == 0:
raise ValidationError('Value is required for Question:{0}'.format(
attrs.get('question').id))

if not isinstance(attrs.get('value'), list) and attrs.get(
'question').type in [QuestionTypes.geo,
QuestionTypes.option,
QuestionTypes.multiple_option]:
raise ValidationError(
{'value': 'Valid list value is required'})
'Valid list value is required for Question:{0}'.format(
attrs.get('question').id))
elif not isinstance(attrs.get('value'), str) and attrs.get(
'question').type in [QuestionTypes.text,
QuestionTypes.photo,
QuestionTypes.date]:

raise ValidationError(
{'value': 'Valid string value is required'})
'Valid string value is required for Question:{0}'.format(
attrs.get('question').id))

elif not isinstance(attrs.get('value'), int) and attrs.get(
'question').type in [QuestionTypes.number,
QuestionTypes.administration]:

raise ValidationError(
{'value': 'Valid number value is required'})
'Valid number value is required for Question:{0}'.format(
attrs.get('question').id))

return attrs

Expand Down
16 changes: 9 additions & 7 deletions backend/api/v1/v1_forms/management/commands/form_seeder.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,18 @@ def handle(self, *args, **options):
for json_file in os.listdir(source_folder)
]
source_files = list(
filter(lambda x: "example" in x
if test else "example" not in x, source_files))
filter(lambda x: "example" in x if test else "example" not in x,
source_files))
Forms.objects.all().delete()
for source in source_files:
for index, source in enumerate(source_files):
json_form = open(source, 'r')
json_form = json.load(json_form)
form = Forms(id=json_form["id"],
name=json_form["form"],
version=1,
type=FormTypes.national)
form = Forms(
id=json_form["id"],
name=json_form["form"],
version=1,
type=FormTypes.national if index > 2 else FormTypes.county
)
form.save()
for qg in json_form["question_groups"]:
question_group = QuestionGroup(name=qg["question_group"],
Expand Down
35 changes: 35 additions & 0 deletions backend/api/v1/v1_forms/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,41 @@ class Meta:
db_table = 'form_approval_rule'


"""
Approval Rule
Form - 1
administration - Current user's administration 1
Level - [2,4]
"""

"""
path administration with level [2,4]
Removed Level - 3
Assign Approval
Form - 1
User - 2
administration - User's administration - 2


Assign Approval
Form - 1
User - 3
administration - User's administration - 3

Assign Approval
Form - 1
User - 4
administration - User's administration - 4

--------- GET /form/approvers/ ------------

form_id,administration_id
direct children - administration_id
# FormApprovalAssignment

"""


class FormApprovalAssignment(models.Model):
form = models.ForeignKey(to=Forms,
on_delete=models.CASCADE,
Expand Down
100 changes: 97 additions & 3 deletions backend/api/v1/v1_forms/serializers.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
from collections import OrderedDict

from django.db.models import Q
from django.utils import timezone
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema_field, inline_serializer
from rest_framework import serializers

from api.v1.v1_forms.constants import QuestionTypes, FormTypes
from api.v1.v1_forms.models import Forms, QuestionGroup, Questions, \
QuestionOptions
from api.v1.v1_profile.models import Administration
QuestionOptions, FormApprovalRule, FormApprovalAssignment
from api.v1.v1_profile.models import Administration, Levels
from api.v1.v1_users.models import SystemUser
from rtmis.settings import FORM_GEO_VALUE
from utils.custom_serializer_fields import CustomChoiceField
from utils.custom_serializer_fields import CustomChoiceField, \
CustomPrimaryKeyRelatedField, CustomListField


class ListOptionSerializer(serializers.ModelSerializer):
Expand Down Expand Up @@ -208,3 +212,93 @@ def get_question_group(self, instance: Forms):
class Meta:
model = Forms
fields = ['id', 'name', 'question_group']


class EditFormTypeSerializer(serializers.ModelSerializer):
form_id = CustomPrimaryKeyRelatedField(queryset=Forms.objects.none())
type = CustomChoiceField(choices=list(FormTypes.FieldStr.keys()))

def __init__(self, **kwargs):
super().__init__(**kwargs)
self.fields.get('form_id').queryset = Forms.objects.all()

def create(self, validated_data):
form: Forms = validated_data.get('form_id')
form.type = validated_data.get('type')
form.save()
return form

class Meta:
model = Forms
fields = ['form_id', 'type']


class EditFormApprovalSerializer(serializers.ModelSerializer):
form_id = CustomPrimaryKeyRelatedField(queryset=Forms.objects.none(),
source='form')
level_id = CustomListField(
child=CustomPrimaryKeyRelatedField(queryset=Levels.objects.none()),
source='levels')

def __init__(self, **kwargs):
super().__init__(**kwargs)
self.fields.get('form_id').queryset = Forms.objects.all()
self.fields.get('level_id').child.queryset = Levels.objects.all()

def create(self, validated_data):
administration = self.context.get('user').user_access.administration
FormApprovalRule.objects.filter(form=validated_data.get('form'),
administration=administration).delete()

validated_data['administration'] = administration
rule: FormApprovalRule = super(EditFormApprovalSerializer,
self).create(validated_data)
if administration.path:
path = f"{administration.path}{administration.id}."
else:
path = f"{administration.id}."

# Get descendants of current admin with selected level
descendants = list(Administration.objects.filter(
path__startswith=path,
level_id__in=rule.levels.all().values_list('id',
flat=True)).values_list(
'id', flat=True))
# Delete assignment for the removed levels
FormApprovalAssignment.objects.filter(
~Q(administration_id__in=descendants), form=rule.form).delete()
return rule

class Meta:
model = FormApprovalRule
fields = ['form_id', 'level_id']


class ApprovalFormUserSerializer(serializers.ModelSerializer):
user_id = CustomPrimaryKeyRelatedField(queryset=SystemUser.objects.none(),
source='user')
administration_id = CustomPrimaryKeyRelatedField(
queryset=Administration.objects.none(), source='administration')

def __init__(self, **kwargs):
super().__init__(**kwargs)
self.fields.get('user_id').queryset = SystemUser.objects.all()
self.fields.get(
'administration_id').queryset = Administration.objects.all()

def create(self, validated_data):
print(validated_data)

assignment, created = FormApprovalAssignment.objects.get_or_create(
form=self.context.get('form'),
administration=validated_data.get('administration'),
user=validated_data.get('user')
)
if not created:
assignment.updated = timezone.now()
assignment.save()
return assignment

class Meta:
model = FormApprovalAssignment
fields = ['user_id', 'administration_id']
121 changes: 98 additions & 23 deletions backend/api/v1/v1_forms/tests/tests_form_submission.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from api.v1.v1_forms.models import Forms
from api.v1.v1_profile.models import Administration, Levels
from api.v1.v1_users.models import SystemUser


def seed_administration_test():
Expand All @@ -24,29 +25,16 @@ class FormSubmissionTestCase(TestCase):
def test_webform_endpoint(self):
self.maxDiff = None
call_command("form_seeder", "--test")
seed_administration_test()
call_command("administration_seeder", "--test")
webform = self.client.get("/api/v1/web/form/1", follow=True)
webform = webform.json()
self.assertEqual(webform.get("name"), "Test Form")
question_group = webform.get("question_group")
self.assertEqual(len(question_group), 1)
self.assertEqual(question_group[0].get("name"), "Question Group 01")
question = question_group[0].get("question")
self.assertEqual(question[3]["type"], "cascade")
self.assertEqual(question[3]["option"], "administration")
self.assertEqual(
webform.get("cascade"), {
"administration":
[{
"label": "Indonesia",
"value": 1,
"children": [{
"label": "Jakarta",
"value": 2,
"children": []
}]
}]
})
list(webform.get("cascade").get('administration')[0]),
['value', 'label', 'children'])

def test_create_new_submission(self):
self.maxDiff = None
Expand Down Expand Up @@ -114,10 +102,97 @@ def test_form_data_endpoint(self):
question_group = webform.get("question_group")
self.assertEqual(len(question_group), 1)
self.assertEqual(question_group[0].get("name"), "Question Group 01")
question = question_group[0].get("question")
self.assertEqual(1, question[0]['id'])
self.assertEqual(1, question[0]['form'])
self.assertEqual('Name', question[0]['name'])
self.assertEqual(True, question[0]['meta'])
self.assertEqual('text', question[0]['type'])
self.assertEqual(True, question[0]['required'])

def test_edit_form_type(self):
call_command("administration_seeder", "--test")
call_command("form_seeder", "--test")
user_payload = {"email": "admin@rtmis.com", "password": "Test105*"}
user_response = self.client.post('/api/v1/login/',
user_payload,
content_type='application/json')
user = user_response.json()
token = user.get('token')
header = {
'HTTP_AUTHORIZATION': f'Bearer {token}'
}

form = Forms.objects.first()
payload = [{"form_id": form.id, "type": 3}]
response = self.client.put('/api/v1/edit/forms/',
payload,
content_type='application/json',
**header)
self.assertEqual(400, response.status_code)

payload = [{"form_id": form.id, "type": 1}]

response = self.client.put('/api/v1/edit/forms/',
payload,
content_type='application/json',
**header)
self.assertEqual(200, response.status_code)
self.assertEqual(response.json().get('message'),
'Forms updated successfully')

def test_edit_form_approval(self):
call_command("administration_seeder", "--test")
call_command("form_seeder", "--test")
user_payload = {"email": "admin@rtmis.com", "password": "Test105*"}
user_response = self.client.post('/api/v1/login/',
user_payload,
content_type='application/json')
user = user_response.json()
token = user.get('token')
header = {
'HTTP_AUTHORIZATION': f'Bearer {token}'
}

form = Forms.objects.first()
payload = [{"form_id": form.id, "level_id": 3}]
response = self.client.post('/api/v1/edit/form/approval/',
payload,
content_type='application/json',
**header)

self.assertEqual(400, response.status_code)
level = Levels.objects.first()
payload = [{"form_id": form.id, "level_id": [level.id]}]

response = self.client.post('/api/v1/edit/form/approval/',
payload,
content_type='application/json',
**header)
self.assertEqual(200, response.status_code)
self.assertEqual(response.json().get('message'),
'Forms updated successfully')

def test_approval_form_user(self):
call_command("administration_seeder", "--test")
call_command("form_seeder", "--test")
user_payload = {"email": "admin@rtmis.com", "password": "Test105*"}
user_response = self.client.post('/api/v1/login/',
user_payload,
content_type='application/json')
user = user_response.json()
token = user.get('token')
header = {
'HTTP_AUTHORIZATION': f'Bearer {token}'
}
u = SystemUser.objects.first()
payload = [{"user_id": u.id, "administration_id": 0}]
response = self.client.post('/api/v1/approval/form/1/',
payload,
content_type='application/json',
**header)

self.assertEqual(400, response.status_code)

payload = [{"user_id": u.id, "administration_id": 1}]

response = self.client.post('/api/v1/approval/form/1/',
payload,
content_type='application/json',
**header)
self.assertEqual(200, response.status_code)
self.assertEqual(response.json().get('message'),
'Forms updated successfully')
7 changes: 6 additions & 1 deletion backend/api/v1/v1_forms/urls.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
from django.urls import re_path

from api.v1.v1_forms.views import web_form_details, list_form, form_data
from api.v1.v1_forms.views import web_form_details, list_form, form_data, \
edit_form_type, edit_form_approval, approval_form_users

urlpatterns = [
re_path(r'^(?P<version>(v1))/web/form/(?P<pk>[0-9]+)/',
web_form_details),
re_path(r'^(?P<version>(v1))/forms/', list_form),
re_path(r'^(?P<version>(v1))/form/(?P<pk>[0-9]+)/',
form_data),
re_path(r'^(?P<version>(v1))/edit/forms/', edit_form_type),
re_path(r'^(?P<version>(v1))/edit/form/approval/', edit_form_approval),
re_path(r'^(?P<version>(v1))/approval/form/(?P<pk>[0-9]+)/',
approval_form_users),
]
Loading