예제 #1
0
 def documentTemplates(self, locale):
     templates = []
     templates_path = capi.get_path_for("reporting", "templates", 
         "templates.xml"
     )
     if os.path.exists(templates_path):
         template_config = etree.fromstring(open(templates_path).read())
         for template in template_config.iter(tag="template"):
             template_file_name = template.get("file")
             template_language = template.get("language", 
                 capi.default_language
             )
             location = capi.get_path_for("reporting", "templates", 
                 template_file_name
             )
             if os.path.exists(location):
                 if (locale.id.language != template_language):
                     continue
                 template_dict = dict(
                     title = template.get("name"),
                     language = template.get("language"),
                     location = base64.encodestring(template_file_name)
                 )
                 templates.append(template_dict)
             else:
                 log.error("Template does not exist. No file found at %s.", 
                     location
                 )
     return templates
예제 #2
0
def write_to_custom(where, file_name, contents):
    """
    Helper api to write to bungeni_custom
    """
    import os
    from bungeni.capi import capi
    path = capi.get_path_for(where, ".auto")
    if not os.path.exists(path):
        os.makedirs(path)
    open(capi.get_path_for(path, file_name), "w").write(contents)
예제 #3
0
def write_to_custom(where, file_name, contents):
    """
    Helper api to write to bungeni_custom
    """
    import os
    from bungeni.capi import capi
    path = capi.get_path_for(where, ".auto")
    if not os.path.exists(path):
        os.makedirs(path)
    open(capi.get_path_for(path, file_name), "w").write(contents)
예제 #4
0
def forms_localization_check_reload(event):
    """Called once from forms_localization_init() and (if in DEVMODE)
    once_per_request on IBeforeTraverseEvent events (ui.publication).
    !+ note: switching descriptor on a type config requires restart!
    """
    # a cache of descriptor elems, to be able to update "re-used" descriptors
    DESC_ELEMS_MODIFIED_SINCE = {}
    # "sys" descriptors, if PATH_UI_FORMS_SYSTEM is modified (or not yet loaded)
    if capi.is_modified_since(PATH_UI_FORMS_SYSTEM):
        descriptor_doc = capi.schema.validate_file_rng("descriptor", PATH_UI_FORMS_SYSTEM)
        Field._roles[:] = roles.SYSTEM_ROLES + roles.CUSTOM_ROLES
        # reset global "constant" ROLES_DEFAULT
        global ROLES_DEFAULT
        ROLES_DEFAULT = " ".join(Field._roles)
        for edescriptor in descriptor_doc.findall("descriptor"):
            type_key = xas(edescriptor, "name")
            descriptor_cls = localize_descriptor(type_key, edescriptor)
            DESC_ELEMS_MODIFIED_SINCE[type_key] = edescriptor
    
    for type_key, ti in capi.iter_type_info(scope="custom"):
        # only check "dedicated" descriptor files
        if ti.descriptor_key == type_key:
            # ok, check if dedicated descriptor file has been modified (or not yet loaded)
            #!+get_descriptor_elem
            file_path = capi.get_path_for("forms", "%s.xml" % (type_key))
            if capi.is_modified_since(file_path):
                descriptor_elem = capi.schema.validate_file_rng("descriptor", file_path)
                descriptor_cls = localize_descriptor(type_key, descriptor_elem, scope="custom")
                DESC_ELEMS_MODIFIED_SINCE[type_key] = descriptor_elem
        else:
            # re-using another descriptor...
            if ti.descriptor_key in DESC_ELEMS_MODIFIED_SINCE:
                descriptor_elem = DESC_ELEMS_MODIFIED_SINCE[ti.descriptor_key]
                descriptor_cls = localize_descriptor(type_key, descriptor_elem, scope="custom")
    DESC_ELEMS_MODIFIED_SINCE.clear()
예제 #5
0
def load_notification_config(file_name, domain_class):
    """Loads the notification configuration for each document
    """
    notifications_utility = component.getUtility(INotificationsUtility)
    path = capi.get_path_for("notifications")
    file_path = os.path.join(path, file_name)
    notification = capi.schema.validate_file_rng("notifications", file_path)
    item_type = file_name.split(".")[0]
    notifications_utility.register_item_type(domain_class, item_type)
    for notify in notification.iterchildren("notify"):
        roles = capi.schema.qualified_roles(notify.get("roles"))
        for role in roles:
            assert component.queryUtility(IRole, role, None), \
                "Notifications configuration error : " \
                "Invalid role - %s. file: %s, state : %s" % (
                role, file_name)
        if notify.get("onstate"):
            states = notify.get("onstate").split()
            for state in states:
                notifications_utility.set_transition_based_notification(
                    domain_class, state, roles)
        elif notify.get("afterstate"):
            states = notify.get("afterstate").split()
            time = notify.get("time")
            for state in states:
                notifications_utility.set_time_based_notification(
                    domain_class, state, roles, time)
        else:
            raise ValueError("Please specify either onstate or afterstate")
    # Register subscriber for domain class
    component.provideHandler(queue_notification,
                             adapts=(domain_class, IWorkflowTransitionEvent))
예제 #6
0
def load_workspace(file_name, domain_class, workflow):
    """Loads the workspace configuration for each documemnt.
    """
    workspace_utility = component.getUtility(IWorkspaceTabsUtility)
    path = capi.get_path_for("workspace")
    file_path = os.path.join(path, file_name)
    workspace = capi.schema.validate_file_rng("workspace", file_path)
    item_type = file_name.split(".")[0]
    workspace_utility.register_item_type(domain_class, item_type)
    for state in workspace.iterchildren(tag="state"):
        # Raises invalid state error if there is no such state defined in the
        # workflow
        workflow.get_state(state.get("id"))
        for tab in state.iterchildren(tag="tab"):
            assert tab.get("id") in capi.workspace_tabs, (
                "Workspace configuration error : "
                "Invalid tab - %s. file: %s, state : %s" % (tab.get("id"), file_name, state.get("id"))
            )
            if tab.get("roles"):
                roles = capi.schema.qualified_roles(tab.get("roles"))
                for role in roles:
                    assert component.queryUtility(IRole, role, None), (
                        "Workspace configuration error : "
                        "Invalid role - %s. file: %s, state : %s" % (role, file_name, state.get("id"))
                    )
                    workspace_utility.set_content(role, tab.get("id"), domain_class, state.get("id"))
예제 #7
0
def register_custom_types():
    """Extend TYPE_REGISTRY with the declarations from bungeni_custom/types.xml.
    This is called prior to loading of the workflows for these custom types.
    Returns (type_key, TI) for the newly created TI instance.
    """
    def parse_elem(type_elem):
        type_key = misc.xml_attr_str(type_elem, "name")
        workflow_key = misc.xml_attr_str(type_elem,
                                         "workflow",
                                         default=type_key)
        archetype_key = type_elem.tag  # !+archetype? move to types?
        return type_key, workflow_key, archetype_key

    def enabled_elems(elems):
        for elem in elems:
            if misc.xml_attr_bool(elem, "enabled", default=True):
                yield elem

    # load XML file
    etypes = etree.fromstring(misc.read_file(capi.get_path_for("types.xml")))
    # register enabled types - ignoring not enabled types
    from bungeni.alchemist import type_info
    for edoc in enabled_elems(etypes.iterchildren("doc")):
        type_key, ti = type_info.register_new_custom_type(*parse_elem(edoc))
    # group/member types
    for egroup in enabled_elems(etypes.iterchildren("group")):
        type_key, ti = type_info.register_new_custom_type(*parse_elem(egroup))
        for emember in enabled_elems(egroup.iterchildren("member")):
            type_key, ti = type_info.register_new_custom_type(
                *parse_elem(emember))
