Exemple #1
0
    def buildProfile(self, input, survey, session):
        idmap = {}
        for profilequestion in survey.values():
            if not IProfileQuestion.providedBy(profilequestion):
                continue
            idmap[profilequestion.external_id] = profilequestion
        if not idmap:
            return ({}, {})

        profile = {}
        keuzemap = {}  # Map `keuze' to profile index
        for facet in input.profiel.facet:
            question = idmap.get(facet.attrib["vraag-id"])
            if question is None:
                continue
            if question.type == "optional":
                profile[question.id] = True
                keuzemap[facet.keuze.attrib["antwoord"]] = 0
            elif question.type == "repeat":
                profile[question.id] = []
                for (i, keuze) in enumerate(facet.keuze):
                    antwoord = attr_unicode(keuze, "antwoord")
                    profile[question.id].append(antwoord)
                    keuzemap[keuze.attrib["antwoord"]] = i

        return (profile, keuzemap)
Exemple #2
0
    def update(self):
        if redirectOnSurveyUpdate(self.request):
            return
        if self.request.environ["REQUEST_METHOD"] == "POST":
            return self._update()

        context = aq_inner(self.context)
        module = self.request.survey.restrictedTraverse(
            self.context.zodb_path.split("/"))
        self.module = module
        if ((IProfileQuestion.providedBy(module) and context.depth == 2)
                or (ICustomRisksModule.providedBy(module)
                    and self.phase == 'actionplan')):
            next = FindNextQuestion(context, filter=self.question_filter)
            if next is None:
                if self.phase == 'identification':
                    url = "%s/actionplan" % self.request.survey.absolute_url()
                elif self.phase == 'evaluation':
                    url = "%s/actionplan" % self.request.survey.absolute_url()
                elif self.phase == 'actionplan':
                    url = "%s/report" % self.request.survey.absolute_url()
            else:
                url = QuestionURL(self.request.survey, next, phase=self.phase)
            return self.request.response.redirect(url)
        else:
            return self._update()
Exemple #3
0
    def exportSurvey(self, parent, survey):
        """ :returns: An XML node with the details of an :obj:`euphorie.content.survey`.
        """
        node = etree.SubElement(parent, "survey")
        if getattr(survey, "external_id", None):
            node.attrib["external-id"] = survey.external_id
        etree.SubElement(node, "title").text = aq_parent(survey).title
        if StripMarkup(survey.introduction):
            etree.SubElement(node, "introduction").text = StripUnwanted(
                survey.introduction)
        if survey.classification_code:
            etree.SubElement(node, "classification-code").text = \
                    survey.classification_code
        etree.SubElement(node, "language").text = survey.language
        etree.SubElement(node, "evaluation-algorithm").text = \
                aq_parent(survey).evaluation_algorithm
        etree.SubElement(node, "evaluation-optional").text = \
                "true" if survey.evaluation_optional else "false"

        for child in survey.values():
            if IProfileQuestion.providedBy(child):
                self.exportProfileQuestion(node, child)
            if IModule.providedBy(child):
                self.exportModule(node, child)
        return node
Exemple #4
0
def BuildSurveyTree(survey, profile, dbsession, old_session=None):
    """(Re)build the survey SQL tree. The existing tree for the
    session is deleted before a new tree is created.

    :param survey: survey to build tree for
    :type survey: :py:class:`euphorie.content.survey.Survey`
    :param profile: desired profile to be used for the tree
    :type profile: dictionary
    :param dbsession: session to build tree in. Defaults to currently active
          session.
    :type dbsession: :py:class:`euphorie.client.model.SurveySession`
    """
    dbsession.reset()

    for child in survey.values():
        if ICustomRisksModule.providedBy(child):
            AddToTree(dbsession, child)
            # Now copy over the custom risks
            risks = get_custom_risks(old_session)
            if risks:
                # find the module that holds the custom risks
                modules = (Session.query(model.Module).filter(
                    sql.and_(
                        model.Module.session_id == dbsession.id,
                        model.Module.module_id == child.id,
                    )).all())
                # there should only ever be 1 result
                if modules:
                    for risk in risks:
                        modules[0].addChild(risk)
        elif IProfileQuestion.providedBy(child):
            # Safeguard against double adding of profile questions
            existing = [
                getattr(item, "module_id") for item in dbsession.children()
            ]
            if child.id in existing:
                continue
            p = profile.get(child.id)
            if not p:
                continue

            if isinstance(p, list):
                profile_question = AddToTree(
                    dbsession,
                    child,
                    title=child.title,
                    profile_index=-1,
                    skip_children=True,
                )
                for (index, title) in enumerate(p):
                    AddToTree(profile_question,
                              child,
                              title=title,
                              profile_index=index)
            # If we get a bool, it will be True, because of `if not p` above
            # Simply add the profile to the tree, don't care about locations
            elif isinstance(p, bool):
                AddToTree(dbsession, child, title=child.title)
        else:
            AddToTree(dbsession, child)
Exemple #5
0
    def update(self):
        if redirectOnSurveyUpdate(self.request):
            return
        if self.request.environ["REQUEST_METHOD"] == "POST":
            return self._update()

        context = aq_inner(self.context)
        module = self.request.survey.restrictedTraverse(
            self.context.zodb_path.split("/"))
        self.module = module
        if (
            (IProfileQuestion.providedBy(module) and context.depth == 2) or
            (ICustomRisksModule.providedBy(module) and self.phase == 'actionplan')
        ):
            next = FindNextQuestion(context, filter=self.question_filter)
            if next is None:
                if self.phase == 'identification':
                    url = "%s/actionplan" % self.request.survey.absolute_url()
                elif self.phase == 'evaluation':
                    url = "%s/actionplan" % self.request.survey.absolute_url()
                elif self.phase == 'actionplan':
                    url = "%s/report" % self.request.survey.absolute_url()
            else:
                url = QuestionURL(self.request.survey, next, phase=self.phase)
            return self.request.response.redirect(url)
        else:
            return self._update()
