Exemplo n.º 1
0
def process_once(config):
    count = 0
    n_errors = 0
    while True:
        with model.session_scope() as session:
            record = (session.query(
                model.Submission,
                model.Survey.modified).join(model.Survey).filter(
                    (model.Submission.modified < model.Survey.modified)
                    | ((model.Submission.modified == None)
                       & (model.Survey.modified != None))).first())
            if record is None:
                break
            sub, htime = record
            log.info("Processing %s, %s < %s", sub, sub and sub.modified,
                     htime)
            if count == 0:
                log.info("Starting new job")

            calculator = Calculator.scoring(sub)
            calculator.mark_entire_survey_dirty(sub.survey)
            calculator.execute()
            if sub.error:
                n_errors += 1
            count += 1

            sub.modified = sub.survey.modified
            session.commit()

    log.info("Successfully recalculated scores for %d submissions.", count)
    log.info("Of those, %d contain user errors.", n_errors)
    return count, n_errors
Exemplo n.º 2
0
            def create_surveys(hsons):
                surveys = []
                for hson in hsons:
                    survey = model.Survey(program=program,
                                          title=hson['title'],
                                          description=hson['description'],
                                          deleted=hson.get('deleted', False))
                    survey.structure = hson['structure']
                    session.add(survey)

                    # Explicitly add to collection because backref is one-way.
                    if not hson.get('deleted', False):
                        program.surveys.append(survey)

                    survey.qnodes = create_qnodes(hson['qnodes'], survey)
                    survey.qnodes.reorder()

                    if 'dependencies' in hson:
                        link_measures(survey, hson['dependencies'])

                    calculator = Calculator.structural()
                    calculator.mark_entire_survey_dirty(survey)
                    calculator.execute()
                    # print_survey(survey)
                return surveys
Exemplo n.º 3
0
    def create_submission(self, survey, user):
        session = object_session(survey)
        program = survey.program
        submission = model.Submission(program=program,
                                      organisation=user.organisation,
                                      survey=survey,
                                      title="First submission",
                                      approval='draft')
        session.add(submission)

        for m in program.measures:
            # Preload response type to avoid autoflush
            response_type = m.response_type
            qnode_measure = m.get_qnode_measure(survey)
            if not qnode_measure:
                continue
            response = model.Response(qnode_measure=qnode_measure,
                                      submission=submission,
                                      user=user)
            response.attachments = []
            response.not_relevant = False
            response.modified = datetime.datetime.utcnow()
            response.approval = 'final'
            response.comment = "Response for %s" % m.title
            session.add(response)
            if response_type.name == 'Yes / No':
                response.response_parts = [{'index': 1, 'note': "Yes"}]
            elif response_type.name in {
                    'Numerical', 'External Numerical', 'Planned', 'Actual'
            }:
                response.response_parts = [{'value': 1}]
            else:
                raise ValueError("Unknown response type")

            response.attachments.append(
                model.Attachment(file_name="File %s 1" % m.title,
                                 url="Bar",
                                 storage='external',
                                 organisation=user.organisation))
            response.attachments.append(
                model.Attachment(file_name="File %s 2" % m.title,
                                 url="Baz",
                                 storage='external',
                                 organisation=user.organisation))
            response.attachments.append(
                model.Attachment(file_name="File %s 3" % m.title,
                                 blob=b'A blob',
                                 storage='external',
                                 organisation=user.organisation))

        session.flush()

        calculator = Calculator.scoring(submission)
        calculator.mark_entire_survey_dirty(submission.survey)
        calculator.execute()
        submission.approval = 'final'
        session.flush()
        return submission