예제 #8
0
def register_custom_types():
    """Extend TYPE_REGISTRY with the declarations from bungeni_custom/types.xml.
    This is called prior to loading of the workflows for these custom types.
    Returns (type_key, TI) for the newly created TI instance.
    """
    xas, xab = misc.xml_attr_str, misc.xml_attr_bool
    tag_archetype_key_mapping = {
        "doc": "doc",
        "event": "event",
        "group": "group",
        "member": "group_member"
    }
    def parse_elem(type_elem):
        type_key = xas(type_elem, "name")
        workflow_key = xas(type_elem, "workflow")
        descriptor_key = xas(type_elem, "descriptor")
        sys_archetype_key = tag_archetype_key_mapping[type_elem.tag]
        custom_archetype_key = xas(type_elem, "archetype")
        label = xas(type_elem, "label", None)
        container_label = xas(type_elem, "container_label", None)
        return (type_key, sys_archetype_key, custom_archetype_key, 
            workflow_key, descriptor_key, 
            label, container_label)
    
    def enabled_elems(elems):
        for elem in elems:
            if xab(elem, "enabled", default=True):
                yield elem
    
    # load types.xml
    file_path = capi.get_path_for("types.xml")
    etypes = capi.schema.validate_file_rng("types", file_path)
    # register enabled types - ignoring not enabled types
    from bungeni.alchemist import type_info
    
    # custom "event" types (must be loaded prior to custom "doc" types)
    for etype in enabled_elems(etypes.iterchildren("event")):
        type_key, ti = type_info.register_new_custom_type(*parse_elem(etype))
    # custom "doc" types
    for etype in enabled_elems(etypes.iterchildren("doc")):
        type_key, ti = type_info.register_new_custom_type(*parse_elem(etype))
    # group/member types
    for egroup in enabled_elems(etypes.iterchildren("group")):
        group_type_key, ti = type_info.register_new_custom_type(*parse_elem(egroup))
        ti.domain_model.privilege_extent = xas(egroup, "privilege_extent", "group")
        for emember in enabled_elems(egroup.iterchildren("member")):
            type_key, ti = type_info.register_new_custom_type(*parse_elem(emember))
            ti.within_type_key = group_type_key
    
    # SYSTEM WIDE settings (set on class attributes on capi)
    capi.__class__.bicameral = xab(etypes, "bicameral")
    capi.__class__.country_code = xas(etypes, "country_code")
    capi.__class__.legislature_type_key = xas(etypes, "legislature_type")
    capi.__class__.chamber_type_key = xas(etypes, "chamber_type")
    
    # sanity checks
    for tk in (capi.chamber_type_key, capi.legislature_type_key):
        ti = capi.get_type_info(tk) # KeyError
        assert ti.sys_archetype_key == "group", \
            "Value %r specified for %r must be a %r" % (tk, attr, "group")
예제 #9
0
def load_notification_config(file_name, domain_class):
    """Loads the notification configuration for each document
    """
    notifications_utility = component.getUtility(INotificationsUtility)
    path = capi.get_path_for("notifications")
    file_path = os.path.join(path, file_name)
    notification = capi.schema.validate_file_rng("notifications", file_path)
    item_type = file_name.split(".")[0]
    notifications_utility.register_item_type(domain_class, item_type)
    for notify in notification.iterchildren("notify"):
        roles = capi.schema.qualified_roles(notify.get("roles"))
        for role in roles:
            assert component.queryUtility(IRole, role, None), \
                "Notifications configuration error : " \
                "Invalid role - %s. file: %s, state : %s" % (
                role, file_name)
        if notify.get("onstate"):
            states = notify.get("onstate").split()
            for state in states:
                notifications_utility.set_transition_based_notification(
                        domain_class, state, roles)
        elif notify.get("afterstate"):
            states = notify.get("afterstate").split()
            time = notify.get("time")
            for state in states:
                notifications_utility.set_time_based_notification(
                        domain_class, state, roles, time)
        else:
            raise ValueError("Please specify either onstate or afterstate")
    # Register subscriber for domain class
    component.provideHandler(queue_notification,
        adapts=(domain_class, IWorkflowTransitionEvent))
예제 #10
0
def register_custom_types():
    """Extend TYPE_REGISTRY with the declarations from bungeni_custom/types.xml.
    This is called prior to loading of the workflows for these custom types.
    Returns (type_key, TI) for the newly created TI instance.
    """
        
    def parse_elem(type_elem):
        type_key = misc.xml_attr_str(type_elem, "name")
        workflow_key = misc.xml_attr_str(type_elem, "workflow", default=type_key)
        archetype_key = type_elem.tag # !+archetype? move to types?
        return type_key, workflow_key, archetype_key
    
    def enabled_elems(elems):
        for elem in elems:
            if misc.xml_attr_bool(elem, "enabled", default=True):
                yield elem
    
    # load XML file
    etypes = etree.fromstring(misc.read_file(capi.get_path_for("types.xml")))
    # register enabled types - ignoring not enabled types
    from bungeni.alchemist import type_info
    for edoc in enabled_elems(etypes.iterchildren("doc")):
        type_key, ti = type_info.register_new_custom_type(*parse_elem(edoc))
    # group/member types
    for egroup in enabled_elems(etypes.iterchildren("group")):
        type_key, ti = type_info.register_new_custom_type(*parse_elem(egroup))
        for emember in enabled_elems(egroup.iterchildren("member")):
            type_key, ti = type_info.register_new_custom_type(*parse_elem(emember))
예제 #11
0
def load_workspace(file_name, domain_class, workflow):
    """Loads the workspace configuration for each documemnt.
    """
    workspace_utility = component.getUtility(IWorkspaceTabsUtility)
    path = capi.get_path_for("workspace")
    file_path = os.path.join(path, file_name)
    workspace = capi.schema.validate_file_rng("workspace", file_path)
    item_type = file_name.split(".")[0]
    workspace_utility.register_item_type(domain_class, item_type)
    for state in workspace.iterchildren(tag="state"):
        # Raises invalid state error if there is no such state defined in the
        # workflow
        workflow.get_state(state.get("id"))
        for tab in state.iterchildren(tag="tab"):
            assert tab.get("id") in capi.workspace_tabs, \
                "Workspace configuration error : " \
                "Invalid tab - %s. file: %s, state : %s" % (
                    tab.get("id"), file_name, state.get("id"))
            if tab.get("roles"):
                roles = capi.schema.qualified_roles(tab.get("roles"))
                for role in roles:
                    assert component.queryUtility(IRole, role, None), \
                        "Workspace configuration error : " \
                        "Invalid role - %s. file: %s, state : %s" % (
                            role, file_name, state.get("id"))
                    workspace_utility.set_content(role,
                                                  tab.get("id"), domain_class,
                                                  state.get("id"))
예제 #12
0
def write_to_custom(where, file_name, contents):
    """
    Helper api to write to bungeni_custom
    """

    from bungeni.capi import capi
    filepath = capi.get_path_for(where, file_name)
    open(filepath, "w").write(contents)
예제 #13
0
def check_reload_descriptor_file(type_key, is_init):
    """Check if a singel file has been modified and needs reloading.
    """
    #!+get_descriptor_elem
    file_path = capi.get_path_for("forms", "%s.xml" % (type_key))
    if capi.is_modified_since(file_path):
        descriptor_doc = capi.schema.validate_file_rng("descriptor", file_path)
        assert xas(descriptor_doc, "name") == type_key, type_key
        descriptor_cls = localize_descriptor(descriptor_doc, is_init, scope="custom")
예제 #14
0
def check_reload_descriptor_file(type_key, is_init):
    """Check if a singel file has been modified and needs reloading.
    """
    #!+get_descriptor_elem
    file_path = capi.get_path_for("forms", "%s.xml" % (type_key))
    if capi.is_modified_since(file_path):
        descriptor_doc = capi.schema.validate_file_rng("descriptor", file_path)
        assert xas(descriptor_doc, "name") == type_key, type_key
        descriptor_cls = localize_descriptor(descriptor_doc, is_init, scope="custom")
예제 #15
0
def load(file_key, workflow_name, path_custom_workflows=capi.get_path_for("workflows")):
    """ (type_key:str, file_key:str, workflow_name:str, 
            path_custom_workflows:str) -> Workflow
    
    Loads the workflow XML definition file, returning the correspondingly setup 
    Workflow instance. Called by workflows.adapters.load_workflow.
    """
    file_path = os.path.join(path_custom_workflows, "%s.xml" % (file_key))
    workflow_doc = capi.schema.validate_file_rng("workflow", file_path)
    return _load(workflow_name, workflow_doc)
예제 #16
0
def get_template(file_name):
    path = capi.get_path_for("email", "templates")
    file_path = os.path.join(path, file_name)
    if os.path.exists(file_path):
        template_file = open(file_path)
        file_string = template_file.read()
        template = etree.fromstring(file_string)
        template_file.close()
        return template
    else:
        raise EmailError("Email template %s does not exist" % file_name)
def get_template(file_name):
    path = capi.get_path_for("email", "templates")
    file_path = os.path.join(path, file_name)
    if os.path.exists(file_path):
        template_file = open(file_path)
        file_string = template_file.read()
        template = etree.fromstring(file_string)
        template_file.close()
        return template
    else:
        raise EmailError("Email template %s does not exist" % file_name)
예제 #18
0
 def setupTemplate(self):
     """Check if a template was provided in the request as url/form 
     parameter.
     """
     template_encoded = self.request.form.get("template", "")
     if template_encoded != "":
         template_file_name = base64.decodestring(template_encoded)
         template_path = capi.get_path_for("reporting", "templates",
                                           template_file_name)
         if os.path.exists(template_path):
             self.oo_template_file = template_path
예제 #19
0
def apply_customization_ui():
    """Called from ui.app.on_wsgi_application_created_event -- must be called
    AFTER custom types have been catalysed.
    """
    # combine config string and execute it
    zcml = ZCML_SLUG.format(ui_zcml_decls="".join([ zd for zd in UI_ZC_DECLS ]))
    # log zcml directives to a dedicated file (before executing), for easier debugging
    misc.check_overwrite_file(capi.get_path_for("workflows/.auto/ui.zcml"), 
        '<?xml version="1.0"?>\n<!-- !! AUTO-GENERATED !! DO NOT MODIFY !! -->' + zcml)
    # execute the zcml
    log.debug("Executing UI feature configuration:\n%s", zcml)
    xmlconfig.string(zcml)
예제 #20
0
def load(file_key, workflow_name,
        path_custom_workflows=capi.get_path_for("workflows")
    ):
    """ (type_key:str, file_key:str, workflow_name:str,
            path_custom_workflows:str) -> Workflow
    
    Loads the workflow XML definition file, returning the correspondingly setup 
    Workflow instance. Called by workflows.adapters.load_workflow.
    """
    file_path = os.path.join(path_custom_workflows, "%s.xml" % (file_key))
    workflow_doc = capi.schema.validate_file_rng("workflow", file_path)
    return _load(workflow_name, workflow_doc)
예제 #21
0
def load_workspace(file_name, domain_class, workflow):
    """Loads the workspace configuration for each document.
    """
    # !+LEGISLATURE_SETUP on first run on an emtpy database, no groups exists
    # and so all these tests will fail -- as a partial workaround, only execute
    # these tests if one Legislature instance is in existence...
    if Session().query(domain.Legislature).all():
        # !+GROUP_NAMES_VALIDATION
        from bungeni.models.utils import get_group_conceptual_active
        for conceptual_name in workflow.get_feature("workspace").get_param(
                "group_names"):
            try:
                get_group_conceptual_active(conceptual_name)
            except orm.exc.NoResultFound:
                raise Exception(
                    "Workflow %r feature %r parameter %r contains "
                    "invalid value %r -- no active group with such a conceptual_name "
                    "found in the database." %
                    (workflow.name, "workspace", "group_names",
                     conceptual_name))
        # !+/GROUP_NAMES_VALIDATION
    workspace_utility = component.getUtility(IWorkspaceTabsUtility)
    path = capi.get_path_for("workspace")
    file_path = os.path.join(path, file_name)
    workspace = capi.schema.validate_file_rng("workspace", file_path)
    type_key = file_name.split(".")[0]
    workspace_utility.register_domain_type(domain_class, type_key)
    # to bookkeep that every workflow state is workspace-declared
    workflow_state_ids = set(workflow._states_by_id.keys())
    for state in workspace.iterchildren(tag="state"):
        state_id = state.get("id")
        workflow.get_state(state_id)  # InvalidStateError if no such state
        assert state_id in workflow_state_ids, \
            "configuration file workspace/%s - duplicate declaration found for state: %r" % (
                file_name, state_id)
        workflow_state_ids.remove(state_id)
        for tab in state.iterchildren(tag="tab"):
            tab_name = tab.get("id")  # !+
            assert tab_name in capi.workspace_tabs, \
                "configuration file workspace/%s - invalid tab: %r [state: %r]" % (
                    file_name, tab_name, state_id)
            tab_roles = tab.get("roles")
            if tab_roles:
                roles = capi.schema.qualified_roles(tab_roles.split())
                for role in roles:
                    assert component.queryUtility(IRole, role, None), \
                        "configuration file workspace/%s - invalid role: %r [state: %r]" % (
                            file_name, role, state_id)
                    workspace_utility.set_content(role, tab_name, domain_class,
                                                  state_id)
    assert not workflow_state_ids, \
        "configuration file workspace/%s - no declaration found for states: %s" % (
            file_name, list(workflow_state_ids))
 def setupTemplate(self):
     """Check if a template was provided in the request as url/form 
     parameter.
     """
     template_encoded = self.request.form.get("template", "")
     if template_encoded != "":
         template_file_name = base64.decodestring(template_encoded)
         template_path = capi.get_path_for("reporting", "templates", 
             template_file_name
         )
         if os.path.exists(template_path):
             self.oo_template_file = template_path