Exemple #6
0
 def ImportProfileQuestion(self, node, survey):
     profile = upload.SurveyImporter.ImportProfileQuestion(self, node, survey)
     if IProfileQuestion.providedBy(profile):
         for field in PQ_FIELDS:
             setattr(profile, field,
                     upload.el_unicode(node, field.replace('_', '-')))
     return profile
Exemple #7
0
    def getDesiredProfile(self):
        """Get the requested profile from the request.

        The profile is returned as a dictionary. The id of the profile
        questions are used as keys. For optional profile questions the value is
        a boolean.  For repetable profile questions the value is a list of
        titles as provided by the user. This format is compatible with
        :py:func:`extractProfile`.

        :rtype: dictionary with profile answers
        """
        profile = {}
        for (id, answer) in self.request.form.items():
            question = self.context.get(id)
            if not IProfileQuestion.providedBy(question):
                continue
            if not self.request.form.get("pq{0}.present".format(id), '') == 'yes':
                continue
            if isinstance(answer, list):
                profile[id] = filter(None, (a.strip() for a in answer))
                if not self.request.form.get("pq{0}.multiple".format(id), '') == 'yes':
                    profile[id] = profile[id][:1]
            else:
                profile[id] = answer
        return profile
Exemple #8
0
    def exportSurvey(self, parent, survey):
        """ :returns: An XML node with the details of an :obj:`euphorie.content.survey`.
        """
        node = etree.SubElement(parent, "survey")
        if getattr(survey, "external_id", None):
            node.attrib["external-id"] = survey.external_id
        etree.SubElement(node, "title").text = aq_parent(survey).title
        if StripMarkup(survey.introduction):
            etree.SubElement(node, "introduction").text = StripUnwanted(
                survey.introduction)
        if survey.classification_code:
            etree.SubElement(node, "classification-code").text = \
                    survey.classification_code
        etree.SubElement(node, "language").text = survey.language
        etree.SubElement(node, "evaluation-algorithm").text = \
                aq_parent(survey).evaluation_algorithm
        etree.SubElement(node, "evaluation-optional").text = \
                "true" if survey.evaluation_optional else "false"

        for child in survey.values():
            if IProfileQuestion.providedBy(child):
                self.exportProfileQuestion(node, child)
            if IModule.providedBy(child):
                self.exportModule(node, child)
        return node
Exemple #9
0
 def ImportProfileQuestion(self, node, survey):
     profile = upload.SurveyImporter.ImportProfileQuestion(
         self, node, survey)
     if IProfileQuestion.providedBy(profile):
         for field in PQ_FIELDS:
             setattr(profile, field,
                     upload.el_unicode(node, field.replace('_', '-')))
     return profile
Exemple #10
0
    def _morph(self, child):
        state = getMultiAdapter((child, self.request),
                                name="plone_context_state")

        return dict(id=child.id,
                    title=child.title,
                    url=state.view_url(),
                    is_profile_question=IProfileQuestion.providedBy(child))
Exemple #11
0
    def _morph(self, child):
        state = getMultiAdapter(
                    (child, self.request),
                    name="plone_context_state")

        return dict(id=child.id,
                    title=child.title,
                    url=state.view_url(),
                    is_profile_question=IProfileQuestion.providedBy(child))
Exemple #12
0
def BuildSurveyTree(survey, profile={}, dbsession=None, old_session=None):
    """(Re)build the survey SQL tree. The existing tree for the
    session is deleted before a new tree is created.

    :param survey: survey to build tree for
    :type survey: :py:class:`euphorie.content.survey.Survey`
    :param profile: desired profile to be used for the tree
    :type profile: dictionary
    :param dbsession: session to build tree in. Defaults to currently active
          session.
    :type dbsession: :py:class:`euphorie.client.model.SurveySession`
    """
    if dbsession is None:
        dbsession = SessionManager.session
    dbsession.reset()

    for child in survey.values():
        if ICustomRisksModule.providedBy(child):
            AddToTree(dbsession, child)
            # Now copy over the custom risks
            risks = get_custom_risks(old_session)
            if risks:
                # find the module that holds the custom risks
                modules = Session.query(model.Module).filter(sql.and_(
                    model.Module.session_id==dbsession.id,
                    model.Module.module_id==child.id)).all()
                # there should only ever be 1 result
                if modules:
                    for risk in risks:
                        modules[0].addChild(risk)
        elif IProfileQuestion.providedBy(child):
            # Safeguard against double adding of profile questions
            existing = [
                getattr(item, 'module_id') for item in dbsession.children()]
            if child.id in existing:
                continue
            p = profile.get(child.id)
            if not p:
                continue

            if isinstance(p, list):
                profile_question = AddToTree(
                    dbsession, child, title=child.title,
                    profile_index=-1, skip_children=True)
                for (index, title) in enumerate(p):
                    AddToTree(
                        profile_question, child, title=title,
                        profile_index=index)
            # If we get a bool, it will be True, because of `if not p` above
            # Simply add the profile to the tree, don't care about locations
            elif isinstance(p, bool):
                AddToTree(
                    dbsession, child, title=child.title)
        else:
            AddToTree(dbsession, child)
Exemple #13
0
    def __call__(self):
        # Render the page only if the user has edit rights,
        # otherwise redirect to the start page of the session.
        if not self.webhelpers.can_edit_session:
            return self.request.response.redirect(
                self.context.aq_parent.absolute_url() + "/@@start"
            )

        if self.webhelpers.redirectOnSurveyUpdate():
            return

        context = aq_inner(self.context)
        utils.setLanguage(self.request, self.survey, self.survey.language)

        module = self.webhelpers.traversed_session.restrictedTraverse(
            context.zodb_path.split("/")
        )
        if self.request.environ["REQUEST_METHOD"] == "POST":
            return self.save_and_continue(module)

        if IProfileQuestion.providedBy(module) and context.depth == 2:

            if self.next_question is None:
                url = self.next_phase_url
            else:
                url = self.next_question_url
            return self.request.response.redirect(url)

        self.title = module.title
        self.module = module
        number_files = 0
        for i in range(1, 5):
            number_files += getattr(self.module, "file{0}".format(i), None) and 1 or 0
        self.has_files = number_files > 0
        self.next_is_actionplan = not self.next_question
        if ICustomRisksModule.providedBy(module):
            template = ViewPageTemplateFile(
                "templates/module_identification_custom.pt"
            ).__get__(self, "")
        else:
            template = self.template
        return template()