Exemplo n.º 4
0
    def put(self, response_type_id):
        '''Update existing'''

        program_id = self.get_argument('programId', '')

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            response_type = (session.query(model.ResponseType).get(
                (response_type_id, program_id)))
            if not response_type:
                raise errors.MissingDocError("No such response type")

            policy = user_session.policy.derive({
                'program':
                response_type.program,
                'surveygroups':
                response_type.program.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('response_type_edit')

            if 'name' in self.request_son:
                rt_by_name = (session.query(model.ResponseType).filter(
                    model.ResponseType.program_id == program_id).filter(
                        model.ResponseType.name ==
                        self.request_son.name).first())
                if rt_by_name and rt_by_name != response_type:
                    raise errors.ModelError(
                        "'" + self.request_son.name +
                        "' as a response type of that name already exists")

            try:
                self._update(response_type, self.request_son)
            except ResponseTypeError as e:
                raise errors.ModelError(str(e))
            except voluptuous.error.Error as e:
                raise errors.ModelError(str(e))
            except Exception as e:
                raise errors.ModelError(str(e))

            verbs = []
            # Check if modified now to avoid problems with autoflush later
            if session.is_modified(response_type):
                verbs.append('update')
                calculator = Calculator.structural()
                for measure in response_type.measures:
                    for qnode_measure in measure.qnode_measures:
                        calculator.mark_measure_dirty(qnode_measure)
                calculator.execute()

            act = Activities(session)
            act.record(user_session.user, response_type, verbs)
            act.ensure_subscription(user_session.user, response_type,
                                    response_type.program, self.reason)

        self.get(response_type_id)
Exemplo n.º 5
0
    def delete(self, qnode_id):
        '''Delete existing.'''

        if not qnode_id:
            raise errors.MethodError("Question node ID required")

        program_id = self.get_argument('programId', '')

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            qnode = (
                session.query(model.QuestionNode)
                .options(joinedload('program'))
                .options(joinedload('program.surveygroups'))
                .get((qnode_id, program_id)))
            if not qnode:
                raise errors.MissingDocError("No such question node")
            log.debug("deleting: %s", qnode)

            program = qnode.program
            survey = qnode.survey
            parent = qnode.parent

            policy = user_session.policy.derive({
                'program': program,
                'survey': survey,
                'surveygroups': program.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('qnode_del')

            act = Activities(session)
            if not qnode.deleted:
                act.record(user_session.user, qnode, ['delete'])
            act.ensure_subscription(
                user_session.user, qnode, qnode.program, self.reason)

            qnode.deleted = True

            calculator = Calculator.structural()
            if parent:
                parent.children.reorder()
                calculator.mark_qnode_dirty(parent)
            else:
                survey.qnodes.reorder()
                calculator.mark_survey_dirty(survey)
            calculator.execute()

        self.finish()
Exemplo n.º 6
0
    def create_submission(self):
        # Respond to a survey
        with model.session_scope() as session:
            program = session.query(model.Program).one()
            user = (session.query(
                model.AppUser).filter_by(email='clerk').one())
            organisation = (session.query(
                model.Organisation).filter_by(name='Utility').one())
            survey = (session.query(
                model.Survey).filter_by(title='Survey 1').one())
            submission = model.Submission(program_id=program.id,
                                          organisation_id=organisation.id,
                                          survey_id=survey.id,
                                          title="Submission",
                                          approval='draft')
            session.add(submission)

            for m in program.measures:
                # Preload response type to avoid autoflush
                response_type = m.response_type
                qnode_measure = m.get_qnode_measure(survey)
                if not qnode_measure:
                    continue
                response = model.Response(submission=submission,
                                          qnode_measure=qnode_measure,
                                          user=user)
                response.attachments = []
                response.not_relevant = False
                response.modified = sa.func.now()
                response.approval = 'final'
                response.comment = "Response for %s" % m.title
                session.add(response)
                if response_type.name == 'Yes / No':
                    response.response_parts = [{'index': 1, 'note': "Yes"}]
                else:
                    response.response_parts = [{'value': 1}]

            calculator = Calculator.scoring(submission)
            calculator.mark_entire_survey_dirty(submission.survey)
            calculator.execute()

            functions = list(submission.rnodes)
            self.assertAlmostEqual(functions[0].score, 33)
            self.assertAlmostEqual(functions[1].score, 0)
            self.assertAlmostEqual(functions[0].qnode.total_weight, 33)
            self.assertAlmostEqual(functions[1].qnode.total_weight, 0)

            return submission.id
Exemplo n.º 7
0
    def set_approval(self, session, rnode, approval, user_session):
        promote = self.get_arguments('promote')
        missing = self.get_argument('missing', '')

        submission = rnode.submission
        promoted = demoted = created = 0

        calculator = Calculator.scoring(submission)
        for response, is_new in self.walk_responses(
                session, rnode, missing, user_session.user):

            if is_new:
                response.not_relevant = True
                response.approval = approval
                response.comment = "*Marked Not Relevant by bulk approval " \
                    "process (was previously empty)*"
                created += 1
            else:
                i1 = APPROVAL_STATES.index(response.approval)
                i2 = APPROVAL_STATES.index(approval)
                if i1 < i2 and 'PROMOTE' in promote:
                    response.approval = approval
                    response.modified = func.now()
                    promoted += 1
                elif i1 > i2 and 'DEMOTE' in promote:
                    response.approval = approval
                    response.modified = func.now()
                    demoted += 1
            calculator.mark_measure_dirty(response.qnode_measure)

        calculator.execute()

        if created:
            self.reason("Created %d (NA)" % created)
        if demoted:
            self.reason("Demoted %d" % demoted)
        if promoted:
            self.reason("Promoted %d" % promoted)

        if created == promoted == demoted == 0:
            self.reason("No changes to approval status")
Exemplo n.º 8
0
    def put(self, submission_id):
        '''Update existing.'''
        if submission_id == '':
            raise errors.MethodError("Submission ID required")

        approval = self.get_argument('approval', '')

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            submission = session.query(model.Submission).get(submission_id)
            if not submission:
                raise errors.MissingDocError("No such submission")

            policy = user_session.policy.derive({
                'org':
                submission.organisation,
                'approval':
                approval,
                'surveygroups':
                submission.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('submission_edit')

            current_level = 0
            verbs = []
            if approval:
                self.check_approval_down_one(session, submission, approval)
                current_level = APPROVAL_STATES.index(submission.approval)
                if approval != submission.approval:
                    verbs.append('state')
                submission.approval = approval
            self._update(submission, self.request_son)
            if session.is_modified(submission):
                verbs.append('update')

            # update measures approval state, when save edited submission no approval, so here should not
            if approval != '':
                approval_level = APPROVAL_STATES.index(approval)
                if 'state' in verbs and approval_level > current_level:
                    approval_level = approval_level - 1
                    responses = (session.query(model.Response).filter(
                        model.Response.submission_id == submission.id,
                        model.Response.approval ==
                        APPROVAL_STATES[approval_level]))
                    for response in responses:
                        # update = updater(response, error_factory=errors.ModelError)
                        # update('title', son)
                        response.approval = approval
                        try:
                            calculator = Calculator.scoring(submission)
                            calculator.mark_measure_dirty(
                                response.qnode_measure)
                            calculator.execute()
                        except ResponseTypeError as e:
                            raise errors.ModelError(str(e))

                        act = Activities(session)
                        act.record(user_session.user, response, verbs)
                        act.ensure_subscription(user_session.user, response,
                                                response.submission,
                                                self.reason)

            if submission.deleted:
                submission.deleted = False
                verbs.append('undelete')

            act = Activities(session)
            act.record(user_session.user, submission, verbs)
            act.ensure_subscription(user_session.user, submission,
                                    submission.organisation, self.reason)

        self.get(submission_id)
Exemplo n.º 9
0
    def duplicate(self, submission, s_submission, session):
        measure_ids = {
            str(qm.measure_id)
            for qm in submission.survey.ordered_qnode_measures
        }

        qnode_ids = {str(q.id) for q in submission.survey.ordered_qnodes}

        s_rnodes = (session.query(model.ResponseNode).filter_by(
            submission_id=s_submission.id).filter(
                model.ResponseNode.qnode_id.in_(qnode_ids)).all())

        for rnode in s_rnodes:
            if str(rnode.qnode_id) not in qnode_ids:
                continue

            # Duplicate
            session.expunge(rnode)
            make_transient(rnode)

            # Customise
            rnode.program = submission.program
            rnode.submission = submission
            session.add(rnode)
            session.flush()
            # No need to flush because no dependencies

        for response in s_submission.responses:
            if str(response.measure_id) not in measure_ids:
                continue

            attachments = list(response.attachments)

            # Fetch lazy-loaded fields
            response.comment

            # Duplicate
            session.expunge(response)
            make_transient(response)

            # Customise
            response.submission_id = submission.id
            response.program_id = submission.program_id
            response.survey_id = submission.survey_id
            response.approval = 'draft'

            session.add(response)
            session.flush()

            # Same thing for attachments
            for attachment in attachments:
                # Fetch lazy-loaded fields
                attachment.blob

                # Duplicate
                session.expunge(attachment)
                make_transient(attachment)
                attachment.id = None

                # Customise
                attachment.response = response

                session.add(attachment)

        session.flush()
        calculator = Calculator.scoring(submission)
        calculator.mark_entire_survey_dirty(submission.survey)
        calculator.execute()
Exemplo n.º 10
0
    def process_submission_file(self, all_rows, session, submission, user):
        program_qnodes = (session.query(
            model.QuestionNode).filter_by(program_id=submission.program.id))

        try:
            order = title = ''
            for row_num in range(0, len(all_rows) - 1):
                order, title = self.parse_order_title(all_rows, row_num, "A")
                function = program_qnodes.filter_by(parent_id=None,
                                                    title=title).one()
                log.debug("function: %s", function)
                function_order = order

                order, title = self.parse_order_title(all_rows, row_num, "B")
                process = program_qnodes.filter_by(parent_id=function.id,
                                                   title=title).one()
                log.debug("process: %s", process)

                order, title = self.parse_order_title(all_rows, row_num, "C")
                subprocess = program_qnodes.filter_by(parent_id=process.id,
                                                      title=title).one()
                log.debug("subprocess: %s", subprocess)

                order, title = self.parse_order_title(all_rows, row_num, "D")
                measure = [
                    qm.measure for qm in subprocess.qnode_measures
                    if qm.measure.title.split('\n')[0] == title
                ]

                if len(measure) == 1:
                    measure = measure[0]
                else:
                    raise Exception(
                        "This survey does not match the target survey.")
                log.debug("measure: %s", measure)

                log.debug("measure response_type: %s",
                          measure.response_type.name)

                response = model.Response()
                response.program_id = submission.program.id
                response.survey_id = submission.survey.id
                response.measure_id = measure.id
                response.submission_id = submission.id
                response.user_id = user.id
                response.comment = all_rows[row_num][col2num("K")]
                # FIXME: Hard-coded; should be read from file
                response.not_relevant = False
                response.modified = datetime.datetime.utcnow()
                response.approval = 'draft'
                response_part = []

                response_part.append(
                    self.parse_response_type(all_rows, row_num,
                                             measure.response_type, "E"))
                if function_order != "7":
                    response_part.append(
                        self.parse_response_type(all_rows, row_num,
                                                 measure.response_type, "F"))
                    response_part.append(
                        self.parse_response_type(all_rows, row_num,
                                                 measure.response_type, "G"))
                    response_part.append(
                        self.parse_response_type(all_rows, row_num,
                                                 measure.response_type, "H"))
                response.response_parts = response_part
                response.audit_reason = "Import"
                session.add(response)
        except sqlalchemy.orm.exc.NoResultFound:
            raise errors.ModelError(
                "Survey structure does not match: Row %d: %s %s" %
                (row_num + 2, order, title))
        except ImportError as e:
            raise errors.ModelError("Row %d: %s %s: %s" %
                                    (row_num + 2, order, title, str(e)))
        except Exception as e:
            raise errors.InternalModelError(
                "Row %d: %s %s: %s" % (row_num + 2, order, title, str(e)))

        calculator = Calculator.scoring(submission)
        calculator.mark_entire_survey_dirty(submission.survey)
        calculator.execute()
Exemplo n.º 11
0
    def set_relevance(self, session, rnode, relevance, user_session):
        not_relevant = relevance == 'NOT_RELEVANT'
        if not_relevant:
            missing = self.get_argument('missing', '')
        else:
            # When marking responses as not NA, just ignore missing responses.
            # It's not possible to create new ones because a non-NA response
            # must have its response parts filled in.
            missing = 'IGNORE'

        submission = rnode.submission
        changed = failed = created = 0

        calculator = Calculator.scoring(submission)
        for response, is_new in self.walk_responses(
                session, rnode, missing, user_session.user):

            if not_relevant:
                response.not_relevant = True
                if is_new:
                    response.approval = submission.approval
                    response.comment = (
                        "*Marked Not Relevant as a bulk action "
                        "(was previously empty)*")
                    created += 1
                else:
                    changed += 1
            else:
                response.not_relevant = False
                changed += 1

            policy = user_session.policy.derive({
                'org': response.submission.organisation,
                'submission': response.submission,
                'approval': response.approval,
                'index': APPROVAL_STATES.index,
                'surveygroups': response.submission.surveygroups,
            })
            policy.verify('surveygroup_interact')
            try:
                policy.verify('response_edit')
            except errors.AuthzError as e:
                err = (
                    "Response %s: %s. You might need to downgrade the "
                    "response's approval status. You can use the bulk "
                    "approval tool for this.".format(
                        response.qnode_measure.get_path(), e))
                raise errors.AuthzError(err)

            calculator.mark_measure_dirty(response.qnode_measure)

        calculator.execute()

        if created:
            self.reason("Created %d" % created)
        if changed:
            self.reason("Changed %d" % changed)
        if failed:
            self.reason(
                "%d measures could not be changed, because a relevant "
                " response must have valid data." % failed)

        if created == changed == failed == 0:
            self.reason("No changes to relevance")
Exemplo n.º 12
0
    def put(self, submission_id, qnode_id):
        '''Save (create or update).'''

        approval = self.get_argument('approval', '')
        relevance = self.get_argument('relevance', '')

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            submission = (
                session.query(model.Submission)
                .get(submission_id))
            if not submission:
                raise errors.MissingDocError("No such submission")

            policy = user_session.policy.derive({
                'org': submission.organisation,
                'submission': submission,
                'approval': approval,
                'index': APPROVAL_STATES.index,
                'surveygroups': submission.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('rnode_edit')

            rnode = (
                session.query(model.ResponseNode)
                .get((submission_id, qnode_id)))

            verbs = []

            if not rnode:
                qnode = (
                    session.query(model.QuestionNode)
                    .get((qnode_id, submission.program.id)))
                if qnode is None:
                    raise errors.MissingDocError("No such question node")
                rnode = model.ResponseNode.from_qnode(
                    qnode, submission, create=True)

            importance = self.request_son.get('importance')
            if importance is not None:
                if int(importance) <= 0:
                    self.request_son['importance'] = None
                elif int(importance) > 5:
                    self.request_son['importance'] = 5
            urgency = self.request_son.get('urgency')
            if urgency is not None:
                if int(urgency) <= 0:
                    self.request_son['urgency'] = None
                elif int(urgency) > 5:
                    self.request_son['urgency'] = 5
            self._update(rnode, self.request_son)
            if session.is_modified(rnode):
                verbs.append('update')
            session.flush()

            if approval:
                policy.verify('submission_response_approval')
                yield self.set_approval(
                    session, rnode, approval, user_session)
                verbs.append('state')
            if relevance:
                yield self.set_relevance(
                    session, rnode, relevance, user_session)
                verbs.append('update')

            try:
                calculator = Calculator.scoring(submission)
                calculator.mark_qnode_dirty(rnode.qnode)
                calculator.execute()
            except ResponseTypeError as e:
                raise errors.ModelError(str(e))

            act = Activities(session)
            act.record(user_session.user, rnode, verbs)
            act.ensure_subscription(
                user_session.user, rnode, rnode.submission,
                self.reason)

        self.get(submission_id, qnode_id)
Exemplo n.º 13
0
    def put(self, submission_id, measure_id):
        '''Save (create or update).'''

        with model.session_scope(version=True) as session:
            user_session = self.get_user_session(session)

            submission = (session.query(model.Submission).get(submission_id))
            if not submission:
                raise errors.MissingDocError("No such submission")

            response = (session.query(model.Response).get(
                (submission_id, measure_id)))

            verbs = []
            if response is None:
                program_id = submission.program_id
                survey_id = submission.survey_id
                qnode_measure = (session.query(model.QnodeMeasure).get(
                    (program_id, survey_id, measure_id)))
                if qnode_measure is None:
                    raise errors.MissingDocError("No such measure")
                response = model.Response(qnode_measure=qnode_measure,
                                          submission=submission,
                                          approval='draft')
                session.add(response)
                verbs.append('create')
            else:
                same_user = response.user.id == user_session.user.id
                td = datetime.datetime.utcnow() - response.modified
                hours_since_update = td.total_seconds() / 60 / 60

                if same_user and hours_since_update < 8:
                    response.version_on_update = False

                modified = self.request_son.get("latest_modified", 0)
                # Convert to int to avoid string conversion errors during
                # JSON marshalling.
                if int(modified) < int(response.modified.timestamp()):
                    raise errors.ModelError(
                        "This response has changed since you loaded the"
                        " page. Please copy or remember your changes and"
                        " refresh the page.")
                verbs.append('update')

            if self.request_son['approval'] != response.approval:
                verbs.append('state')

            self._update(response, self.request_son, user_session.user)
            if not session.is_modified(response) and 'update' in verbs:
                verbs.remove('update')

            policy = user_session.policy.derive({
                'org':
                submission.organisation,
                'submission':
                submission,
                'approval':
                response.approval,
                'index':
                APPROVAL_STATES.index,
                'surveygroups':
                submission.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('response_edit')

            session.flush()

            # Prevent creating a second version during following operations
            response.version_on_update = False

            try:
                calculator = Calculator.scoring(submission)
                calculator.mark_measure_dirty(response.qnode_measure)
                calculator.execute()
            except ResponseTypeError as e:
                raise errors.ModelError(str(e))

            act = Activities(session)
            act.record(user_session.user, response, verbs)
            act.ensure_subscription(user_session.user, response,
                                    response.submission, self.reason)

        self.get(submission_id, measure_id)
Exemplo n.º 14
0
    def process_structure_file(self, all_rows, session, program):
        response_types = self.create_response_types(session, program)

        survey = model.Survey()
        survey.program = program
        survey.title = "Imported Survey"
        survey.description = None
        with open(
                os.path.join(os.path.dirname(os.path.abspath(__file__)),
                             'aquamark_hierarchy.json')) as data_file:
            survey.structure = json.load(data_file)
        session.add(survey)
        session.flush()

        log.info("survey: %s" % survey.id)

        function_title_row = [{
            "title": row[col2num("J")],
            "order": row[col2num("C")],
            "row_num": all_rows.index(row)
        } for row in all_rows if str(row[col2num("S")]) == "Function Header"]

        process_title_row = [{
            "title": row[col2num("J")],
            "order": row[col2num("D")],
            "row_num": all_rows.index(row)
        } for row in all_rows if str(row[col2num("S")]) == "Process Header"]

        subprocess_title_row = [{
            "title": row[col2num("J")],
            "order": row[col2num("E")],
            "row_num": all_rows.index(row)
        } for row in all_rows if str(row[col2num("S")]) == "SubProcess Header"]

        for function in function_title_row:
            function_order = int(function['order'])
            function_title = function['title'].replace(
                "{} - ".format(function_order), "")
            function_description = self.parse_description(
                all_rows, function['row_num'])

            qnode_function = model.QuestionNode()
            qnode_function.program = program
            qnode_function.survey = survey
            qnode_function.seq = function_order - 1
            qnode_function.title = function_title
            qnode_function.description = bleach.clean(function_description,
                                                      strip=True)

            session.add(qnode_function)
            session.flush()

            process_row = [
                row for row in process_title_row
                if "{}.".format(function_order) in row['title']
            ]

            for process in process_row:
                process_order = int(process['order'])
                process_title = process['title'].replace(
                    "{}.{} - ".format(function_order, process_order), "")

                # print("process order:", process_order)
                # print("process title:", process_title)
                process_description = self.parse_description(
                    all_rows, process['row_num'], "")

                qnode_process = model.QuestionNode()
                qnode_process.program = program
                qnode_process.survey = survey
                qnode_process.parent = qnode_function
                qnode_process.seq = process_order - 1
                qnode_process.title = process_title
                qnode_process.description = bleach.clean(process_description,
                                                         strip=True)
                # log.info("qnode_process: %s" % qnode_process)
                session.add(qnode_process)
                session.flush()

                subprocess_row = [
                    row for row in subprocess_title_row if "{}.{}.".format(
                        function_order, process_order) in row['title']
                ]
                for subprocess in subprocess_row:
                    subprocess_order = int(subprocess['order'])
                    subprocess_title = subprocess['title'].replace(
                        "{}.{}.{} - ".format(function_order, process_order,
                                             subprocess_order), "")

                    # print("subprocess order:", subprocess_order)
                    # print("subprocess title:", subprocess_title)
                    subprocess_description = self.parse_description(
                        all_rows, subprocess['row_num'], "")

                    qnode_subprocess = model.QuestionNode()
                    qnode_subprocess.program = program
                    qnode_subprocess.survey = survey
                    qnode_subprocess.parent = qnode_process
                    qnode_subprocess.seq = subprocess_order - 1
                    qnode_subprocess.title = subprocess_title
                    qnode_subprocess.description = bleach.clean(
                        subprocess_description, strip=True)

                    session.add(qnode_subprocess)
                    session.flush()

                    measure_title_row = [
                        {
                            "title": row[col2num("k")],
                            "row_num": all_rows.index(row),
                            "order": row[col2num("F")],
                            "weight": row[col2num("L")],
                            "resp_num": row[col2num("F")]
                        } for row in all_rows
                        if function_order == row[col2num("C")]
                        and process_order == row[col2num("D")]
                        and subprocess_order == row[col2num("E")]
                        and row[col2num("F")] != 0 and row[col2num("G")] == 1
                    ]

                    for measure in measure_title_row:
                        measure_order = int(measure["order"])
                        measure_title = measure['title'].replace(
                            "{}.{}.{}.{} - ".format(function_order,
                                                    process_order,
                                                    subprocess_order,
                                                    measure_order), "")

                        measure_description = self.parse_description(
                            all_rows, measure['row_num'], "Description")
                        # Comments are part of the response, so ignore that
                        # row
                        measure_weight = measure['weight']

                        m = model.Measure()
                        m.program = program
                        m.title = measure_title
                        m.weight = measure_weight
                        m.description = bleach.clean(measure_description,
                                                     strip=True)
                        rt_id = "standard"
                        if function_order == 7:
                            rt_id = "business-support-%s" % int(
                                measure['resp_num'])
                        # log.info("response_type: %s", rt_id)
                        m.response_type = response_types[rt_id]
                        session.add(m)
                        session.flush()
                        qnode_measure = model.QnodeMeasure(
                            program=program,
                            survey=survey,
                            qnode=qnode_subprocess,
                            measure=m)
                        qnode_subprocess.qnode_measures.reorder()
                        session.add(qnode_measure)
                        session.flush()

        calculator = Calculator.structural()
        calculator.mark_entire_survey_dirty(survey)
        calculator.execute()
Exemplo n.º 15
0
    def put(self, program_id):
        '''
        Update an existing program.
        '''
        if program_id == '':
            raise errors.MethodError("Can't use PUT for new program (no ID).")

        editable = self.get_argument('editable', '')
        if editable != '':
            self._update_state(program_id, truthy(editable))
            return

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            program = session.query(model.Program).get(program_id)
            if not program:
                raise errors.MissingDocError("No such program")

            try:
                groups_changed = assign_surveygroups(user_session, program,
                                                     self.request_son)
            except ValueError as e:
                raise errors.ModelError(str(e))

            policy = user_session.policy.derive({
                'program':
                program,
                'surveygroups':
                program.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('program_edit')

            if not program.is_editable:
                raise errors.MethodError("This program is closed for editing")

            calculator = Calculator.structural()
            if self.request_son['has_quality'] != program.has_quality:
                # Recalculate stats for surveys. This will trigger the
                # recalculation of the submissions in the recalculation
                # daemon.
                for survey in program.surveys:
                    calculator.mark_survey_dirty(survey)

            self._update(program, self.request_son)

            calculator.execute()

            verbs = []
            if session.is_modified(program) or groups_changed:
                verbs.append('update')

            if program.deleted:
                program.deleted = False
                verbs.append('undelete')

            act = Activities(session)
            act.record(user_session.user, program, verbs)
            act.ensure_subscription(user_session.user, program, program,
                                    self.reason)
        self.get(program_id)
Exemplo n.º 16
0
    def put(self, qnode_id):
        '''Update existing.'''

        if not qnode_id:
            self.ordering()
            return

        program_id = self.get_argument('programId', '')
        parent_id = self.get_argument('parentId', '')

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            qnode = (
                session.query(model.QuestionNode)
                .options(joinedload('program'))
                .options(joinedload('program.surveygroups'))
                .get((qnode_id, program_id)))
            if not qnode:
                raise errors.MissingDocError("No such question node")

            policy = user_session.policy.derive({
                'program': qnode.program,
                'survey': qnode.survey,
                'surveygroups': qnode.program.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('qnode_edit')

            self._update(session, qnode, self.request_son)

            verbs = []
            if session.is_modified(qnode):
                verbs.append('update')

            calculator = Calculator.structural()
            if parent_id and str(qnode.parent_id) != parent_id:
                # Change parent
                old_parent = qnode.parent
                new_parent = (
                    session.query(model.QuestionNode)
                    .get((parent_id, program_id)))
                if new_parent.survey != qnode.survey:
                    raise errors.ModelError("Can't move to different survey")
                if not new_parent:
                    raise errors.ModelError("No such question node")
                old_parent.children.remove(qnode)
                old_parent.children.reorder()
                new_parent.children.append(qnode)
                new_parent.children.reorder()
                calculator.mark_qnode_dirty(old_parent)
                calculator.mark_qnode_dirty(qnode)
                self.reason("Moved from %s to %s" % (
                    old_parent.title, new_parent.title))
                verbs.append('relation')

            if qnode.deleted:
                # Get a reference to the collection before changing the
                # deleted flag - otherwise, if a query is needed to
                # instantiate the collection, it will seem as if the object
                # is already in the collection and insert will not work as
                # expected.
                if qnode.parent:
                    collection = qnode.parent.children
                else:
                    collection = qnode.survey.qnodes
                qnode.deleted = False
                collection.insert(qnode.seq, qnode)
                collection.reorder()
                calculator.mark_qnode_dirty(qnode)
                verbs.append('undelete')

            calculator.execute()

            act = Activities(session)
            act.record(user_session.user, qnode, verbs)
            act.ensure_subscription(
                user_session.user, qnode, qnode.program, self.reason)

        self.get(qnode_id)
Exemplo n.º 17
0
    def post(self, qnode_id):
        '''Create new.'''

        if qnode_id:
            raise errors.MethodError("Can't use POST for existing object")

        program_id = self.get_argument('programId', '')
        survey_id = self.get_argument('surveyId', '')
        parent_id = self.get_argument('parentId', '')

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            program = (
                session.query(model.Program)
                .options(joinedload('surveygroups'))
                .get(program_id))
            if not program:
                raise errors.ModelError("No such program")

            qnode = model.QuestionNode(program=program)
            self._update(session, qnode, self.request_son)
            log.debug("new: %s", qnode)

            if survey_id:
                survey = (
                    session.query(model.Survey)
                    .get((survey_id, program_id)))
                if not survey:
                    raise errors.ModelError("No such survey")
            else:
                survey = None
            log.debug("survey: %s", survey)

            if parent_id:
                parent = (
                    session.query(model.QuestionNode)
                    .get((parent_id, program_id)))
                if not parent:
                    raise errors.ModelError("Parent does not exist")
                if not survey:
                    survey = parent.survey
                elif parent.survey != survey:
                    raise errors.ModelError(
                        "Parent does not belong to that survey")
            else:
                parent = None

            qnode.survey = survey

            if parent:
                log.debug("Appending to parent")
                parent.children.append(qnode)
                parent.children.reorder()
                log.debug("committing: %s", parent.children)
            elif survey:
                log.debug("Appending to survey")
                survey.qnodes.append(qnode)
                survey.qnodes.reorder()
                log.debug("committing: %s", survey.qnodes)
            else:
                raise errors.ModelError("Parent or survey ID required")

            # Need to flush so object has an ID to record action against.
            session.flush()

            policy = user_session.policy.derive({
                'program': qnode.program,
                'survey': qnode.survey,
                'surveygroups': qnode.program.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('qnode_add')

            calculator = Calculator.structural()
            calculator.mark_qnode_dirty(qnode)
            calculator.execute()

            qnode_id = str(qnode.id)

            act = Activities(session)
            act.record(user_session.user, qnode, ['create'])
            act.ensure_subscription(
                user_session.user, qnode, qnode.program, self.reason)

        self.get(qnode_id)