예제 #23
0
def set_get_gettext():
    """Set this callable as the z3evoque.get_gettext global function to return 
    a gettext bound onto an i18n domain and a language. 
    
    This function is to be defined and called by the application - 
    get_gettext itself should have the parameters (i18n_domain, language).
    """
    from bungeni.capi import capi
    _i18n_domain_localedirs = {
        "bungeni": capi.get_path_for("translations", "bungeni"),
    }
    _untranslated = []

    def _get_gettext(i18n_domain, language):
        """Get a _() i18n gettext function bound to domain and language.
        !+ There is probably a better way to do this; the following "obvious"
           way does not work:
                zope.i18nmessageid.MessageFactory(i18n_domain)
        """
        import gettext
        try:
            t = gettext.translation(
                i18n_domain,
                localedir=_i18n_domain_localedirs[i18n_domain],
                languages=[language])
        except (IOError, ):
            cls, exc, tb = sys.exc_info()
            if language != "en":
                log.error(""" [%s] %s [lang=%s] -> trying with [lang=%s]""" %
                          (cls.__name__, exc, language, "en"))
                return _get_gettext(i18n_domain, "en")
            else:
                log.error(""" [%s] %s [lang=%s]""" %
                          (cls.__name__, exc, language))
                raise exc
        # wrap t.gettext to intercept and log possibly untranslated msgids
        def _gt(msgid):
            try:
                msgstr = t.gettext(msgid)
                return msgstr
            finally:
                if msgid == msgstr and msgid not in _untranslated:
                    _untranslated.append(msgid)
                    log.warn('i18n NOT LOCALIZED [%s, %s] "%s"' %
                             (i18n_domain, language, msgid))

        return _gt

    global get_gettext
    get_gettext = _get_gettext
예제 #24
0
def get_mask(context):
    # assert IBungeniParliamentaryContent.providedBy(context)
    # !+IBungeniParliamentaryContent(mr, nov-2011) only context typed
    # interfaces.IBungeniParliamentaryContent should ever get here!
    # But for this case, all we need is that context defines a type:
    m = "PI context [%s] for get_mask must specify a type attr" % (context)
    assert hasattr(context, "type"), m
    path = capi.get_path_for("registry")
    config = ConfigParser()
    config.readfp(open(os.path.join(path, "config.ini")))
    try:
        return config.get("types", context.type)
    except NoOptionError:
        return None
예제 #25
0
def get_mask(context):
    # assert IBungeniParliamentaryContent.providedBy(context)
    # !+IBungeniParliamentaryContent(mr, nov-2011) only context typed
    # interfaces.IBungeniParliamentaryContent should ever get here!
    # But for this case, all we need is that context defines a type:
    m = "PI context [%s] for get_mask must specify a type attr" % (context)
    assert hasattr(context, "type"), m
    path = capi.get_path_for("registry")
    config = ConfigParser()
    config.readfp(open(os.path.join(path, "config.ini")))
    try:
        return config.get("types", context.type)
    except NoOptionError:
        return None
예제 #26
0
def load_workspace(file_name, domain_class, workflow):
    """Loads the workspace configuration for each document.
    """
    # !+LEGISLATURE_SETUP on first run on an emtpy database, no groups exists 
    # and so all these tests will fail -- as a partial workaround, only execute
    # these tests if one Legislature instance is in existence...
    if Session().query(domain.Legislature).all():
        # !+GROUP_NAMES_VALIDATION
        from bungeni.models.utils import get_group_conceptual_active
        for conceptual_name in workflow.get_feature("workspace").get_param("group_names"):
            try:
                get_group_conceptual_active(conceptual_name)
            except orm.exc.NoResultFound:
                raise Exception("Workflow %r feature %r parameter %r contains "
                    "invalid value %r -- no active group with such a conceptual_name "
                    "found in the database." % (
                        workflow.name, "workspace", "group_names", conceptual_name))
        # !+/GROUP_NAMES_VALIDATION
    workspace_utility = component.getUtility(IWorkspaceTabsUtility)
    path = capi.get_path_for("workspace")
    file_path = os.path.join(path, file_name)
    workspace = capi.schema.validate_file_rng("workspace", file_path)
    type_key = file_name.split(".")[0]
    workspace_utility.register_domain_type(domain_class, type_key)
    # to bookkeep that every workflow state is workspace-declared
    workflow_state_ids = set(workflow._states_by_id.keys())
    for state in workspace.iterchildren(tag="state"):
        state_id = state.get("id")
        workflow.get_state(state_id) # InvalidStateError if no such state
        assert state_id in workflow_state_ids, \
            "configuration file workspace/%s - duplicate declaration found for state: %r" % (
                file_name, state_id)
        workflow_state_ids.remove(state_id)
        for tab in state.iterchildren(tag="tab"):
            tab_name = tab.get("id") # !+
            assert tab_name in capi.workspace_tabs, \
                "configuration file workspace/%s - invalid tab: %r [state: %r]" % (
                    file_name, tab_name, state_id)
            tab_roles = tab.get("roles")
            if tab_roles:
                roles = capi.schema.qualified_roles(tab_roles.split())
                for role in roles:
                    assert component.queryUtility(IRole, role, None), \
                        "configuration file workspace/%s - invalid role: %r [state: %r]" % (
                            file_name, role, state_id)
                    workspace_utility.set_content(
                        role, tab_name, domain_class, state_id)
    assert not workflow_state_ids, \
        "configuration file workspace/%s - no declaration found for states: %s" % (
            file_name, list(workflow_state_ids))
예제 #27
0
 def documentTemplates(self, locale):
     templates = []
     templates_path = capi.get_path_for("reporting", "templates",
                                        "templates.xml")
     if os.path.exists(templates_path):
         template_config = etree.fromstring(open(templates_path).read())
         for template in template_config.iter(tag="template"):
             template_file_name = template.get("file")
             template_language = template.get("language",
                                              capi.default_language)
             location = capi.get_path_for("reporting", "templates",
                                          template_file_name)
             if os.path.exists(location):
                 if (locale.id.language != template_language):
                     continue
                 template_dict = dict(
                     title=template.get("name"),
                     language=template.get("language"),
                     location=base64.encodestring(template_file_name))
                 templates.append(template_dict)
             else:
                 log.error("Template does not exist. No file found at %s.",
                           location)
     return templates
예제 #28
0
def set_get_gettext():
    """Set this callable as the z3evoque.get_gettext global function to return 
    a gettext bound onto an i18n domain and a language. 
    
    This function is to be defined and called by the application - 
    get_gettext itself should have the parameters (i18n_domain, language).
    """
    from bungeni.capi import capi
    _i18n_domain_localedirs = {
        "bungeni": capi.get_path_for("translations", "bungeni"),
    }
    _untranslated = []
    def _get_gettext(i18n_domain, language):
        """Get a _() i18n gettext function bound to domain and language.
        !+ There is probably a better way to do this; the following "obvious"
           way does not work:
                zope.i18nmessageid.MessageFactory(i18n_domain)
        """
        import gettext
        try:
            t = gettext.translation(i18n_domain,
                    localedir=_i18n_domain_localedirs[i18n_domain],
                    languages=[language])
        except (IOError,):
            cls, exc, tb = sys.exc_info()
            if language != "en":
                log.error(""" [%s] %s [lang=%s] -> trying with [lang=%s]""",
                    cls.__name__, exc, language, "en")
                return _get_gettext(i18n_domain, "en")
            else:
                log.error(""" [%s] %s [lang=%s]""",
                    cls.__name__, exc, language)
                raise exc
        # wrap t.gettext to intercept and log possibly untranslated msgids
        def _gt(msgid):
            try: 
                msgstr = t.ugettext(msgid)
                return msgstr
            finally:
                if msgid == msgstr and msgid not in _untranslated:
                    _untranslated.append(msgid)
                    log.warn('i18n NOT LOCALIZED [%s, %s] "%s"',
                        i18n_domain, language, msgid)
        return _gt
    global get_gettext
    get_gettext = _get_gettext
예제 #29
0
def zcml_check_regenerate():
    """Called after all XML workflows have been loaded (see adapers.py).
    """
    #!+permissions.zcml(mr, aug-2011) bypass writing to disk?
    filepath = capi.get_path_for(os.path.join("workflows/.auto/", ZCML_FILENAME))
    # read current file
    try:
        persisted = open(filepath, "r").read().decode("utf-8")
    except IOError:
        persisted = u""
    # regenerate, compare, and re-write if needed
    regenerated = ZCML_BOILERPLATE % ("\n".join(ZCML_LINES))
    if persisted != regenerated:
        if not os.path.exists(os.path.dirname(filepath)):
            os.makedirs(os.path.dirname(filepath))
        log.warn("CHANGES to file:\n%s", 
            misc.unified_diff(persisted, regenerated, filepath, "NEW"))
        open(filepath, "w").write(regenerated.encode("utf-8"))
예제 #30
0
def load_custom_roles():
    file_path = capi.get_path_for("roles.xml")
    roles_config = capi.schema.validate_file_rng("roles", file_path)
    gsm = zope.component.getGlobalSiteManager()
    custom_roles = []
    for role_config in roles_config.iterchildren(tag="role"):
        role_id = "bungeni.%s" % (role_config.get("id"))
        custom_roles.append(role_id)
        role = Role(role_id, role_config.get("title"))
        role_annt = interfaces.ISubRoleAnnotations(role)
        gsm.registerUtility(role, IRole, role_id)
        for sub_role_config in role_config.iterchildren(tag="subrole"):
            sub_role_id = "bungeni.%s" % (sub_role_config.get("id"))
            custom_roles.append(sub_role_id)
            sub_role = Role(sub_role_id, sub_role_config.get("title"))
            sub_role_annt = interfaces.ISubRoleAnnotations(sub_role)
            sub_role_annt.is_sub_role = True
            sub_role_annt.parent = role
            role_annt.sub_roles.append(sub_role_id)
            gsm.registerUtility(sub_role, IRole, sub_role_id)
    CUSTOM_ROLES[:] = sorted(custom_roles)
예제 #31
0
파일: roles.py 프로젝트: gelie/bungeni_src
def load_custom_roles():
    file_path = capi.get_path_for("roles.xml")
    roles_config = capi.schema.validate_file_rng("roles", file_path)
    gsm = zope.component.getGlobalSiteManager()
    custom_roles = []
    for role_config in roles_config.iterchildren(tag="role"):
        role_id = "bungeni.%s" % (role_config.get("id"))
        custom_roles.append(role_id)
        role = Role(role_id, role_config.get("title"))
        role_annt = interfaces.ISubRoleAnnotations(role)
        gsm.registerUtility(role, IRole, role_id)
        for sub_role_config in role_config.iterchildren(tag="subrole"):
            sub_role_id = "bungeni.%s" % (sub_role_config.get("id"))
            custom_roles.append(sub_role_id)
            sub_role = Role(sub_role_id, sub_role_config.get("title"))
            sub_role_annt = interfaces.ISubRoleAnnotations(sub_role)
            sub_role_annt.is_sub_role = True
            sub_role_annt.parent = role
            role_annt.sub_roles.append(sub_role_id)
            gsm.registerUtility(sub_role, IRole, sub_role_id)
    CUSTOM_ROLES[:] = sorted(custom_roles)
예제 #32
0
def load_workspace(file_name, domain_class):
    """Loads the workspace configuration for each documemnt.
    """
    workspace_utility = component.getUtility(IWorkspaceTabsUtility)
    path = capi.get_path_for("workspace")
    file_path = os.path.join(path, file_name)
    item_type = file_name.split(".")[0]
    workspace_utility.register_item_type(domain_class, item_type)
    workspace = etree.fromstring(open(file_path).read())
    for state in workspace.iterchildren(tag="state"):
        for tab in state.iterchildren(tag="tab"):
            assert tab.get("id") in capi.workspace_tabs, \
                "Workspace configuration error : " \
                "Invalid tab - %s. file: %s, state : %s" % (
                    tab.get("id"), file_name, state.get("id"))
            if tab.get("roles"):
                roles = tab.get("roles").split()
                for role in roles:
                    assert component.queryUtility(IRole, role, None), \
                        "Workspace configuration error : " \
                        "Invalid role - %s. file: %s, state : %s" % (
                            role, file_name, state.get("id"))
                    workspace_utility.set_content(role,
                        tab.get("id"), domain_class, state.get("id"))
예제 #33
0
    Field,
    show, hide,
    #norm_sorted,
)
from bungeni.models import roles
from bungeni.ui.descriptor import field
from bungeni.capi import capi
from bungeni.utils import naming, misc

xas, xab, xai = misc.xml_attr_str, misc.xml_attr_bool, misc.xml_attr_int

# constants 

import bungeni.ui.descriptor.descriptor as DESCRIPTOR_MODULE

PATH_UI_FORMS_SYSTEM = capi.get_path_for("forms", "ui.xml")
ROLES_DEFAULT = " ".join(Field._roles)


####
# Load and apply forms localization --
# Localize descriptors from {bungeni_custom}/forms/.

def is_descriptor(cls):
    try:
        return IModelDescriptor.implementedBy(cls)
    except (TypeError, AttributeError):
        return False
    '''
    try:
        return issubclass(cls, ModelDescriptor):
예제 #34
0
    show,
    hide,
    #norm_sorted,
)
from bungeni.models import roles
from bungeni.ui.descriptor import field
from bungeni.capi import capi
from bungeni.utils import naming, misc

xas, xab, xai = misc.xml_attr_str, misc.xml_attr_bool, misc.xml_attr_int

# constants

from bungeni.ui.descriptor import descriptor as DESCRIPTOR_MODULE

PATH_UI_FORMS_SYSTEM = capi.get_path_for("forms", "ui.xml")
ROLES_DEFAULT = " ".join(Field._roles)

####
# Load and apply forms localization --
# Localize descriptors from {bungeni_custom}/forms/.


def is_descriptor(cls):
    try:
        return IModelDescriptor.implementedBy(cls)
    except (TypeError, AttributeError):
        return False
    '''
    try:
        return issubclass(cls, ModelDescriptor):
예제 #35
0
def register_custom_types():
    """Extend TYPE_REGISTRY with the declarations from bungeni_custom/types.xml.
    This is called prior to loading of the workflows for these custom types.
    Returns (type_key, TI) for the newly created TI instance.
    """
    xas, xab = misc.xml_attr_str, misc.xml_attr_bool
    tag_archetype_key_mapping = {
        "doc": "doc",
        "event": "event",
        "group": "group",
        "member": "group_member"
    }

    def parse_elem(type_elem):
        type_key = xas(type_elem, "name")
        workflow_key = xas(type_elem, "workflow")
        descriptor_key = xas(type_elem, "descriptor")
        sys_archetype_key = tag_archetype_key_mapping[type_elem.tag]
        custom_archetype_key = xas(type_elem, "archetype")
        label = xas(type_elem, "label", None)
        container_label = xas(type_elem, "container_label", None)
        return (type_key, sys_archetype_key, custom_archetype_key,
                workflow_key, descriptor_key, label, container_label)

    def enabled_elems(elems):
        for elem in elems:
            if xab(elem, "enabled", default=True):
                yield elem

    # load types.xml
    file_path = capi.get_path_for("types.xml")
    etypes = capi.schema.validate_file_rng("types", file_path)
    # register enabled types - ignoring not enabled types
    from bungeni.alchemist import type_info

    # custom "event" types (must be loaded prior to custom "doc" types)
    for etype in enabled_elems(etypes.iterchildren("event")):
        type_key, ti = type_info.register_new_custom_type(*parse_elem(etype))
    # custom "doc" types
    for etype in enabled_elems(etypes.iterchildren("doc")):
        type_key, ti = type_info.register_new_custom_type(*parse_elem(etype))
    # group/member types
    for egroup in enabled_elems(etypes.iterchildren("group")):
        group_type_key, ti = type_info.register_new_custom_type(
            *parse_elem(egroup))
        ti.domain_model.privilege_extent = xas(egroup, "privilege_extent",
                                               "group")
        for emember in enabled_elems(egroup.iterchildren("member")):
            type_key, ti = type_info.register_new_custom_type(
                *parse_elem(emember))
            ti.within_type_key = group_type_key

    # SYSTEM WIDE settings (set on class attributes on capi)
    capi.__class__.bicameral = xab(etypes, "bicameral")
    capi.__class__.country_code = xas(etypes, "country_code")
    capi.__class__.legislature_type_key = xas(etypes, "legislature_type")
    capi.__class__.chamber_type_key = xas(etypes, "chamber_type")

    # sanity checks
    for tk in (capi.chamber_type_key, capi.legislature_type_key):
        ti = capi.get_type_info(tk)  # KeyError
        assert ti.sys_archetype_key == "group", \
            "Value %r specified for %r must be a %r" % (tk, attr, "group")
예제 #36
0
def zcml_check_regenerate():
    """For debug purposes; called after loading of all XML workflows (adapers.py).
    """
    misc.check_overwrite_file(
        capi.get_path_for(os.path.join("workflows/.auto/", ZCML_FILENAME)),
        ZCML_BOILERPLATE % ("\n".join(ZCML_LINES)))
예제 #37
0
    def setUp(self):

        # register translations
        #import zope.i18n.zcml
        #zope.i18n.zcml.registerTranslations(getConfigContext(),
        #    capi.get_path_for("translations", "bungeni"))
        # !+ZCML_PYTHON(mr, apr-2011) above registerTranslations() in python
        # does not work, as subsequent utility lookup fails. We workaround it
        # by executing the following parametrized bit of ZCML:
        from zope.configuration import xmlconfig
        xmlconfig.string("""
            <configure xmlns="http://namespaces.zope.org/zope"
                xmlns:i18n="http://namespaces.zope.org/i18n">
                <include package="zope.i18n" file="meta.zcml" />
                <i18n:registerTranslations directory="%s" />
            </configure>
            """ % (capi.get_path_for("translations", "bungeni")))

        sm = site.LocalSiteManager(self.context)
        self.context.setSiteManager(sm)

        from bungeni.core import language
        from bungeni.ui import z3evoque
        z3evoque.set_get_gettext()
        z3evoque.setup_evoque()
        z3evoque.domain.set_on_globals("devmode",
                                       common.has_feature("devmode"))
        z3evoque.domain.set_on_globals("absoluteURL", url.absoluteURL)
        z3evoque.domain.set_on_globals("get_section_name",
                                       url.get_section_name)
        z3evoque.domain.set_on_globals("get_base_direction",
                                       language.get_base_direction)
        z3evoque.domain.set_on_globals("is_rtl", language.is_rtl)

        # !+ where is the view name for the app root (slash) set?

        # CONVENTION: the action of each site top-section is made to point
        # directly the primary sub-section (the INDEX) that it contains.
        # EXCEPTION: the "/", when logged in, is redirected to "/workspace/pi"

        self.context["bungeni"] = AkomaNtosoSection(
            title=_(u"Bungeni"),
            description=_(u"Current parliamentary activity"),
            default_name="bung",  # !+NAMING(mr, jul-2011) bung?!?
        )

        # top-level sections
        workspace = self.context["workspace"] = WorkspaceSection(
            title=_("section_workspace", default=u"Workspace"),
            description=_(u"Current parliamentary activity"),
            default_name="my-documents",
        )
        alsoProvides(workspace, interfaces.ISearchableSection)

        workspace["my-documents"] = WorkspaceSection(
            title=_("section_workspace_documents", default=u"my documents"),
            description=_(u"my documents workspace section"),
            default_name="inbox",
            marker=interfaces.IWorkspaceDocuments,
        )

        for tab in capi.workspace_tabs:
            workspace["my-documents"][tab] = WorkspaceContainer(
                tab_type=tab,
                title=_("section_workspace_%s" % tab, default=tab),
                marker=interfaces.IWorkspaceTab)

        ws_uc = workspace["under-consideration"] = WorkspaceSection(
            title=_(u"under consideration"),
            description=_(u"documents under consideration"),
            default_name="documents",
            marker=interfaces.IWorkspaceUnderConsideration)
        ws_uc["documents"] = WorkspaceUnderConsiderationContainer(
            name="documents",
            title=_(u"under consideration"),
            description=_(u"documents under consideration"),
            marker=interfaces.IWorkspaceTrackedDocuments)
        ws_uc["tracked-documents"] = WorkspaceTrackedDocumentsContainer(
            name="tracked documents",
            title=_(u"tracked documents"),
            description=_(u"tracked documents"))

        ws_sched = workspace["scheduling"] = Section(
            title=_("section_scheduling", default=u"Scheduling"),
            description=_(u"Workspace Scheduling"),
            default_name="index",
            marker=interfaces.IWorkspaceScheduling)
        ws_sched["committees"] = QueryContent(
            container_getter(get_chamber_for_context, "committees"),
            title=_("section_scheduling_committees", default=u"Committees"),
            #!+marker=interfaces.ICommitteeAddContext,
            description=_(u"Committee schedules"))
        ws_sched["documents"] = WorkspaceSchedulableContainer(
            name=_(u"schedulable items"),
            title=_(u"schedulable items"),
            description=_(u"documents available for scheduling"))
        ws_sched["sittings"] = QueryContent(
            container_getter(get_chamber_for_context, "sittings"),
            title=_("section_scheduling_sittings", default=u"Sittings"),
            description=_(u"Plenary Sittings"))
        ws_sched["sessions"] = QueryContent(
            container_getter(get_chamber_for_context, "sessions"),
            title=_("section_scheduling_sessions", default=u"Sessions"),
            description=_(u"Plenary Sessions"))
        ws_sched["venues"] = QueryContent(container_getter(
            get_chamber_for_context, "venues"),
                                          title=_("section_scheduling_venues",
                                                  default=u"Venues"),
                                          description=_(u"Venues"))
        ws_sched["agendaitems"] = QueryContent(
            container_getter(get_chamber_for_context, "agendaitems"),
            title=_("section_scheduling_agenda_items",
                    default=u"Agenda items"),
            #marker=interfaces.IAgendaItemAddContext,
            description=_(u"Manage agenda items"))
        ws_sched["publications"] = QueryContent(
            container_getter(get_chamber_for_context, "publications"),
            title=_("section_scheduling_publications",
                    default=u"Publications"),
            description=_(u"Publications"))

        workspace["groups"] = WorkspaceSection(
            title=_("section_groups", default=u"Groups"),
            description=_(u"Bungeni Groups"),
            default_name="my-groups",
            marker=interfaces.IWorkspaceGroups)
        workspace["groups"]["my-groups"] = WorkspaceGroupsContainer(
            name="my-groups",
            title=_(u"My Groups"),
            description=_(u"Groups that the user is a member of"))

        #!+TIMING
        #!+AUTO CONTAINERS SCHEDULING(mb, April-2012)
        # type_info missing container name
        for type_key, ti in capi.iter_type_info():
            if model_interfaces.IScheduleContent.implementedBy(
                    ti.domain_model):
                container_property_name = naming.plural(type_key)
                container_class_name = naming.container_class_name(type_key)
                if not ws_sched.has_key(container_property_name):
                    ws_sched[container_property_name] = \
                        getattr(domain, container_class_name)()
                    to_locatable_container(ti.domain_model,
                                           ws_sched[container_property_name])

        ##########
        # Admin User Interface
        # Administration section

        #!+SECURITY(miano. nov-2010) Admin section now uses AdminSection
        # container that is identical to Section, only difference is that
        # traversing though it requires zope.ManageSite permission as defined
        # in core/configure.zcml

        admin = self.context["admin"] = AdminSection(
            title=_(u"Administration"),
            description=_(u"Manage bungeni settings"),
            default_name="admin-index",
            marker=model_interfaces.IBungeniAdmin)

        content = admin["content"] = Section(
            title=_(u"Content"),
            description=_(u"browse bungeni content"),
            marker=model_interfaces.IBungeniAdmin,
            default_name="browse-admin")
        alsoProvides(content, interfaces.ISearchableSection)

        admin["email-settings"] = Section(
            title=_(u"email settings"),
            description=_(u"manage email settings"),
            marker=model_interfaces.IBungeniAdmin,
            default_name="email-settings")

        admin["search-settings"] = Section(
            title=_(u"search settings"),
            description=_(u"manage bungeni email settings"),
            marker=model_interfaces.IBungeniAdmin,
            default_name="search-settings")

        admin["registry-settings"] = Section(
            title=_(u"registry settings"),
            description=_(u"manage registry settings"),
            marker=model_interfaces.IBungeniAdmin,
            default_name="registry-settings")

        admin["serialization-manager"] = Section(
            title=_(u"serialization manager"),
            description=_(u"batch serialization of content"),
            marker=model_interfaces.IBungeniAdmin,
            default_name="serialization-manager")

        content[u"parliaments"] = domain.ParliamentContainer()
        to_locatable_container(domain.Parliament, content[u"parliaments"])
        content[u"governments"] = domain.GovernmentContainer()
        to_locatable_container(domain.Government, content[u"governments"])
        content[u"joint-committees"] = domain.JointCommitteeContainer()
        to_locatable_container(domain.JointCommittee,
                               content["joint-committees"])
        content[u"users"] = domain.UserContainer()
        to_locatable_container(domain.User, content[u"users"])

        api = self.context[u"api"] = APISection(
            title=_(u"Bungeni API"),
            description=_(u"Bungeni REST API"),
            default_name="index",
        )

        api[u"workspace"] = copy.deepcopy(workspace)

        api[u"users"] = copy.deepcopy(content[u"users"])

        self.context["oauth"] = OAuthSection(
            title=_(u"Bungeni OAuth API"),
            description=_(u"Bungeni OAuth API"),
            default_name="index",
        )
        admin[u"applications"] = domain.OAuthApplicationContainer()
        to_locatable_container(domain.OAuthApplication, admin[u"applications"])
예제 #38
0
def zcml_check_regenerate():
    """For debug purposes; called after loading of all XML workflows (adapers.py).
    """
    misc.check_overwrite_file(
        capi.get_path_for(os.path.join("workflows/.auto/", ZCML_FILENAME)),
        ZCML_BOILERPLATE % ("\n".join(ZCML_LINES)))