Exemple #14
0
    def update(self):
        if redirectOnSurveyUpdate(self.request):
            return
        context = aq_inner(self.context)
        module = self.request.survey.restrictedTraverse(
            context.zodb_path.split("/"))
        if self.request.environ["REQUEST_METHOD"] == "POST":
            self.save_and_continue(module)
        else:
            if IProfileQuestion.providedBy(module) and context.depth == 2:
                next = FindNextQuestion(context, filter=self.question_filter)
                if next is None:
                    url = "%s/actionplan" % self.request.survey.absolute_url()
                else:
                    url = QuestionURL(self.request.survey,
                                      next,
                                      phase=self.phase)
                return self.request.response.redirect(url)

            elif ICustomRisksModule.providedBy(module) \
                    and not self.context.skip_children \
                    and len(self.get_custom_risks()):
                url = "%s/customization/%d" % (
                    self.request.survey.absolute_url(), int(self.context.path))
                return self.request.response.redirect(url)

            self.tree = getTreeData(self.request,
                                    context,
                                    filter=model.NO_CUSTOM_RISKS_FILTER)
            self.title = module.title
            self.module = module
            number_files = 0
            for i in range(1, 5):
                number_files += getattr(self.module, 'file{0}'.format(i),
                                        None) and 1 or 0
            self.has_files = number_files > 0
            self.next_is_actionplan = not FindNextQuestion(
                context, filter=self.question_filter)
            super(IdentificationView, self).update()
Exemple #15
0
    def update(self):
        if redirectOnSurveyUpdate(self.request):
            return
        context = aq_inner(self.context)
        module = self.request.survey.restrictedTraverse(
            context.zodb_path.split("/"))
        if self.request.environ["REQUEST_METHOD"] == "POST":
            self.save_and_continue(module)
        else:
            if IProfileQuestion.providedBy(module) and context.depth == 2:
                next = FindNextQuestion(context, filter=self.question_filter)
                if next is None:
                    url = "%s/actionplan" % self.request.survey.absolute_url()
                else:
                    url = QuestionURL(self.request.survey, next, phase=self.phase)
                return self.request.response.redirect(url)

            elif ICustomRisksModule.providedBy(module) \
                    and not self.context.skip_children \
                    and len(self.get_custom_risks()):
                url = "%s/customization/%d" % (
                    self.request.survey.absolute_url(),
                    int(self.context.path))
                return self.request.response.redirect(url)

            self.tree = getTreeData(
                self.request, context, filter=model.NO_CUSTOM_RISKS_FILTER)
            self.title = module.title
            self.module = module
            number_files = 0
            for i in range(1, 5):
                number_files += getattr(
                    self.module, 'file{0}'.format(i), None) and 1 or 0
            self.has_files = number_files > 0
            self.next_is_actionplan = not FindNextQuestion(
                context, filter=self.question_filter)
            super(IdentificationView, self).update()
Exemple #16
0
    def getDesiredProfile(self):
        """Get the requested profile from the request.

        The profile is returned as a dictionary. The id of the profile
        questions are used as keys. For optional profile questions the value is
        a boolean.  For repetable profile questions the value is a list of
        titles as provided by the user. This format is compatible with
        :py:func:`extractProfile`.

        :rtype: dictionary with profile answers
        """
        profile = {}
        for (id, answer) in self.request.form.items():
            match = self.id_patt.match(id)
            if match:
                id = match.group(1)
            question = self.context.get(id)
            if not IProfileQuestion.providedBy(question):
                continue
            if getattr(question, 'use_location_question', True):
                # Ignore questions found via the id pattern if they profile
                # is repeatable
                if match:
                    continue
                if not self.request.form.get("pq{0}.present".format(id),
                                             '') == 'yes':
                    continue
                if isinstance(answer, list):
                    profile[id] = filter(None, (a.strip() for a in answer))
                    if not self.request.form.get("pq{0}.multiple".format(id),
                                                 '') == 'yes':
                        profile[id] = profile[id][:1]
                else:
                    profile[id] = answer
            else:
                profile[id] = answer in (True, 'yes')
        return profile
Exemple #17
0
    def getDesiredProfile(self):
        """Get the requested profile from the request.

        The profile is returned as a dictionary. The id of the profile
        questions are used as keys. For optional profile questions the value is
        a boolean.  For repetable profile questions the value is a list of
        titles as provided by the user. This format is compatible with
        :py:func:`extractProfile`.

        :rtype: dictionary with profile answers
        """
        profile = {}
        for (id, answer) in self.request.form.items():
            match = self.id_patt.match(id)
            if match:
                id = match.group(1)
            question = self.context.get(id)
            if not IProfileQuestion.providedBy(question):
                continue
            if getattr(question, 'use_location_question', True):
                # Ignore questions found via the id pattern if they profile
                # is repeatable
                if match:
                    continue
                if not self.request.form.get(
                        "pq{0}.present".format(id), '') == 'yes':
                    continue
                if isinstance(answer, list):
                    profile[id] = filter(None, (a.strip() for a in answer))
                    if not self.request.form.get("pq{0}.multiple".format(id), '') == 'yes':
                        profile[id] = profile[id][:1]
                else:
                    profile[id] = answer
            else:
                profile[id] = answer in (True, 'yes')
        return profile
Exemple #18
0
    def __call__(self):
        # Render the page only if the user has edit rights,
        # otherwise redirect to the start page of the session.
        if not self.webhelpers.can_edit_session:
            return self.request.response.redirect(
                self.context.aq_parent.aq_parent.absolute_url() + "/@@start"
            )
        if self.webhelpers.redirectOnSurveyUpdate():
            return

        context = aq_inner(self.context)
        utils.setLanguage(self.request, self.survey, self.survey.language)
        if (IProfileQuestion.providedBy(self.module) and context.depth == 2) or (
            ICustomRisksModule.providedBy(self.module) and self.phase == "actionplan"
        ):
            next_question = FindNextQuestion(
                context, self.context.session, filter=self.question_filter
            )
            if next_question is None:
                if self.phase == ("identification", "evaluation"):
                    url = (
                        self.webhelpers.traversed_session.absolute_url()
                        + "/@@actionplan"
                    )
                elif self.phase == "actionplan":
                    url = self.webhelpers.traversed_session.absolute_url() + "/@@report"
            else:
                url = "{session_url}/{path}/@@actionplan".format(
                    session_url=self.webhelpers.traversed_session.absolute_url(),
                    path="/".join(next_question.short_path),
                )
            return self.request.response.redirect(url)

        self.title = self.context.title
        previous = FindPreviousQuestion(
            self.context, self.context.session, filter=self.question_filter
        )
        if previous is None:
            self.previous_url = "%s/@@%s" % (
                self.context.aq_parent.absolute_url(),
                self.phase,
            )
        else:
            self.previous_url = "{session_url}/{path}/@@{phase}".format(
                session_url=self.webhelpers.traversed_session.absolute_url(),
                path="/".join(previous.short_path),
                phase=self.phase,
            )
        next_question = FindNextQuestion(
            self.context, self.context.session, filter=self.question_filter
        )
        if next_question is None:
            self.next_url = (
                self.webhelpers.traversed_session.absolute_url() + "/@@report"
            )
        else:
            self.next_url = "{session_url}/{path}/@@{phase}".format(
                session_url=self.webhelpers.traversed_session.absolute_url(),
                path="/".join(next_question.short_path),
                phase=self.phase,
            )
        return self.index()
Exemple #19
0
def getTreeData(request, context, phase="identification", filter=None):
    """Assemble data for a navigation tree

    This function returns a nested dictionary structure reflecting the
    elements for a navigation tree. The tree will all sibling questions of
    the current context, the current module and all its module siblings, its
    parents up to the root module, and all modules at the root level.

    Optionally a SQLAlchemy clause can be provided, which will be used to
    filter items shown in the tree. The current item and its parents will
    always be shown.

    Each element is reflect as a dictionary item with the following keys:

    - id: the SQL object id
    - type: the SQL object type
    - number: a human presentable numbering of the item
    - title: the object title
    - current: boolean indicating if this is the current context or its
      direct parent module
    - active: boolean indicating if this is a parent node of the current
      context
    - class: CSS classes to use for this node
    - children: a list of child nodes (in the right order)
    - url: URL for this item
    """
    query = Session.query(model.SurveyTreeItem)
    title_custom_risks = utils.get_translated_custom_risks_title(request)
    root = context
    parents = []
    while root.parent_id is not None:
        parent = query.get(root.parent_id)
        parents.append(parent)
        root = parent
    parents.reverse()

    base_url = "%s/%s/" % (request.survey.absolute_url(), phase)

    def morph(obj):
        info = {
            'id':
            obj.id,
            'number':
            obj.number,
            'title':
            obj.title,
            'active':
            obj.path != context.path and context.path.startswith(obj.path),
            'current': (obj.path == context.path),
            'current_parent': (obj.path == context.path[:-3]),
            'path':
            context.path,
            'children': [],
            'type':
            obj.type,
            'leaf_module':
            False,
            'depth':
            obj.depth,
            'url':
            base_url + "/".join(obj.short_path)
        }
        cls = []
        for key in ["active", "current", "current_parent"]:
            if info[key]:
                cls.append(key)

        if obj.postponed:
            cls.append("postponed")
        else:
            if isinstance(obj, model.Risk):
                if obj.identification:
                    cls.append("answered")
                if obj.identification == "no":
                    cls.append("risk")
        info["class"] = cls and " ".join(cls) or None
        return info

    # Result is always pointing to the level *above* the current level.
    # At the end it will be the virtual tree root
    result = {
        'children': [],
        'leaf_module': False,
        'current': False,
        'id': None,
        'title': None
    }
    result["class"] = None
    children = []
    for obj in context.siblings(filter=filter):
        info = morph(obj)
        if obj.type != 'risk' and obj.zodb_path.find('custom-risks') > -1:
            info['title'] = title_custom_risks
        children.append(info)
    result["children"] = children

    if isinstance(context, model.Module):
        # If this is an optional module, check the "postponed" flag.
        # As long as the optional question has not been answered, skip
        # showing its children.
        # Only a "Yes" answer will set skip_children to False
        module = request.survey.restrictedTraverse(
            context.zodb_path.split("/"))
        if (getattr(module, 'optional', False)
                and context.postponed in (True, None)):
            context.skip_children = True
        if not context.skip_children:
            # For modules which do not skip children, include the list of
            # children.
            me = first(lambda x: x["current"], result["children"])
            children = []
            for obj in context.children(filter=filter):
                info = morph(obj)
                # XXX: The check for SurveySession is due to Euphorie tests which don't
                # have a proper canonical ZODB survey object and don't test the
                # following OiRA-specific code.
                if obj.depth == 2 \
                        and not getattr(obj, 'is_custom_risk', False) \
                        and not isinstance(request.survey, SurveySession):
                    module = request.survey.restrictedTraverse(
                        obj.zodb_path.split('/'))
                    if IProfileQuestion.providedBy(module) and \
                            not ICustomRisksModule.providedBy(aq_parent(module)):
                        info['type'] = u'location'
                        info['children'] = [
                            morph(sub) for sub in obj.children(filter=filter)
                        ]
                children.append(info)
            me["children"] = children
            types = set([c["type"] for c in me["children"]])
            me["leaf_module"] = "risk" in types

    elif isinstance(context, model.Risk):
        # For a risk we also want to include all siblings of its module parent
        parent = parents.pop()
        siblings = []
        for obj in parent.siblings(model.Module, filter=filter):
            info = morph(obj)
            if obj.zodb_path.find('custom-risks') > -1:
                info['title'] = title_custom_risks
            siblings.append(info)
        myparent = first(lambda x: x["active"], siblings)
        myparent["children"] = result["children"]
        myparent["leaf_module"] = True
        result["children"] = siblings

    if parents:
        # Add all parents up to the root
        while len(parents) > 1:
            parent = parents.pop()
            new = morph(parent)
            if isinstance(parent, model.Module) and parent.depth == 2:
                module = request.survey.restrictedTraverse(
                    parent.zodb_path.split('/'))
                if IProfileQuestion.providedBy(module) and \
                        not ICustomRisksModule.providedBy(aq_parent(module)):
                    new['type'] = u'location'
            new["children"] = result["children"]
            result["children"] = [new]

        # Finally list all modules at the root level
        parent = parents.pop()
        roots = []
        for obj in parent.siblings(model.Module, filter=filter):
            info = morph(obj)
            if obj.zodb_path.find('custom-risks') > -1:
                info['title'] = title_custom_risks
            roots.append(info)

        myroot = first(lambda x: x["active"], roots)
        myroot["children"] = result["children"]
        result["children"] = roots

    return result
