コード例 #1
0
ファイル: module.py プロジェクト: EU-OSHA/Euphorie
    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()
コード例 #2
0
ファイル: module.py プロジェクト: euphorie/Euphorie
    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()
コード例 #3
0
ファイル: profile.py プロジェクト: euphorie/Euphorie
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)
コード例 #4
0
ファイル: profile.py プロジェクト: euphorie/Euphorie
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)
コード例 #5
0
ファイル: module.py プロジェクト: euphorie/Euphorie
    def save_and_continue(self, module):
        """We received a POST request.
        Submit the form and figure out where to go next.
        """
        context = aq_inner(self.context)
        reply = self.request.form
        _next = reply.get("next", None)
        # In Safari browser we get a list
        if isinstance(_next, list):
            _next = _next.pop()
        if module.optional:
            if "skip_children" in reply:
                context.skip_children = reply.get("skip_children")
                context.postponed = False
            else:
                context.postponed = True
            self.context.session.touch()

        if _next == "previous":
            if self.previous_question is None:
                # We ran out of questions, step back to intro page
                url = "%s/@@identification" % self.context.aq_parent.absolute_url()
                self.request.response.redirect(url)
                return
            self.request.response.redirect(self.previous_question_url)
            return
        else:
            if ICustomRisksModule.providedBy(module):
                if _next == "add_custom_risk":
                    self.add_custom_risk()
                    notify(CustomRisksModifiedEvent(self.context))
                    risk_id = self.context.children().count()
                    url = "{parent_url}/{risk_id}/@@identification".format(
                        parent_url=self.context.absolute_url(),
                        risk_id=risk_id,
                    )
                    return self.request.response.redirect(url)
                else:
                    # We ran out of questions, proceed to the action plan
                    return self.request.response.redirect(self.next_phase_url)
            if self.next_question is None:
                # We ran out of questions, proceed to the action plan
                return self.request.response.redirect(self.next_phase_url)

        self.request.response.redirect(self.next_question_url)
コード例 #6
0
ファイル: module.py プロジェクト: euphorie/Euphorie
    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()
コード例 #7
0
ファイル: module.py プロジェクト: EU-OSHA/Euphorie
    def save_and_continue(self, module):
        """ We received a POST request.
            Submit the form and figure out where to go next.
        """
        context = aq_inner(self.context)
        reply = self.request.form
        if module.optional:
            if "skip_children" in reply:
                context.skip_children = reply.get("skip_children")
                context.postponed = False
            else:
                context.postponed = True
            SessionManager.session.touch()

        if reply["next"] == "previous":
            next = FindPreviousQuestion(context, filter=self.question_filter)
            if next is None:
                # We ran out of questions, step back to intro page
                url = "%s/identification" % self.request.survey.absolute_url()
                self.request.response.redirect(url)
                return
        else:
            if ICustomRisksModule.providedBy(module):
                if not context.skip_children:
                    # The user will now be allowed to create custom
                    # (user-defined) risks.
                    url = "%s/customization/%d" % (
                        self.request.survey.absolute_url(),
                        int(self.context.path))
                    return self.request.response.redirect(url)
                else:
                    # We ran out of questions, proceed to the evaluation
                    url = "%s/actionplan" % self.request.survey.absolute_url()
                    return self.request.response.redirect(url)
            next = FindNextQuestion(context, filter=self.question_filter)
            if next is None:
                # We ran out of questions, proceed to the evaluation
                url = "%s/actionplan" % self.request.survey.absolute_url()
                return self.request.response.redirect(url)

        url = QuestionURL(self.request.survey, next, phase="identification")
        self.request.response.redirect(url)
コード例 #8
0
ファイル: module.py プロジェクト: euphorie/Euphorie
    def save_and_continue(self, module):
        """ We received a POST request.
            Submit the form and figure out where to go next.
        """
        context = aq_inner(self.context)
        reply = self.request.form
        if module.optional:
            if "skip_children" in reply:
                context.skip_children = reply.get("skip_children")
                context.postponed = False
            else:
                context.postponed = True
            SessionManager.session.touch()

        if reply["next"] == "previous":
            next = FindPreviousQuestion(context, filter=self.question_filter)
            if next is None:
                # We ran out of questions, step back to intro page
                url = "%s/identification" % self.request.survey.absolute_url()
                self.request.response.redirect(url)
                return
        else:
            if ICustomRisksModule.providedBy(module):
                if not context.skip_children:
                    # The user will now be allowed to create custom
                    # (user-defined) risks.
                    url = "%s/customization/%d" % (
                        self.request.survey.absolute_url(),
                        int(self.context.path))
                    return self.request.response.redirect(url)
                else:
                    # We ran out of questions, proceed to the evaluation
                    url = "%s/actionplan" % self.request.survey.absolute_url()
                    return self.request.response.redirect(url)
            next = FindNextQuestion(context, filter=self.question_filter)
            if next is None:
                # We ran out of questions, proceed to the evaluation
                url = "%s/actionplan" % self.request.survey.absolute_url()
                return self.request.response.redirect(url)

        url = QuestionURL(self.request.survey, next, phase="identification")
        self.request.response.redirect(url)
コード例 #9
0
ファイル: module.py プロジェクト: EU-OSHA/Euphorie
    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()
コード例 #10
0
ファイル: module.py プロジェクト: euphorie/Euphorie
    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()
コード例 #11
0
 def use_node(elem):
     # Recursively find the nodes that are not disabled
     global use_nodes
     # Skip this elem?
     # 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 on the module will be considered as "do
     # not skip children"
     zodb_elem = self.context.aq_parent.restrictedTraverse(
         elem.zodb_path.split("/"))
     if getattr(zodb_elem, "optional", False):
         if (elem.postponed in (True, None) or elem.skip_children
             ) and not ICustomRisksModule.providedBy(zodb_elem):
             return
     children = [
         x for x in s_paths if x.path.startswith(elem.path)
         and len(x.path) == len(elem.path) + 3
     ]
     if children:
         for child in children:
             use_node(child)
     else:
         use_nodes.append(elem.path)
コード例 #12
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
コード例 #13
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])
コード例 #14
0
ファイル: session.py プロジェクト: euphorie/tno.euphorie
    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])
コード例 #15
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
コード例 #16
0
ファイル: module.py プロジェクト: euphorie/Euphorie
    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()
コード例 #17
0
ファイル: navigation.py プロジェクト: euphorie/Euphorie
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