Skip to content

Commit

Permalink
Add order of list source reference validation (#243)
Browse files Browse the repository at this point in the history
  • Loading branch information
petechd authored Jun 20, 2024
1 parent 0453302 commit 5b25ba8
Show file tree
Hide file tree
Showing 6 changed files with 1,327 additions and 1 deletion.
1 change: 1 addition & 0 deletions app/error_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,4 @@
"Variants have more than one question type for block."
)
PREVIEW_WITHOUT_INTRODUCTION_BLOCK = "No introduction block found. Introduction block is mandatory when using the preview questions feature."
LIST_REFERENCED_BEFORE_CREATED = "List referenced as source before it has been created."
36 changes: 36 additions & 0 deletions app/validators/questionnaire_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ def __init__(self, schema):
for block in list_collector.get("repeating_blocks", [])
}
self._answers_with_context = {}
self._lists_with_context = {}

@lru_cache
def get_block_ids_for_block_type(self, block_type: str) -> list[str]:
Expand Down Expand Up @@ -209,6 +210,41 @@ def answers_with_context(self):
self._answers_with_context = answers_dict
return self._answers_with_context

@property
def lists_with_context(self):
if supplementary_list := self.supplementary_lists:
for list_id in supplementary_list:
self._lists_with_context[list_id] = {
"section_index": 0,
"block_index": 0,
}

if blocks := self.list_collectors:
for block in blocks:
list_id = block["for_list"]
if list_id not in self._lists_with_context:
section_id = self.get_section_id_for_block_id(block["id"])
section_index = self.section_ids.index(section_id)
self._lists_with_context[list_id] = {
"section_index": section_index,
"block_index": self.block_ids.index(block["id"]),
}
if blocks := self.get_blocks(type="PrimaryPersonListCollector"):
for block in blocks:
list_id = block["for_list"]
if list_id not in self._lists_with_context or (
self.block_ids.index(block["id"])
< self._lists_with_context[list_id]["block_index"]
):
section_id = self.get_section_id_for_block_id(block["id"])
section_index = self.section_ids.index(section_id)
self._lists_with_context[list_id] = {
"section_index": section_index,
"block_index": self.block_ids.index(block["id"]),
}

return self._lists_with_context

@staticmethod
def capture_answers(*, answers, answers_dict, context):
for answer in answers:
Expand Down
41 changes: 40 additions & 1 deletion app/validators/questionnaire_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
from app.validators.answer_code_validator import AnswerCodeValidator
from app.validators.metadata_validator import MetadataValidator
from app.validators.placeholders.placeholder_validator import PlaceholderValidator
from app.validators.questionnaire_schema import QuestionnaireSchema, find_duplicates
from app.validators.questionnaire_schema import (
QuestionnaireSchema,
find_duplicates,
get_object_containing_key,
)
from app.validators.sections.section_validator import SectionValidator
from app.validators.validator import Validator

Expand All @@ -30,6 +34,7 @@ def validate(self):
self.validate_duplicates()
self.validate_smart_quotes()
self.validate_white_spaces()
self.validate_list_references()

for section in self.questionnaire_schema.sections:
section_validator = SectionValidator(section, self.questionnaire_schema)
Expand Down Expand Up @@ -134,3 +139,37 @@ def validate_introduction_block(self):
)
if not has_introduction_blocks:
self.add_error(error_messages.PREVIEW_WITHOUT_INTRODUCTION_BLOCK)

def validate_list_references(self):
lists_with_context = self.questionnaire_schema.lists_with_context

# We need to keep track of section index for: common_definitions.json#/section_enabled
for section_index, section in enumerate(self.questionnaire_schema.sections):
identifier_references = get_object_containing_key(section, "source")
for _, identifier_reference, parent_block in identifier_references:
if identifier_reference["source"] == "list":
list_identifier = identifier_reference["identifier"]
if parent_block:
if (
self.questionnaire_schema.block_ids.index(
parent_block["id"]
)
< lists_with_context[list_identifier]["block_index"]
):
self.add_error(
error_messages.LIST_REFERENCED_BEFORE_CREATED.format(),
list_id=list_identifier,
section_id=section["id"],
block_id=parent_block["id"],
)
elif (
section_index
< lists_with_context[list_identifier]["section_index"]
):
# Section level "enabled" rule that can use list source,
# check: common_definitions.json#/section_enabled
self.add_error(
error_messages.LIST_REFERENCED_BEFORE_CREATED.format(),
list_name=list_identifier,
section_id=section["id"],
)
Loading

0 comments on commit 5b25ba8

Please sign in to comment.