Exemple #20
0
    def update(self):
        super(MeasuresOverview, self).update()
        lang = getattr(self.request, "LANGUAGE", "en")
        if "-" in lang:
            lang = lang.split("-")[0]
        if self.session is not None and self.session.title != (
            callable(getattr(self.context, "Title", None))
            and self.context.Title()
            or ""
        ):
            self.session_title = self.session.title
        else:
            self.session_title = (
                callable(getattr(self.context, "Title", None))
                and self.context.Title()
                or ""
            )
        today = date.today()
        this_month = date(today.year, today.month, 1)
        self.label_page = translate(
            _(u"label_page", default=u"Page"), target_language=lang
        )
        self.label_page_of = translate(
            _(u"label_page_of", default=u"of"), target_language=lang
        )

        def get_next_month(this_month):
            month = this_month.month + 1
            year = this_month.year
            if month == 13:
                month = 1
                year = year + 1
            return date(year, month, 1)

        next_month = get_next_month(this_month)
        month_after_next = get_next_month(next_month)
        self.months = []
        self.months.append(today.strftime("%b"))
        self.months.append(next_month.strftime("%b"))
        self.months.append(month_after_next.strftime("%b"))
        self.monthstrings = [
            translate(
                PloneLocalesFactory(
                    "month_{0}_abbr".format(month.lower()),
                    default=month,
                ),
                target_language=lang,
            )
            for month in self.months
        ]

        query = (
            Session.query(model.Module, model.Risk, model.ActionPlan)
            .select_from(model.Module)
            .filter(
                sql.and_(
                    model.Module.session == self.session,
                    model.Module.profile_index > -1,
                )
            )
            .filter(sql.not_(model.SKIPPED_PARENTS))
            .filter(
                sql.or_(
                    model.MODULE_WITH_RISK_OR_TOP5_FILTER,
                    model.RISK_PRESENT_OR_TOP5_FILTER,
                )
            )
            .join(model.Risk, model.Risk.parent_id == model.Module.id)
            .join(model.ActionPlan, model.ActionPlan.risk_id == model.Risk.id)
            .order_by(
                sql.case(
                    value=model.Risk.priority, whens={"high": 0, "medium": 1}, else_=2
                ),
                model.Risk.path,
            )
        )
        measures = [
            t
            for t in query.all()
            if (
                (
                    (
                        t[-1].planning_start is not None
                        and t[-1].planning_start.strftime("%b") in self.months
                    )
                    or (
                        t[-1].planning_end is not None
                        and t[-1].planning_end.strftime("%b") in self.months
                    )
                    or (
                        t[-1].planning_start is not None
                        and (
                            t[-1].planning_end is None
                            or t[-1].planning_end >= month_after_next
                        )
                        and t[-1].planning_start <= this_month
                    )
                )
                and t[1].identification not in ("n/a", "yes")
                and (
                    t[-1].responsible is not None
                    or t[-1].requirements is not None
                    or t[-1].budget is not None
                    or t[-1].action is not None
                )
            )
        ]

        modulesdict = defaultdict(lambda: defaultdict(list))
        for module, risk, action in measures:
            if "custom-risks" not in risk.zodb_path:
                risk_obj = self.survey.restrictedTraverse(risk.zodb_path.split("/"))
                title = risk_obj and risk_obj.problem_description or risk.title
            else:
                title = risk.title
            classes = []
            start_month = action.planning_start and date(
                action.planning_start.year, action.planning_start.month, 1
            )
            end_month = action.planning_end and date(
                action.planning_end.year, action.planning_end.month, 1
            )
            for m in [this_month, next_month, month_after_next]:
                cls = None
                if start_month:
                    if start_month == m:
                        cls = "start"
                    if end_month:
                        if end_month == m:
                            if end_month == (start_month is not None and start_month):
                                cls = "start-end"
                            else:
                                cls = "end"
                        elif start_month < m and end_month > m:
                            cls = "ongoing"
                    elif start_month < m:
                        cls = "ongoing"
                elif end_month:
                    if end_month == m:
                        cls = "end"
                    elif end_month > m:
                        cls = "ongoing"
                classes.append(cls)
            modulesdict[module][risk.priority].append(
                {
                    "title": title,
                    "description": action.action,
                    "months": [
                        (
                            action.planning_start
                            and action.planning_start.month == m.month
                        )
                        or (
                            action.planning_end and action.planning_end.month == m.month
                        )
                        for m in [today, next_month, month_after_next]
                    ],
                    "classes": classes,
                }
            )

        main_modules = {}
        for module, risks in sorted(modulesdict.items(), key=lambda m: m[0].zodb_path):
            module_obj = self.survey.restrictedTraverse(module.zodb_path.split("/"))
            if (
                IProfileQuestion.providedBy(module_obj)
                or ICustomRisksModule.providedBy(module_obj)
                or module.depth >= 3
            ):
                path = module.path[:6]
            else:
                path = module.path[:3]
            if path in main_modules:
                for prio in risks.keys():
                    if prio in main_modules[path]["risks"]:
                        main_modules[path]["risks"][prio].extend(risks[prio])
                    else:
                        main_modules[path]["risks"][prio] = risks[prio]
            else:
                title = module.title
                number = module.number
                main_modules[path] = {"name": title, "number": number, "risks": risks}

        self.modules = []
        for key in sorted(main_modules.keys()):
            self.modules.append(main_modules[key])
