diff --git a/backend/api/v1/v1_forms/management/commands/form_approval_seeder.py b/backend/api/v1/v1_forms/management/commands/form_approval_seeder.py new file mode 100644 index 000000000..ace3b670e --- /dev/null +++ b/backend/api/v1/v1_forms/management/commands/form_approval_seeder.py @@ -0,0 +1,21 @@ +import random + +from django.core.management import BaseCommand + +from api.v1.v1_forms.models import Forms, FormApprovalRule +from api.v1.v1_profile.models import Access, Levels + + +class Command(BaseCommand): + def handle(self, *args, **options): + FormApprovalRule.objects.all().delete() + for form in Forms.objects.all(): + for user in Access.objects.filter(administration__level_id=2): + limit = random.choices([1, 2]) + levels = Levels.objects.filter(level__gt=1)[:limit[0]] + rule = FormApprovalRule.objects.create( + form=form, + administration=user.administration + ) + rule.levels.set(levels) + rule.save() diff --git a/backend/api/v1/v1_forms/serializers.py b/backend/api/v1/v1_forms/serializers.py index e75d0a342..c36464ce2 100644 --- a/backend/api/v1/v1_forms/serializers.py +++ b/backend/api/v1/v1_forms/serializers.py @@ -9,7 +9,7 @@ from api.v1.v1_forms.constants import QuestionTypes, FormTypes from api.v1.v1_forms.models import Forms, QuestionGroup, Questions, \ QuestionOptions, FormApprovalRule, FormApprovalAssignment -from api.v1.v1_profile.models import Administration, Levels +from api.v1.v1_profile.models import Administration, Levels, Access from api.v1.v1_users.models import SystemUser from rtmis.settings import FORM_GEO_VALUE from utils.custom_serializer_fields import CustomChoiceField, \ @@ -302,3 +302,46 @@ def create(self, validated_data): class Meta: model = FormApprovalAssignment fields = ['user_id', 'administration_id'] + + +class FormApprovalLevelListSerializer(serializers.ModelSerializer): + class Meta: + model = FormApprovalRule + fields = ['form_id', 'levels'] + + +class FormApproverRequestSerializer(serializers.Serializer): + administration_id = CustomPrimaryKeyRelatedField( + queryset=Administration.objects.none()) + form_id = CustomPrimaryKeyRelatedField( + queryset=Forms.objects.none()) + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.fields.get('form_id').queryset = Forms.objects.all() + self.fields.get( + 'administration_id').queryset = Administration.objects.all() + + +class FormApproverUserSerializer(serializers.ModelSerializer): + class Meta: + model = SystemUser + fields = ['id', 'first_name', 'last_name', 'email'] + + +class FormApproverResponseSerializer(serializers.ModelSerializer): + user = serializers.SerializerMethodField() + administration = serializers.SerializerMethodField() + + def get_user(self, instance: Administration): + access: Access = instance.user_administration.first() + if access: + return FormApproverUserSerializer(instance=access.user).data + return None + + def get_administration(self, instance: Administration): + return {'id': instance.id, 'name': instance.name} + + class Meta: + model = Administration + fields = ['user', 'administration'] diff --git a/backend/api/v1/v1_forms/tests/tests_form_approval.py b/backend/api/v1/v1_forms/tests/tests_form_approval.py new file mode 100644 index 000000000..42c098375 --- /dev/null +++ b/backend/api/v1/v1_forms/tests/tests_form_approval.py @@ -0,0 +1,51 @@ +from django.core.management import call_command +from django.test import TestCase +from rest_framework_simplejwt.tokens import RefreshToken + +from api.v1.v1_profile.constants import UserRoleTypes +from api.v1.v1_users.models import SystemUser + + +class FormApprovalTestCase(TestCase): + def test_approval_endpoint(self): + call_command("form_seeder", "--test") + call_command("administration_seeder", "--test") + call_command("form_approval_seeder") + 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}' + } + response = self.client.get('/api/v1/form/approval-level/', + content_type='application/json', + **header) + self.assertEqual(403, response.status_code) + call_command("fake_user_seeder", "-r", 10) + admin_user = SystemUser.objects.filter( + user_access__role=UserRoleTypes.admin).first() + if admin_user: + t = RefreshToken.for_user(admin_user) + header = { + 'HTTP_AUTHORIZATION': f'Bearer {t.access_token}' + } + response = self.client.get('/api/v1/form/approval-level/', + content_type='application/json', + **header) + self.assertEqual(200, response.status_code) + header = { + 'HTTP_AUTHORIZATION': f'Bearer {token}' + } + + response = self.client.get('/api/v1/admin/form/approval-level/1/', + content_type='application/json', + **header) + self.assertEqual(200, response.status_code) + response = self.client.get( + '/api/v1/form/approver/?administration_id=1&form_id=1', + content_type='application/json', + **header) + self.assertEqual(200, response.status_code) diff --git a/backend/api/v1/v1_forms/urls.py b/backend/api/v1/v1_forms/urls.py index dbbbfe543..b7e748a12 100644 --- a/backend/api/v1/v1_forms/urls.py +++ b/backend/api/v1/v1_forms/urls.py @@ -1,7 +1,8 @@ from django.urls import re_path from api.v1.v1_forms.views import web_form_details, list_form, form_data, \ - edit_form_type, edit_form_approval, approval_form_users + edit_form_type, edit_form_approval, approval_form_users, \ + form_approval_level, form_approval_level_administration, form_approver urlpatterns = [ re_path(r'^(?P(v1))/web/form/(?P[0-9]+)/', @@ -13,4 +14,8 @@ re_path(r'^(?P(v1))/edit/form/approval/', edit_form_approval), re_path(r'^(?P(v1))/approval/form/(?P[0-9]+)/', approval_form_users), + re_path(r'^(?P(v1))/form/approval-level/', form_approval_level), + re_path(r'^(?P(v1))/admin/form/approval-level/(?P[0-9]+)/', + form_approval_level_administration), + re_path(r'^(?P(v1))/form/approver/', form_approver), ] diff --git a/backend/api/v1/v1_forms/views.py b/backend/api/v1/v1_forms/views.py index 9104cc720..831b70d81 100644 --- a/backend/api/v1/v1_forms/views.py +++ b/backend/api/v1/v1_forms/views.py @@ -8,11 +8,13 @@ from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response -from api.v1.v1_forms.models import Forms +from api.v1.v1_forms.models import Forms, FormApprovalRule from api.v1.v1_forms.serializers import ListFormSerializer, \ WebFormDetailSerializer, FormDataSerializer, ListFormRequestSerializer, \ EditFormTypeSerializer, EditFormApprovalSerializer, \ - ApprovalFormUserSerializer + ApprovalFormUserSerializer, FormApprovalLevelListSerializer, \ + FormApproverRequestSerializer, FormApproverResponseSerializer +from api.v1.v1_profile.models import Administration from utils.custom_permissions import IsSuperAdmin, IsAdmin from utils.custom_serializer_fields import validate_serializers_message @@ -134,3 +136,62 @@ def approval_form_users(request, version, pk): except ArithmeticError as ex: return Response({'message': ex.args}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + +@extend_schema(responses={200: FormApprovalLevelListSerializer(many=True)}, + tags=['Form']) +@api_view(['GET']) +@permission_classes([IsAuthenticated, IsAdmin]) +def form_approval_level(request, version): + instance = FormApprovalRule.objects.filter( + administration=request.user.user_access.administration) + return Response( + FormApprovalLevelListSerializer(instance=instance, many=True).data, + status=status.HTTP_200_OK) + + +@extend_schema(responses={200: FormApprovalLevelListSerializer(many=True)}, + tags=['Form']) +@api_view(['GET']) +@permission_classes([IsAuthenticated, IsSuperAdmin]) +def form_approval_level_administration(request, version, pk): + administration = get_object_or_404(Administration, pk=pk) + instance = FormApprovalRule.objects.filter( + administration=administration) + return Response( + FormApprovalLevelListSerializer(instance=instance, many=True).data, + status=status.HTTP_200_OK) + + +@extend_schema(parameters=[ + OpenApiParameter(name='administration_id', + required=True, + type=OpenApiTypes.NUMBER, + location=OpenApiParameter.QUERY), + OpenApiParameter(name='form_id', + required=True, + type=OpenApiTypes.NUMBER, + location=OpenApiParameter.QUERY), +], + responses={200: FormApproverResponseSerializer(many=True)}, + tags=['Form']) +@api_view(['GET']) +@permission_classes([IsAuthenticated, IsSuperAdmin | IsAdmin]) +def form_approver(request, version): + try: + serializer = FormApproverRequestSerializer(data=request.GET) + if not serializer.is_valid(): + return Response( + {'message': validate_serializers_message(serializer.errors)}, + status=status.HTTP_400_BAD_REQUEST + ) + + instance = Administration.objects.filter( + parent=serializer.validated_data.get('administration_id'), + ) + return Response(FormApproverResponseSerializer(instance=instance, + many=True).data, + status=status.HTTP_200_OK) + except Exception as ex: + return Response({'message': ex.args}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR)