def create_workbook(self): """Create an Excel workbook containing the all risks and measures.""" book = Workbook() sheet = book.worksheets[0] sheet.title = translate(_("report_timeline_title", default="Timeline"), context=self.request) survey = self.context.aq_parent for (column, (ntype, key, title)) in enumerate(self.columns): sheet.cell(row=1, column=column + 1).value = translate( title, context=self.request) row = 2 for (module, risk, measure) in self.get_measures(): if risk.identification in ["n/a", "yes"]: continue column = 1 if risk.is_custom_risk: zodb_node = None else: zodb_node = survey.restrictedTraverse( risk.zodb_path.split("/")) for (ntype, key, title) in self.columns: value = None if ntype == "measure": value = getattr(measure, key, None) elif ntype == "risk": value = getattr(risk, key, None) if key == "priority": value = self.priority_name(value) elif key == "title": if (getattr(zodb_node, "problem_description", None) and zodb_node.problem_description.strip()): value = zodb_node.problem_description elif key == "number": if risk.is_custom_risk: num_elems = value.split(".") value = ".".join(["Ω"] + num_elems[1:]) elif ntype == "module": if key == "title": if risk.is_custom_risk: value = utils.get_translated_custom_risks_title( self.request) else: value = module.title if value is not None: cell = sheet.cell(row=row, column=column) if key == "number": # force sting cell.set_explicit_value(value) else: cell.value = value column += 1 row += 1 return book
def get_modules(self): """Returns the modules for this session""" sql_modules = (Session.query(model.Module).filter( model.SurveyTreeItem.session == self.context.session, ).order_by( model.SurveyTreeItem.path)) modules = [] for sql_module in sql_modules: if sql_module.skip_children: continue if sql_module.zodb_path.find("custom-risks") != -1: module_title = get_translated_custom_risks_title(self.request) else: module_title = sql_module.title risks = self.get_risks_for(sql_module) modules.append({ "title": module_title, "checked": bool(risks), "risks": risks, }) return modules
def getModules(self): """ Return a list of dicts of all the top-level modules and locations belonging to this survey. """ session = Session() session_id = SessionManager.id base_url = "%s/identification" % self.request.survey.absolute_url() profile = extractProfile(self.request.survey, SessionManager.session) module_query = self.module_query( sessionid=session_id, optional_modules=len(profile) and "(%s)" % (','.join( ["'%s'" % k for k in profile.keys()])) or None ) module_res = session.execute(module_query).fetchall() modules_and_profiles = {} for row in module_res: if row[0] is not None: if row[0].find('profile') > 0: path = row[0][:3] modules_and_profiles[path] = 'profile' else: modules_and_profiles[row[0]] = '' module_paths = [ p[0] for p in session.execute(module_query).fetchall() if p[0] is not None] module_paths = modules_and_profiles.keys() module_paths = sorted(module_paths) parent_node = orm.aliased(model.Module) titles = dict(session.query(model.Module.path, model.Module.title) .filter(model.Module.session_id == session_id) .filter(model.Module.path.in_(module_paths))) location_titles = dict(session.query( model.Module.path, parent_node.title ).filter( model.Module.session_id == session_id).filter( model.Module.path.in_(module_paths)).filter( sql.and_( parent_node.session_id == session_id, parent_node.depth < model.Module.depth, model.Module.path.like(parent_node.path + "%") ) )) modules = {} toc = {} title_custom_risks = utils.get_translated_custom_risks_title(self.request) for path in module_paths: number = ".".join(self.slicePath(path)) # top-level module, always include it in the toc if len(path) == 3: title = titles[path] if title == 'title_other_risks': title = title_custom_risks toc[path] = { 'path': path, 'title': title, 'locations': [], 'number': number, } # If this is a profile (aka container for locations), skip # adding to the list of modules if modules_and_profiles[path] == 'profile': continue # sub-module (location) or location container else: if path in location_titles: title = u"{0} - {1}".format(location_titles[path], titles[path]) toc[path[:3]]['locations'].append({ 'path': path, 'title': titles[path], 'number': number, }) else: log.warning( "Status: found a path for a submodule {0} for which " "there's no location title.".format(path)) continue modules[path] = { 'path': path, 'title': title, 'url': '%s/%s' % (base_url, '/'.join(self.slicePath(path))), 'todo': 0, 'ok': 0, 'postponed': 0, 'risk_with_measures': 0, 'risk_without_measures': 0, 'number': number, } self.tocdata = toc return modules
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
def getModules(self): """Return a list of dicts of all the top-level modules and locations belonging to this survey. """ sql_session = self.sql_session session_id = self.session.id module_paths = self.getModulePaths() url_schema = "%s/{0}/@@identification" % self.context.absolute_url() parent_node = orm.aliased(model.Module) titles = dict( sql_session.query(model.Module.path, model.Module.title).filter( model.Module.session_id == session_id).filter( model.Module.path.in_(module_paths))) location_titles = dict( sql_session.query(model.Module.path, parent_node.title).filter( model.Module.session_id == session_id).filter( model.Module.path.in_(module_paths)).filter( sql.and_( parent_node.session_id == session_id, parent_node.depth < model.Module.depth, model.Module.path.like(parent_node.path + "%"), ))) modules = {} toc = {} title_custom_risks = utils.get_translated_custom_risks_title( self.request) for path in module_paths: number = ".".join(self.slicePath(path)) # top-level module, always include it in the toc if len(path) == 3: title = titles[path] if (title == "title_other_risks" or title == "Other risks" or title == "Custom risks"): title = title_custom_risks toc[path] = { "path": path, "title": title, "locations": [], "number": number, } # If this is a profile (aka container for locations), skip # adding to the list of modules if self.modules_and_profiles[path] == "profile": continue # sub-module (location) or location container else: if path in location_titles: title = "{0} - {1}".format(location_titles[path], titles[path]) toc[path[:3]]["locations"].append({ "path": path, "title": titles[path], "number": number }) else: log.warning( "Status: found a path for a submodule {0} for which " "there's no location title.".format(path)) continue modules[path] = { "path": path, "title": title, "url": url_schema.format("/".join(self.slicePath(path))), "todo": 0, "ok": 0, "postponed": 0, "risk_with_measures": 0, "risk_without_measures": 0, "number": number, } self.tocdata = toc return modules
def slide_title(self): if self.is_custom and self.item_type == "module": return client_utils.get_translated_custom_risks_title(self.request) return self.context.title
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
def getModules(self): """ Return a list of dicts of all the top-level modules and locations belonging to this survey. """ sql_session = self.sql_session session_id = self.session.id module_paths = self.getModulePaths() base_url = "%s/identification" % self.request.survey.absolute_url() parent_node = orm.aliased(model.Module) titles = dict( sql_session.query( model.Module.path, model.Module.title ).filter( model.Module.session_id == session_id ).filter( model.Module.path.in_(module_paths) ) ) location_titles = dict( sql_session.query( model.Module.path, parent_node.title ).filter( model.Module.session_id == session_id ).filter( model.Module.path.in_(module_paths) ).filter( sql.and_( parent_node.session_id == session_id, parent_node.depth < model.Module.depth, model.Module.path.like(parent_node.path + "%") ) ) ) modules = {} toc = {} title_custom_risks = utils.get_translated_custom_risks_title(self.request) for path in module_paths: number = ".".join(self.slicePath(path)) # top-level module, always include it in the toc if len(path) == 3: title = titles[path] if title == 'title_other_risks': title = title_custom_risks toc[path] = { 'path': path, 'title': title, 'locations': [], 'number': number, } # If this is a profile (aka container for locations), skip # adding to the list of modules if self.modules_and_profiles[path] == 'profile': continue # sub-module (location) or location container else: if path in location_titles: title = u"{0} - {1}".format(location_titles[path], titles[path]) toc[path[:3]]['locations'].append({ 'path': path, 'title': titles[path], 'number': number, }) else: log.warning( "Status: found a path for a submodule {0} for which " "there's no location title.".format(path)) continue modules[path] = { 'path': path, 'title': title, 'url': '%s/%s' % (base_url, '/'.join(self.slicePath(path))), 'todo': 0, 'ok': 0, 'postponed': 0, 'risk_with_measures': 0, 'risk_without_measures': 0, 'number': number, } self.tocdata = toc return modules
def getModules(self): """ Return a list of dicts of all the top-level modules and locations belonging to this survey. """ sql_session = self.sql_session session_id = self.session.id module_paths = self.getModulePaths() base_url = "%s/identification" % self.request.survey.absolute_url() parent_node = orm.aliased(model.Module) titles = dict( sql_session.query(model.Module.path, model.Module.title).filter( model.Module.session_id == session_id).filter( model.Module.path.in_(module_paths))) location_titles = dict( sql_session.query(model.Module.path, parent_node.title).filter( model.Module.session_id == session_id).filter( model.Module.path.in_(module_paths)).filter( sql.and_( parent_node.session_id == session_id, parent_node.depth < model.Module.depth, model.Module.path.like(parent_node.path + "%")))) modules = {} toc = {} title_custom_risks = utils.get_translated_custom_risks_title( self.request) for path in module_paths: number = ".".join(self.slicePath(path)) # top-level module, always include it in the toc if len(path) == 3: title = titles[path] if title == 'title_other_risks': title = title_custom_risks toc[path] = { 'path': path, 'title': title, 'locations': [], 'number': number, } # If this is a profile (aka container for locations), skip # adding to the list of modules if self.modules_and_profiles[path] == 'profile': continue # sub-module (location) or location container else: if path in location_titles: title = u"{0} - {1}".format(location_titles[path], titles[path]) toc[path[:3]]['locations'].append({ 'path': path, 'title': titles[path], 'number': number, }) else: log.warning( "Status: found a path for a submodule {0} for which " "there's no location title.".format(path)) continue modules[path] = { 'path': path, 'title': title, 'url': '%s/%s' % (base_url, '/'.join(self.slicePath(path))), 'todo': 0, 'ok': 0, 'postponed': 0, 'risk_with_measures': 0, 'risk_without_measures': 0, 'number': number, } self.tocdata = toc return modules
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