예제 #39
0
    def setUp(self):
        
        # register translations
        #import zope.i18n.zcml
        #zope.i18n.zcml.registerTranslations(getConfigContext(),
        #    capi.get_path_for("translations", "bungeni"))
        # !+ZCML_PYTHON(mr, apr-2011) above registerTranslations() in python 
        # does not work, as subsequent utility lookup fails. We workaround it 
        # by executing the following parametrized bit of ZCML:
        from zope.configuration import xmlconfig
        xmlconfig.string("""
            <configure xmlns="http://namespaces.zope.org/zope"
                xmlns:i18n="http://namespaces.zope.org/i18n">
                <include package="zope.i18n" file="meta.zcml" />
                <i18n:registerTranslations directory="%s" />
            </configure>
            """ % (capi.get_path_for("translations", "bungeni")))
        
        sm = site.LocalSiteManager(self.context)
        self.context.setSiteManager(sm)
        
        from bungeni.core import language
        from bungeni.ui import z3evoque
        z3evoque.set_get_gettext()
        z3evoque.setup_evoque()
        z3evoque.domain.set_on_globals("devmode", common.has_feature("devmode"))
        z3evoque.domain.set_on_globals("absoluteURL", url.absoluteURL)
        z3evoque.domain.set_on_globals("get_section_name", url.get_section_name)
        z3evoque.domain.set_on_globals("get_base_direction", 
            language.get_base_direction)
        z3evoque.domain.set_on_globals("is_rtl", language.is_rtl)          
        
        # !+ where is the view name for the app root (slash) set?
        
        # CONVENTION: the action of each site top-section is made to point 
        # directly the primary sub-section (the INDEX) that it contains.
        # EXCEPTION: the "/", when logged in, is redirected to "/workspace/pi"
        
        self.context["bungeni"] = AkomaNtosoSection(
            title=_(u"Bungeni"),
            description=_(u"Current parliamentary activity"),
            default_name="bung", # !+NAMING(mr, jul-2011) bung?!?
        )
        
        # top-level sections
        workspace = self.context["workspace"] = WorkspaceSection(
            title=_("section_workspace", default=u"Workspace"),
            description=_(u"Current parliamentary activity"),
            default_name="my-documents",
        )
        alsoProvides(workspace, interfaces.ISearchableSection)
        
        workspace["my-documents"] = WorkspaceSection(
            title=_("section_workspace_documents", default=u"my documents"),
            description=_(u"my documents workspace section"),
            default_name="inbox",
            marker=interfaces.IWorkspaceDocuments,
        )
        
        for tab in capi.workspace_tabs:
            workspace["my-documents"][tab] = WorkspaceContainer(
                tab_type=tab,
                title=_("section_workspace_%s" % tab, default=tab),
                marker=interfaces.IWorkspaceTab
            )

        ws_uc = workspace["under-consideration"] = WorkspaceSection(
            title=_(u"under consideration"),
            description=_(u"documents under consideration"),
            default_name="documents",
            marker=interfaces.IWorkspaceUnderConsideration)
        ws_uc["documents"] = WorkspaceUnderConsiderationContainer(
            name="documents",
            title=_(u"under consideration"),
            description=_(u"documents under consideration"),
            marker=interfaces.IWorkspaceTrackedDocuments)
        ws_uc["tracked-documents"] = WorkspaceTrackedDocumentsContainer(
            name="tracked documents",
            title=_(u"tracked documents"),
            description=_(u"tracked documents"))
        
        ws_sched = workspace["scheduling"] = Section(
            title=_("section_scheduling", default=u"Scheduling"),
            description=_(u"Workspace Scheduling"),
            default_name="index",
            marker=interfaces.IWorkspaceScheduling)
        ws_sched["committees"] = QueryContent(
            container_getter(get_chamber_for_context, "committees"),
            title=_("section_scheduling_committees", default=u"Committees"),
            #!+marker=interfaces.ICommitteeAddContext,
            description=_(u"Committee schedules"))
        ws_sched["documents"] = WorkspaceSchedulableContainer(
            name=_(u"schedulable items"),
            title=_(u"schedulable items"),
            description=_(u"documents available for scheduling"))
        ws_sched["sittings"] = QueryContent(
            container_getter(get_chamber_for_context, "sittings"),
            title=_("section_scheduling_sittings", default=u"Sittings"),
            description=_(u"Plenary Sittings"))
        ws_sched["sessions"] = QueryContent(
            container_getter(get_chamber_for_context, "sessions"),
            title=_("section_scheduling_sessions", default=u"Sessions"),
            description=_(u"Plenary Sessions"))
        ws_sched["venues"] = QueryContent(
            container_getter(get_chamber_for_context, "venues"),
            title=_("section_scheduling_venues", default=u"Venues"),
            description=_(u"Venues"))
        ws_sched["agendaitems"] = QueryContent(
            container_getter(get_chamber_for_context, "agendaitems"),
            title=_("section_scheduling_agenda_items", 
                default=u"Agenda items"),
            #marker=interfaces.IAgendaItemAddContext,
            description=_(u"Manage agenda items"))
        ws_sched["publications"] = QueryContent(
            container_getter(get_chamber_for_context, "publications"),
            title=_("section_scheduling_publications", 
                default=u"Publications"),
            description=_(u"Publications"))
        
        workspace["groups"] = WorkspaceSection(
            title=_("section_groups", default=u"Groups"),
            description=_(u"Bungeni Groups"),
            default_name="my-groups",
            marker=interfaces.IWorkspaceGroups)
        workspace["groups"]["my-groups"] = WorkspaceGroupsContainer(
            name="my-groups",
            title=_(u"My Groups"),
            description=_(u"Groups that the user is a member of"))
        
        #!+TIMING
        #!+AUTO CONTAINERS SCHEDULING(mb, April-2012)
        # type_info missing container name
        for type_key, ti in capi.iter_type_info():
            if model_interfaces.IScheduleContent.implementedBy(ti.domain_model):
                container_property_name = naming.plural(type_key)
                container_class_name = naming.container_class_name(type_key)
                if not ws_sched.has_key(container_property_name):
                    ws_sched[container_property_name] = \
                        getattr(domain, container_class_name)()
                    to_locatable_container(
                        ti.domain_model, ws_sched[container_property_name])
        
        
        ##########
        # Admin User Interface
        # Administration section
        
        #!+SECURITY(miano. nov-2010) Admin section now uses AdminSection
        # container that is identical to Section, only difference is that
        # traversing though it requires zope.ManageSite permission as defined
        # in core/configure.zcml
        
        admin = self.context["admin"] = AdminSection(
            title=_(u"Administration"),
            description=_(u"Manage bungeni settings"),
            default_name="admin-index",
            marker=model_interfaces.IBungeniAdmin)
        
        content = admin["content"] = Section(
            title=_(u"Content"),
            description=_(u"browse bungeni content"),
            marker=model_interfaces.IBungeniAdmin,
            default_name="browse-admin")
        alsoProvides(content, interfaces.ISearchableSection)
        
        admin["email-settings"] = Section(
            title=_(u"email settings"),
            description=_(u"manage email settings"),
            marker=model_interfaces.IBungeniAdmin,
            default_name="email-settings")
        
        admin["search-settings"] = Section(
            title=_(u"search settings"),
            description=_(u"manage bungeni email settings"),
            marker=model_interfaces.IBungeniAdmin,
            default_name="search-settings")
        
        admin["registry-settings"] = Section(
            title=_(u"registry settings"),
            description=_(u"manage registry settings"),
            marker=model_interfaces.IBungeniAdmin,
            default_name="registry-settings")
        
        admin["serialization-manager"] = Section(
            title=_(u"serialization manager"),
            description=_(u"batch serialization of content"),
            marker=model_interfaces.IBungeniAdmin,
            default_name="serialization-manager")
        
        content[u"parliaments"] = domain.ParliamentContainer()
        to_locatable_container(domain.Parliament, content[u"parliaments"])
        content[u"governments"] = domain.GovernmentContainer()
        to_locatable_container(domain.Government, content[u"governments"])
        content[u"joint-committees"] = domain.JointCommitteeContainer()
        to_locatable_container(domain.JointCommittee,
            content["joint-committees"])
        content[u"users"] = domain.UserContainer()
        to_locatable_container(domain.User, content[u"users"])

        api = self.context[u"api"] = APISection(
            title=_(u"Bungeni API"),
            description=_(u"Bungeni REST API"),
            default_name="index",
        )

        api[u"workspace"] = copy.deepcopy(workspace)

        api[u"users"] = copy.deepcopy(content[u"users"])

        self.context["oauth"] = OAuthSection(
            title=_(u"Bungeni OAuth API"),
            description=_(u"Bungeni OAuth API"),
            default_name="index",
        )
        admin[u"applications"] = domain.OAuthApplicationContainer()
        to_locatable_container(domain.OAuthApplication, admin[u"applications"])