Skip to content

Commit

Permalink
FWF-3748: [Feature] Added submissions count for form list with create…
Browse files Browse the repository at this point in the history
…_submissions permission (#2521)

* FWF-3748: [Feature] Added submissions cout for form list with create_submissions permission

* FWF-3748: [Feature] Testcase added
  • Loading branch information
auslin-aot authored Jan 21, 2025
1 parent 7d3fdb8 commit f4feb61
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 1 deletion.
17 changes: 17 additions & 0 deletions forms-flow-api/src/formsflow_api/models/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,23 @@ def find_by_form_names( # pylint: disable=too-many-arguments, too-many-position
pagination = query.paginate(page=page_no, per_page=limit, error_out=False)
return pagination.items, total_count

@classmethod
def find_applications_count_by_parent_form_id_user(
cls, parent_form_id, user_name, tenant
):
"""Fetch application count based on parent_form_id and user who submitted the application."""
count_query = (
db.session.query(func.count(Application.id))
.join(FormProcessMapper, cls.form_process_mapper_id == FormProcessMapper.id)
.filter(
FormProcessMapper.parent_form_id == parent_form_id,
FormProcessMapper.tenant == tenant,
cls.created_by == user_name,
cls.application_status != DRAFT_APPLICATION_STATUS,
)
)
return count_query.scalar()

@classmethod
def find_applications_by_auth_formids_user( # pylint: disable=too-many-arguments, too-many-positional-arguments
cls,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ def find_all_active_by_formid(
cls.form_name,
cls.modified,
cls.description,
cls.parent_form_id,
)
limit = total_count if limit is None else limit
query = query.paginate(page=page_number, per_page=limit, error_out=False)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ def get(): # pylint: disable=too-many-locals
)
sort_by = sort_by.split(",")
sort_order = sort_order.split(",")
include_submissions_count = dict_data.get("include_submissions_count", False)
if form_type:
form_type = form_type.split(",")
if search:
Expand All @@ -319,6 +320,7 @@ def get(): # pylint: disable=too-many-locals
is_active=is_active,
is_designer=is_designer,
active_forms=active_forms,
include_submissions_count=include_submissions_count,
)
return (
(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,6 @@ class FormProcessMapperListRequestSchema(FormProcessMapperListReqSchema):
ignore_designer = fields.Bool(
data_key="showForOnlyCreateSubmissionUsers", required=False
)
include_submissions_count = fields.Bool(
data_key="includeSubmissionsCount", required=False
)
14 changes: 13 additions & 1 deletion forms-flow-api/src/formsflow_api/services/form_process_mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from flask import current_app
from formsflow_api_utils.exceptions import BusinessException
from formsflow_api_utils.services.external import FormioService
from formsflow_api_utils.utils import CREATE_SUBMISSIONS
from formsflow_api_utils.utils.enums import FormProcessMapperStatus
from formsflow_api_utils.utils.user_context import UserContext, user_context

Expand Down Expand Up @@ -50,6 +51,7 @@ def get_all_forms( # pylint: disable=too-many-positional-arguments
is_active,
is_designer: bool,
active_forms: bool,
include_submissions_count: bool,
**kwargs,
): # pylint: disable=too-many-arguments, too-many-locals
"""Get all forms."""
Expand Down Expand Up @@ -90,8 +92,18 @@ def get_all_forms( # pylint: disable=too-many-positional-arguments
**designer_filters if is_designer else {},
)
mapper_schema = FormProcessMapperSchema()
mappers_response = mapper_schema.dump(mappers, many=True)
if include_submissions_count and CREATE_SUBMISSIONS in user.roles:
current_app.logger.debug("Fetching submissions count..")
for mapper in mappers_response:
mapper["submissionsCount"] = (
Application.find_applications_count_by_parent_form_id_user(
mapper["parentFormId"], user.user_name, user.tenant_key
)
)

return (
mapper_schema.dump(mappers, many=True),
mappers_response,
get_all_mappers_count,
)

Expand Down
60 changes: 60 additions & 0 deletions forms-flow-api/tests/unit/api/test_form_process_mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from formsflow_api.services import FormHistoryService
from tests.utilities.base_test import (
get_application_create_payload,
get_draft_create_payload,
get_form_request_payload,
get_formio_form_request_payload,
get_token,
Expand Down Expand Up @@ -778,3 +779,62 @@ def test_unpublish(app, client, session, jwt, mock_redis_client, create_mapper):
mock_post.return_value = mock_response
response = client.post(f"/form/{mapper_id}/unpublish", headers=headers)
assert response.status_code == 200


def test_form_list_submission_count(app, client, session, jwt, create_mapper):
"""Tests the form list endpoint with includeSubmissionsCount query param."""
token = get_token(jwt, role=CREATE_DESIGNS)
headers = {
"Authorization": f"Bearer {token}",
"content-type": "application/json",
}

form_id = create_mapper["formId"]
auth_payload = {
"resourceId": "1234",
"resourceDetails": {},
"roles": [],
}
# create authorization for the form.
client.post(
"/authorizations/form", headers=headers, data=json.dumps(auth_payload)
)
client.post(
"/authorizations/designer", headers=headers, data=json.dumps(auth_payload)
)
client.post(
"/authorizations/application", headers=headers, data=json.dumps(auth_payload)
)
token = get_token(jwt, role=CREATE_SUBMISSIONS)
headers = {
"Authorization": f"Bearer {token}",
"content-type": "application/json",
}
# create application.
rv = client.post(
"/application/create",
headers=headers,
json=get_application_create_payload(form_id),
)
assert rv.status_code == 201

# create draft
client.post("/draft", headers=headers, json=get_draft_create_payload(form_id))

token = get_token(jwt, role=CREATE_SUBMISSIONS)
headers = {"Authorization": f"Bearer {token}", "content-type": "application/json"}
# submissionsCount exclude draft and return submission count
response = client.get("/form?includeSubmissionsCount=true", headers=headers)
assert response.status_code == 200
forms = response.json["forms"]
assert len(forms) == 1
assert forms[0]["submissionsCount"] == 1

# Assert form list api with no create_submissions permission.
token = get_token(jwt, role=CREATE_DESIGNS)
headers = {"Authorization": f"Bearer {token}", "content-type": "application/json"}
response = client.get("/form?includeSubmissionsCount=true", headers=headers)
assert response.status_code == 200
forms = response.json["forms"]
assert len(forms) == 1
assert "submissionsCount" not in forms[0]

0 comments on commit f4feb61

Please sign in to comment.