Exemple #21
0
    def update(self):
        self.verify_view_permission()
        super(MeasuresOverview, self).update()
        lang = getattr(self.request, "LANGUAGE", "en")
        if "-" in lang:
            lang = lang.split("-")[0]
        now = datetime.now()
        next_month = datetime(now.year, (now.month + 1) % 12 or 12, 1)
        month_after_next = datetime(now.year, (now.month + 2) % 12 or 12, 1)
        self.months = []
        self.months.append(now.strftime("%b"))
        self.months.append(next_month.strftime("%b"))
        self.months.append(month_after_next.strftime("%b"))
        self.monthstrings = [
            translate(
                PloneLocalesMessageFactory("month_{0}_abbr".format(
                    month.lower()),
                                           default=month),
                target_language=lang,
            ) for month in self.months
        ]

        query = (Session.query(
            Module, Risk, ActionPlan).select_from(Module).filter(
                sql.and_(
                    Module.session == self.session, Module.profile_index >
                    -1)).filter(sql.not_(SKIPPED_PARENTS)).filter(
                        sql.or_(
                            MODULE_WITH_RISK_OR_TOP5_FILTER,
                            RISK_PRESENT_OR_TOP5_FILTER)).join(
                                Risk, Risk.parent_id == Module.id).join(
                                    ActionPlan,
                                    ActionPlan.risk_id == Risk.id).order_by(
                                        sql.case(value=Risk.priority,
                                                 whens={
                                                     "high": 0,
                                                     "medium": 1
                                                 },
                                                 else_=2),
                                        Risk.path,
                                    ))

        measures = [
            t for t in query.all()
            if ((t[-1].planning_end is not None
                 and t[-1].planning_end.strftime("%b") in self.months) and
                (t[-1].planning_start is not None or t[-1].responsible
                 is not None or t[-1].prevention_plan is not None
                 or t[-1].requirements is not None or t[-1].budget is not None
                 or t[-1].action_plan is not None))
        ]

        modulesdict = defaultdict(lambda: defaultdict(list))
        for module, risk, action in measures:
            if "custom-risks" not in risk.zodb_path:
                risk_obj = self.context.restrictedTraverse(
                    risk.zodb_path.split("/"))
                title = risk_obj and risk_obj.problem_description or risk.title
            else:
                title = risk.title
            modulesdict[module][risk.priority or "low"].append({
                "title":
                title,
                "description":
                action.action_plan,
                "months": [
                    action.planning_end
                    and action.planning_end.month == m.month
                    for m in [now, next_month, month_after_next]
                ],
            })

        main_modules = {}
        for module, risks in sorted(modulesdict.items(),
                                    key=lambda m: m[0].zodb_path):
            module_obj = self.context.restrictedTraverse(
                module.zodb_path.split("/"))
            if (IProfileQuestion.providedBy(module_obj)
                    or ICustomRisksModule.providedBy(module_obj)
                    or module.depth >= 3):
                path = module.path[:6]
            else:
                path = module.path[:3]
            if path in main_modules:
                for prio in risks.keys():
                    if prio in main_modules[path]["risks"]:
                        main_modules[path]["risks"][prio].extend(risks[prio])
                    else:
                        main_modules[path]["risks"][prio] = risks[prio]
            else:
                title = module.title
                number = module.number
                if "custom-risks" in module.zodb_path:
                    num_elems = number.split(".")
                    number = ".".join(["Ω"] + num_elems[1:])
                    title = api.portal.translate(_(title))
                main_modules[path] = {
                    "name": title,
                    "number": number,
                    "risks": risks
                }

        self.modules = []
        for key in sorted(main_modules.keys()):
            self.modules.append(main_modules[key])
Exemple #22
0
def getTreeData(request, context, phase="identification", filter=None):
    """Assemble data for a navigation tree

    This function returns a nested dictionary structure reflecting the
    elements for a navigation tree. The tree will all sibling questions of
    the current context, the current module and all its module siblings, its
    parents up to the root module, and all modules at the root level.

    Optionally a SQLAlchemy clause can be provided, which will be used to
    filter items shown in the tree. The current item and its parents will
    always be shown.

    Each element is reflect as a dictionary item with the following keys:

    - id: the SQL object id
    - type: the SQL object type
    - number: a human presentable numbering of the item
    - title: the object title
    - current: boolean indicating if this is the current context or its
      direct parent module
    - active: boolean indicating if this is a parent node of the current
      context
    - class: CSS classes to use for this node
    - children: a list of child nodes (in the right order)
    - url: URL for this item
    """
    query = Session.query(model.SurveyTreeItem)
    title_custom_risks = utils.get_translated_custom_risks_title(request)
    root = context
    parents = []
    while root.parent_id is not None:
        parent = query.get(root.parent_id)
        parents.append(parent)
        root = parent
    parents.reverse()

    base_url = "%s/%s/" % (request.survey.absolute_url(), phase)

    def morph(obj):
        info = {'id': obj.id,
                'number': obj.number,
                'title': obj.title,
                'active': obj.path != context.path and
                                context.path.startswith(obj.path),
                'current': (obj.path == context.path),
                'current_parent': (obj.path == context.path[:-3]),
                'path': context.path,
                'children': [],
                'type': obj.type,
                'leaf_module': False,
                'depth': obj.depth,
                'url': base_url + "/".join(obj.short_path)
                }
        cls = []
        for key in ["active", "current", "current_parent"]:
            if info[key]:
                cls.append(key)

        if obj.postponed:
            cls.append("postponed")
        else:
            if isinstance(obj, model.Risk):
                if obj.identification:
                    cls.append("answered")
                if obj.identification == "no":
                    cls.append("risk")
        info["class"] = cls and " ".join(cls) or None
        return info

    # Result is always pointing to the level *above* the current level.
    # At the end it will be the virtual tree root
    result = {'children': [],
              'leaf_module': False,
              'current': False,
              'id': None,
              'title': None}
    result["class"] = None
    children = []
    for obj in context.siblings(filter=filter):
        info = morph(obj)
        if obj.type != 'risk' and obj.zodb_path.find('custom-risks') > -1:
            info['title'] = title_custom_risks
        children.append(info)
    result["children"] = children

    if isinstance(context, model.Module):
        if not context.skip_children:
            # For modules which do not skip children, include the list of
            # children.
            me = first(lambda x: x["current"], result["children"])
            children = []
            for obj in context.children(filter=filter):
                info = morph(obj)
                # XXX: The check for SurveySession is due to Euphorie tests which don't
                # have a proper canonical ZODB survey object and don't test the
                # following OiRA-specific code.
                if obj.depth == 2 \
                        and not getattr(obj, 'is_custom_risk', False) \
                        and not isinstance(request.survey, SurveySession):
                    module = request.survey.restrictedTraverse(obj.zodb_path.split('/'))
                    if IProfileQuestion.providedBy(module) and \
                            not ICustomRisksModule.providedBy(aq_parent(module)):
                        info['type'] = u'location'
                        info['children'] = [
                            morph(sub) for sub in obj.children(filter=filter)]
                children.append(info)
            me["children"] = children
            types = set([c["type"] for c in me["children"]])
            me["leaf_module"] = "risk" in types

    elif isinstance(context, model.Risk):
        # For a risk we also want to include all siblings of its module parent
        parent = parents.pop()
        siblings = []
        for obj in parent.siblings(model.Module, filter=filter):
            info = morph(obj)
            if obj.zodb_path.find('custom-risks') > -1:
                info['title'] = title_custom_risks
            siblings.append(info)
        myparent = first(lambda x: x["active"], siblings)
        myparent["children"] = result["children"]
        myparent["leaf_module"] = True
        result["children"] = siblings

    if parents:
        # Add all parents up to the root
        while len(parents) > 1:
            parent = parents.pop()
            new = morph(parent)
            if isinstance(parent, model.Module) and parent.depth == 2:
                module = request.survey.restrictedTraverse(parent.zodb_path.split('/'))
                if IProfileQuestion.providedBy(module) and \
                        not ICustomRisksModule.providedBy(aq_parent(module)):
                    new['type'] = u'location'
            new["children"] = result["children"]
            result["children"] = [new]

        # Finally list all modules at the root level
        parent = parents.pop()
        roots = []
        for obj in parent.siblings(model.Module, filter=filter):
            info = morph(obj)
            if obj.zodb_path.find('custom-risks') > -1:
                info['title'] = title_custom_risks
            roots.append(info)

        myroot = first(lambda x: x["active"], roots)
        myroot["children"] = result["children"]
        result["children"] = roots

    return result
Exemple #23
0
    def exportSurvey(self, parent, survey):
        """Export a survey given a parent and the survey itself

        :returns: An XML node with the details of an :obj:`euphorie.content.survey`.
        """
        node = etree.SubElement(parent, "survey")
        if getattr(survey, "external_id", None):
            node.attrib["external-id"] = survey.external_id
        etree.SubElement(node, "title").text = aq_parent(survey).title
        if self.include_intro_text and StripMarkup(survey.introduction):
            node = self._add_string_or_html(node, survey.introduction,
                                            "introduction")
        if survey.classification_code:
            etree.SubElement(
                node, "classification-code").text = survey.classification_code
        etree.SubElement(node, "language").text = survey.language
        if self.is_etranslate_compatible:
            etree.SubElement(node,
                             "tool_type",
                             attrib={"value": get_tool_type(survey)})
            etree.SubElement(
                node,
                "measures_text_handling",
                attrib={
                    "value": getattr(survey, "measures_text_handling", "full")
                },
            )
            etree.SubElement(
                node,
                "integrated_action_plan",
                attrib={
                    "value":
                    "true" if getattr(survey, "integrated_action_plan", False)
                    else "false"
                },
            )
            etree.SubElement(
                node,
                "evaluation-algorithm",
                attrib={"value": aq_parent(survey).evaluation_algorithm},
            )
            etree.SubElement(
                node,
                "evaluation-optional",
                attrib={
                    "value": "true" if survey.evaluation_optional else "false"
                },
            )
        else:
            etree.SubElement(node, "tool_type").text = get_tool_type(survey)
            etree.SubElement(node, "measures_text_handling").text = getattr(
                survey, "measures_text_handling", "full")
            etree.SubElement(
                node, "integrated_action_plan").text = ("true" if getattr(
                    survey, "integrated_action_plan", False) else "false")
            etree.SubElement(node, "evaluation-algorithm").text = aq_parent(
                survey).evaluation_algorithm
            etree.SubElement(node, "evaluation-optional").text = (
                "true" if survey.evaluation_optional else "false")
        if IToolCategory.providedBy(survey):
            tool_category = IToolCategory(survey).tool_category or []
            etree.SubElement(node, "tool-category").text = ", ".join(
                [x.replace(",", COMMA_REPLACEMENT) for x in tool_category])

        if getattr(survey, "external_site_logo", None):
            self.exportImage(node,
                             survey.external_site_logo,
                             tagname="external_site_logo")
        if getattr(survey, "image", None):
            self.exportImage(node, survey.image)

        for child in survey.values():
            if IProfileQuestion.providedBy(child):
                self.exportProfileQuestion(node, child)
            if IModule.providedBy(child):
                self.exportModule(node, child)
        return node
Exemple #24
0
def getTreeData(
    request,
    context,
    element=None,
    phase="identification",
    filter=None,
    survey=None,
    no_current=False,
):
    """Assemble data for a navigation tree

    This function returns a nested dictionary structure reflecting the
    elements for a navigation tree. The tree will all sibling questions of
    the current context, the current module and all its module siblings, its
    parents up to the root module, and all modules at the root level.

    Optionally a SQLAlchemy clause can be provided, which will be used to
    filter items shown in the tree. The current item and its parents will
    always be shown.

    Each element is reflect as a dictionary item with the following keys:

    - id: the SQL object id
    - type: the SQL object type
    - number: a human presentable numbering of the item
    - title: the object title
    - current: boolean indicating if this is the current context or its
      direct parent module
    - active: boolean indicating if this is a parent node of the current
      context
    - class: CSS classes to use for this node
    - children: a list of child nodes (in the right order)
    - url: URL for this item
    """
    if not survey:
        # Standard, real-world case
        webhelpers = api.content.get_view("webhelpers", context, request)
        survey = webhelpers._survey
        traversed_session = webhelpers.traversed_session
    else:
        # XXX Fixme
        # Only in tests...
        # In some tests in test_navigation, the view "webhelpers" cannot be found
        # for the given context. That's why we pass in the survey item directly.
        traversed_session = survey

    # This is the tree element that we start from.
    # It can be the same as the context that gets passed in, if it has an Acquisition
    # chain. On views that are called outside of the context of a module or risk,
    # e.g. the initial @@identification view, the tree-element that we find is not
    # in an acqusition context, so that we cannot use it for fetching the traversed
    # session via webhelpers.
    if not element:
        element = context

    query = Session.query(model.SurveyTreeItem)
    title_custom_risks = utils.get_translated_custom_risks_title(request)
    root = element
    parents = []
    while root.parent_id is not None:
        parent = query.get(root.parent_id)
        parents.append(parent)
        root = parent
    parents.reverse()

    def morph(obj):
        number = obj.number
        # The custom risks don't have a real number, but an Omega instead
        if obj.zodb_path.find("custom-risks") > -1:
            num_elems = number.split(".")
            number = ".".join(["Ω"] + num_elems[1:])
        info = {
            "id":
            obj.id,
            "number":
            number,
            "title":
            obj.title,
            "active": (obj.path != element.path
                       and element.path.startswith(obj.path)),
            "current": (obj.path == element.path),
            "current_parent": (obj.path == element.path[:-3]),
            "path":
            element.path,
            "children": [],
            "type":
            obj.type,
            "leaf_module":
            False,
            "depth":
            obj.depth,
            "url":
            "{session_url}/{obj_path}/@@{phase}".format(
                session_url=traversed_session.absolute_url(),
                obj_path="/".join(obj.short_path),
                phase=phase,
            ),
            "css_id":
            "",
        }
        cls = []
        for key in ["active", "current", "current_parent"]:
            if info[key]:
                if key == "current" and no_current:
                    continue
                cls.append(key)

        if obj.postponed:
            cls.append("postponed")
        else:
            if isinstance(obj, model.Risk):
                if obj.identification:
                    cls.append("answered")
                if obj.identification == "no":
                    cls.append("risk")
        info["class"] = cls and " ".join(cls) or None
        return info

    # Result is always pointing to the level *above* the current level.
    # At the end it will be the virtual tree root
    result = {
        "children": [],
        "leaf_module": False,
        "current": False,
        "id": None,
        "title": None,
    }
    result["class"] = None
    children = []
    for obj in element.siblings(filter=filter):
        info = morph(obj)
        if obj.type != "risk" and obj.zodb_path.find("custom-risks") > -1:
            info["title"] = title_custom_risks
            info["css_id"] = "other-risks"
        children.append(info)
    result["children"] = children

    if isinstance(element, model.Module):
        # If this is an optional module, check the "postponed" flag.
        # As long as the optional question has not been answered, skip
        # showing its children.
        # Only a "Yes" answer will set skip_children to False
        module = survey.restrictedTraverse(element.zodb_path.split("/"))
        # In the custom risks module, we never skip children
        # Due to historical reasons, some custom modules might be set to
        # postponed. Here, we ignore that setting.
        if ICustomRisksModule.providedBy(module):
            element.skip_children = False
        elif getattr(module, "optional",
                     False) and element.postponed in (True, None):
            element.skip_children = True
        if not element.skip_children:
            # For modules which do not skip children, include the list of
            # children.
            me = first(lambda x: x["current"], result["children"])
            children = []
            for obj in element.children(filter=filter):
                info = morph(obj)
                # XXX: The check for SurveySession is due to Euphorie tests which don't
                # have a proper canonical ZODB survey object and don't test the
                # following OiRA-specific code.
                if (obj.depth == 2
                        and not getattr(obj, "is_custom_risk", False)
                        and not isinstance(survey, SurveySession)):
                    module = survey.restrictedTraverse(
                        obj.zodb_path.split("/"))
                    if IProfileQuestion.providedBy(
                            module) and not ICustomRisksModule.providedBy(
                                aq_parent(module)):
                        info["type"] = "location"
                        info["children"] = [
                            morph(sub) for sub in obj.children(filter=filter)
                        ]
                children.append(info)
            me["children"] = children
            types = set([c["type"] for c in me["children"]])
            me["leaf_module"] = "risk" in types

    elif isinstance(element, model.Risk):
        # For a risk we also want to include all siblings of its module parent
        parent = parents.pop()
        siblings = []
        for obj in parent.siblings(model.Module, filter=filter):
            info = morph(obj)
            if obj.zodb_path.find("custom-risks") > -1:
                info["title"] = title_custom_risks
                info["css_id"] = "other-risks"
            siblings.append(info)
        myparent = first(lambda x: x["active"], siblings)
        myparent["children"] = result["children"]
        myparent["leaf_module"] = True
        result["children"] = siblings

    if parents:
        # Add all parents up to the root
        while len(parents) > 1:
            parent = parents.pop()
            new = morph(parent)
            if isinstance(parent, model.Module) and parent.depth == 2:
                module = survey.restrictedTraverse(parent.zodb_path.split("/"))
                if IProfileQuestion.providedBy(
                        module) and not ICustomRisksModule.providedBy(
                            aq_parent(module)):
                    new["type"] = "location"
            new["children"] = result["children"]
            result["children"] = [new]

        # Finally list all modules at the root level
        parent = parents.pop()
        roots = []
        for obj in parent.siblings(model.Module, filter=filter):
            info = morph(obj)
            if obj.zodb_path.find("custom-risks") > -1:
                info["title"] = title_custom_risks
            roots.append(info)

        myroot = first(lambda x: x["active"], roots)
        myroot["children"] = result["children"]
        result["children"] = roots

    return result