def set_locked_version(self, tallySheetVersion: TallySheetVersion): if tallySheetVersion is None: if not has_role_based_access(self, ACCESS_TYPE_UNLOCK): raise ForbiddenException( message="User not authorized to unlock the tally sheet.", code=MESSAGE_CODE_TALLY_SHEET_NOT_AUTHORIZED_TO_UNLOCK) self.submission.set_locked_version(submissionVersion=None) else: if self.template.is_submit_allowed(): if self.submittedVersionId is None: raise ForbiddenException( message= "Data entry tally sheet cannot be locked before submitting", code=MESSAGE_CODE_TALLY_SHEET_CANNOT_LOCK_BEFORE_SUBMIT ) elif self.submittedStamp.createdBy == get_user_name(): raise ForbiddenException( message= "Data entry tally sheet submitted user is not allowed to lock/unlock.", code= MESSAGE_CODE_TALLY_SHEET_SAME_USER_CANNOT_SAVE_AND_SUBMIT ) if not has_role_based_access(self, ACCESS_TYPE_LOCK): raise ForbiddenException( message="User is not authorized to lock the tally sheet.", code=MESSAGE_CODE_TALLY_SHEET_NOT_AUTHORIZED_TO_LOCK) self.submission.set_locked_version( submissionVersion=tallySheetVersion.submissionVersion) self.update_status_report()
def get_by_id(tallySheetId, tallySheetCode=None): # Filter by authorized areas user_access_area_ids: Set[int] = get_user_access_area_ids() query_args = [TallySheetModel] query_filters = [ TallySheetModel.tallySheetId == tallySheetId, TallySheetModel.areaId.in_(user_access_area_ids), Template.Model.templateId == Model.templateId ] query_group_by = [Model.tallySheetId] if tallySheetCode is not None: query_filters.append(Template.Model.templateName == tallySheetCode) tally_sheet = db.session.query(*query_args).filter( *query_filters).group_by(*query_group_by).one_or_none() # Validate the authorization if tally_sheet is not None and not has_role_based_access( election=tally_sheet.election, tally_sheet_code=tally_sheet.tallySheetCode, access_type=WORKFLOW_ACTION_TYPE_VIEW): raise UnauthorizedException( message="Not authorized to view tally sheet. (tallySheetId=%d)" % tallySheetId, code=MESSAGE_CODE_TALLY_SHEET_NOT_AUTHORIZED_TO_VIEW) return tally_sheet
def get_tally_sheet_workflow_instance_actions(self, workflow_instance): tally_sheet_workflow_instance_actions = db.session.query( WorkflowActionModel.workflowActionId, WorkflowActionModel.actionName, WorkflowActionModel.actionType, WorkflowActionModel.fromStatus, WorkflowActionModel.toStatus).filter( WorkflowActionModel.workflowId == workflow_instance.workflowId).order_by( WorkflowActionModel.workflowActionId).all() processed_tally_sheet_workflow_instance_actions = [] for tally_sheet_workflow_instance_action in tally_sheet_workflow_instance_actions: processed_tally_sheet_workflow_instance_actions.append({ "workflowActionId": tally_sheet_workflow_instance_action.workflowActionId, "actionName": tally_sheet_workflow_instance_action.actionName, "actionType": tally_sheet_workflow_instance_action.actionType, "fromStatus": tally_sheet_workflow_instance_action.fromStatus, "toStatus": tally_sheet_workflow_instance_action.toStatus, "allowed": tally_sheet_workflow_instance_action.fromStatus == workflow_instance.status, "authorized": has_role_based_access( tally_sheet=self, access_type=tally_sheet_workflow_instance_action.actionType ) }) return processed_tally_sheet_workflow_instance_actions
def authorize_workflow_action(self, workflow_action, content=None): from auth import has_role_based_access if not has_role_based_access(election=self.tallySheet.election, tally_sheet_code=self.tallySheet.tallySheetCode, access_type=workflow_action.actionType): UnauthorizedException(message="Not allowed to %s" % (workflow_action.actionName), code=MESSAGE_CODE_WORKFLOW_ACTION_NOT_AUTHORIZED) if workflow_action.actionType == WORKFLOW_ACTION_TYPE_REQUEST_CHANGES and workflow_action.toStatus in [ WORKFLOW_STATUS_TYPE_CHANGES_REQUESTED]: from orm.entities import TallySheet from orm.entities.TallySheet import TallySheetTallySheetModel extended_election = self.tallySheet.election.get_extended_election() verified_parent_tally_sheets = db.session.query( TallySheet.Model.tallySheetId ).filter( TallySheetTallySheetModel.childTallySheetId == self.tallySheet.tallySheetId, TallySheet.Model.tallySheetId == TallySheetTallySheetModel.parentTallySheetId, WorkflowInstance.Model.workflowInstanceId == TallySheet.Model.workflowInstanceId, WorkflowInstance.Model.status.in_( extended_election.tally_sheet_verified_statuses_list() ) ).all() if len(verified_parent_tally_sheets) > 0: raise MethodNotAllowedException( message="Cannot request changes since the data from this report has been already aggregated in verified summary reports.", code=MESSAGE_CODE_TALLY_SHEET_CANNOT_BE_UNLOCKED_WHILE_HAVING_VERIFIED_PARENT_SUMMARY_SHEETS)
def authorize_workflow_action(self, workflow_action, content=None): from auth import has_role_based_access if not has_role_based_access(self.tallySheet, workflow_action.actionType): UnauthorizedException( message="Not allowed to %s" % (workflow_action.actionName), code=MESSAGE_CODE_WORKFLOW_ACTION_NOT_AUTHORIZED)
def get_all(electionId=None, areaId=None, tallySheetCode=None, voteType=None, partyId=None, limit=None, offset=None): # Filter by authorized areas user_access_area_ids: Set[int] = get_user_access_area_ids() query_args = [Model] query_filters = [ Submission.Model.areaId.in_(user_access_area_ids), Template.Model.templateId == Model.templateId, Submission.Model.submissionId == Model.tallySheetId, Election.Model.electionId == Submission.Model.electionId ] query_group_by = [Model.tallySheetId] if areaId is not None: query_filters.append(Submission.Model.areaId == areaId) if electionId is not None: election = Election.get_by_id(electionId=electionId) query_filters.append( Election.Model.electionId.in_( election.get_this_and_below_election_ids())) if tallySheetCode is not None: query_filters.append(Template.Model.templateName == tallySheetCode) if voteType is not None: query_filters.append(Election.Model.voteType == voteType) if partyId is not None: query_filters += [ MetaData.Model.metaId == Model.metaId, MetaData.Model.metaDataKey == "partyId", MetaData.Model.metaDataValue == partyId ] tally_sheet_list = db.session.query(*query_args).filter( *query_filters).group_by(*query_group_by).order_by(Model.tallySheetId) tally_sheet_list = get_paginated_query(query=tally_sheet_list, limit=limit, offset=offset) authorized_tally_sheet_list = [] for tally_sheet in tally_sheet_list: if has_role_based_access(election=tally_sheet.submission.election, tally_sheet_code=tally_sheet.tallySheetCode, access_type=WORKFLOW_ACTION_TYPE_VIEW): authorized_tally_sheet_list.append(tally_sheet) return authorized_tally_sheet_list
def create(cls, tallySheetId): tally_sheet = TallySheet.get_by_id(tallySheetId=tallySheetId) if tally_sheet is None: raise NotFoundException( message="Tally sheet not found. (tallySheetId=%d)" % tallySheetId, code=MESSAGE_CODE_TALLY_SHEET_NOT_FOUND ) # Validate the authorization if not has_role_based_access(tally_sheet=tally_sheet, access_type=WORKFLOW_ACTION_TYPE_SAVE): raise UnauthorizedException( message="Not authorized to edit tally sheet. (tallySheetId=%d)" % tallySheetId, code=MESSAGE_CODE_TALLY_SHEET_NOT_AUTHORIZED_TO_EDIT ) return TallySheetVersionModel(tallySheetId=tallySheetId)
def _get_allowed_workflow_actions(self, workflow_action_type): workflow_actions = db.session.query(WorkflowActionModel).filter( WorkflowActionModel.fromStatus == WorkflowInstance.Model.status, WorkflowInstance.Model.workflowInstanceId == self.tallySheet.workflowInstanceId, Workflow.Model.workflowId == WorkflowInstance.Model.workflowId, WorkflowActionModel.workflowId == WorkflowInstance.Model.workflowId, WorkflowActionModel.actionType == workflow_action_type).all() authorized_workflow_actions = [] for workflow_action in workflow_actions: if has_role_based_access(tally_sheet=self.tallySheet, access_type=workflow_action.actionType): authorized_workflow_actions.append(workflow_action) return authorized_workflow_actions
def get_all(electionId=None, areaId=None, tallySheetCode=None, voteType=None): # Filter by authorized areas user_access_area_ids: Set[int] = get_user_access_area_ids() query_args = [Model] query_filters = [ Submission.Model.areaId.in_(user_access_area_ids), Template.Model.templateId == Model.templateId, Submission.Model.submissionId == Model.tallySheetId, Election.Model.electionId == Submission.Model.electionId ] query_group_by = [Model.tallySheetId] if areaId is not None: query_filters.append(Submission.Model.areaId == areaId) if electionId is not None: election = Election.get_by_id(electionId=electionId) query_filters.append( Election.Model.electionId.in_( election.get_this_and_below_election_ids())) if tallySheetCode is not None: query_filters.append(Template.Model.templateName == tallySheetCode) if voteType is not None: query_filters.append(Election.Model.voteType == voteType) tally_sheet_list = db.session.query(*query_args).filter( *query_filters).group_by(*query_group_by) authorized_tally_sheet_list = [] for tally_sheet in tally_sheet_list: if has_role_based_access(tally_sheet=tally_sheet, access_type=WORKFLOW_ACTION_TYPE_VIEW): authorized_tally_sheet_list.append(tally_sheet) return authorized_tally_sheet_list
def _append_latest_workflow_instance_to_cached_tally_sheets( cached_tally_sheets): cached_tally_sheet_ids = [ cached_tally_sheet["tallySheetId"] for cached_tally_sheet in cached_tally_sheets ] tally_sheet_workflow_instances = WorkflowInstance.Model.query.filter( WorkflowInstance.Model.workflowInstanceId == TallySheet.Model.workflowInstanceId, TallySheet.Model.tallySheetId.in_(cached_tally_sheet_ids)).all() tally_sheet_workflow_instances_map = { tally_sheet_workflow_instance.workflowInstanceId: tally_sheet_workflow_instance for tally_sheet_workflow_instance in tally_sheet_workflow_instances } tally_sheet_elections = db.session.query( Election.Model.electionId, Election.Model.electionTemplateName, Election.Model.voteType).filter( Election.Model.electionId == Submission.Model.electionId, Submission.Model.submissionId.in_(cached_tally_sheet_ids)).all() tally_sheet_elections_map = { tally_sheet_election.electionId: tally_sheet_election for tally_sheet_election in tally_sheet_elections } for tally_sheet_index in range(len(cached_tally_sheet_ids)): cached_tally_sheet = cached_tally_sheets[tally_sheet_index] tally_sheet_workflow_instance_id = cached_tally_sheet[ "workflowInstanceId"] workflow_instance = tally_sheet_workflow_instances_map[ tally_sheet_workflow_instance_id] workflow_actions = workflow_instance.workflow.actions # Convert the actions list to a list of dictionary objects due to following issue # https://github.com/ECLK/results-tabulation/issues/708 workflow_action_dict_list = [] for workflow_action in workflow_actions: workflow_action_dict_list.append({ "workflowActionId": workflow_action.workflowActionId, "actionName": workflow_action.actionName, "actionType": workflow_action.actionType, "fromStatus": workflow_action.fromStatus, "toStatus": workflow_action.toStatus, "allowed": workflow_action.fromStatus == workflow_instance.status, "authorized": has_role_based_access( election=tally_sheet_elections_map[ cached_tally_sheet["electionId"]], tally_sheet_code=cached_tally_sheet["tallySheetCode"], access_type=workflow_action.actionType) }) setattr(workflow_instance, "actions", workflow_action_dict_list) cached_tally_sheet["workflowInstance"] = WorkflowInstanceSchema().dump( workflow_instance).data return cached_tally_sheets