예제 #1
0
def output_features_by_type():
    """
    provides a list of features per type
    """

    from bungeni.capi import capi
    from zope.dottedname.resolve import resolve
    from bungeni.alchemist.catalyst import MODEL_MODULE
    from bungeni.utils import naming

    # get a list of available types in a list
    li_available_types = []
    for type_key, ti in capi.iter_type_info():
        li_available_types.append(type_key)
        
    li_features = []
    li_features.append("<featuresByType>")
    
    for type_key, ti in capi.iter_type_info():
        obj =  resolve("%s.%s" % (MODEL_MODULE.__name__, naming.model_name(type_key)))       
        if len(obj.available_dynamic_features) > 0:
            li_features.append('  <features for="%s">' % type_key)
            for dyn_feature in obj.available_dynamic_features:
                workflow = False
                # check if feature is a type
                if dyn_feature in li_available_types:
                    # feature is a type, so it has a workflow
                    workflow = True
                li_features.append(
                    '     <feature name="%(name)s" workflow="%(wf)s" />' % 
                    {"name": dyn_feature, "wf": workflow}
                )
            li_features.append("  </features>")
    li_features.append("</featuresByType>")
    return "\n".join(li_features).encode("utf-8")    
예제 #2
0
def _setup_all():
    """Do all workflow related setup.
    
    This is the entry point of setup from configuration, with the main other
    participating modules being:
    - alchemist/type_info.py
    - alchemist/model.py
    - ui/descriptor/localization.py
    """
    log.info("adapters._setup_all() ------------------------------------------")
    # cleared by each call to zope.app.testing.placelesssetup.tearDown()
    register_generic_workflow_adapters()
    
    # system and archetypes
    for type_key, ti in capi.iter_type_info():
        # retrieve the domain class and associate domain class with this type
        utils.inisetattr(ti, "domain_model", retrieve_domain_model(type_key))
        # load/get workflow instance (if any) and associate with type
        load_workflow(type_key, ti)
    
    # custom types
    # - first register/update each type in types.xml
    register_custom_types()
    for type_key, ti in capi.iter_type_info(scope="custom"):
        # load/get workflow instance (if any) and associate with type
        load_workflow(type_key, ti)
    
    # check/regenerate zcml directives for workflows - needs to be when and 
    # right-after *all* workflows are loaded (to pre-empt further application 
    # loading with possibly stale permission configuration).
    from bungeni.core.workflow import xmlimport
    xmlimport.zcml_check_regenerate()
예제 #3
0
def output_features():
    """
    provides a list of features 
    """

    from bungeni.capi import capi
    from zope.dottedname.resolve import resolve
    from bungeni.alchemist.catalyst import MODEL_MODULE
    from bungeni.utils import naming
    from bungeni.feature.feature import get_feature_cls

    # get a list of available types in a list
    li_available_types = []
    for type_key, ti in capi.iter_type_info():
        li_available_types.append(type_key)
        
    li_features = []
    li_features.append("<features>")
    li_unique_features = []
    
    for type_key, ti in capi.iter_type_info():
        obj =  resolve("%s.%s" % (MODEL_MODULE.__name__, naming.model_name(type_key)))       
        if len(obj.available_dynamic_features) > 0:
            for dyn_feature in obj.available_dynamic_features:
                # check if feature is a type
                li_unique_features.append('%s' % dyn_feature)
    li_unique_features = list(set(li_unique_features))
    for f in li_unique_features:
        fcls = get_feature_cls(f)
        li_features.append(' <feature name="%s" >' % f)
    if fcls.depends_on:
                li_features.append('  <depends>')
                for depends in fcls.depends_on:
                    li_features.append('   <depend>%s</depend>' % depends)
                li_features.append('  </depends>') 
    if fcls.feature_parameters is not None:
        if len(fcls.feature_parameters) > 0 :
            li_features.append('  <params>')
            for key, val in fcls.feature_parameters.iteritems():
                li_features.append('    <param name="%s">' % key)
                for key2, val2 in val.iteritems():
                    li_features.append('     <%(name)s>%(value)s</%(name)s>' %
                        {"name": key2, "value": val2 } 
                    )
                li_features.append('    </param>')
            li_features.append('  </params>')
    li_features.append(' </feature>')
    li_features.append("</features>")
    
    print "\n".join(li_features).encode("utf-8")               
    return "\n".join(li_features).encode("utf-8")    
예제 #4
0
def forms_localization_init():
    """Called once on IWSGIApplicationCreatedEvent.
    """
    # first create / update descriptor classes as per config
    forms_localization_check_reload(None)
    
    # then, do the once-only update/setup of each domain model
    for type_key, ti in capi.iter_type_info():
        
        # localize model from descriptor
        if ti.descriptor_model:
            alchemist.model.localize_domain_model_from_descriptor_class(
                ti.domain_model, ti.descriptor_model)
        else:
            log.warn("Skipping localization - descriptor for model %s is None", 
                ti.domain_model)
        
        # catalyze
        if ti.scope != "custom":
            #!+CATALYSE_SYSTEM_DESCRIPTORS -- all non-custom types have already 
            # catalysed on import of ui.descriptor, and may not "catalyse twice"
            # so just working around it by "calling" less of alchemist.catalyst.catalyse(ti)
            # Make ui.descriptor.catalyse_system_descriptors to be more selective,
            # and then catalyse remaining support types here?
            #alchemist.catalyst.catalyse(ti)
            #!+re-apply_security breaks edit event view (fields shown in view mode!)
            #alchemist.catalyst.apply_security(ti)
            alchemist.catalyst.generate_collection_traversal(ti)
        else:
            alchemist.catalyst.catalyse(ti)

        # sanity check integrity
        ti.sanity_check_integrity()
예제 #5
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()
예제 #6
0
def setup_retract_transitions():
    """Set up any retract transitions (from terminal states) for all workflows
    """
    def add_retract_transitions(wf):
        def getRoles(transition):
            original_roles = transition.user_data.get("_roles", [])
            allowed_roles = set()
            #transitions to  source
            tx_to_source = wf.get_transitions_to(transition.source)
            for tx in tx_to_source:
                if tx.source is None:
                    allowed_roles.update(set(original_roles))
                else:
                    for role in tx.user_data.get("_roles", []):
                        if role in original_roles:
                            allowed_roles.add(role)
            if not len(allowed_roles):
                allowed_roles = original_roles
            return allowed_roles

        transitions = wf._transitions_by_id.values()
        terminal_transitions = [
            transition for transition in transitions if
            (wf.get_transitions_from(transition.destination) == [] and
                transition.source and transition.trigger in [MANUAL, SYSTEM]
            )
        ]
        for transition in terminal_transitions:
            roles = getRoles(transition)
            if roles:
                title = _("revert_transition_title",
                    default="Undo - ${title}",
                    mapping={
                        "title": translate(transition.title, domain="bungeni")
                    }
                )
                title = "Undo - %s" % transition.title
                tid = "%s.%s" % (transition.destination, 
                    transition.source)
                pid = "bungeni.%s.wf.%s" % (wf.name, tid)
                ntransition = Transition(title, transition.destination,
                    transition.source, 
                    trigger=MANUAL,
                    condition=allow_retract,
                    permission=pid,
                    condition_args=True,
                    roles=roles)
                if ntransition.id in wf._transitions_by_id:
                    continue
                log.debug("adding transition %s", ntransition.id)
                provideUtility(Permission(pid), IPermission, pid)
                for role in roles:
                    role_perm_mgr.grantPermissionToRole(pid, role, check=False)
                transitions.append(ntransition)
        wf.refresh(wf._states_by_id.values(), transitions)
    
    for type_key, ti in capi.iter_type_info():
        if ti.workflow:
            add_retract_transitions(ti.workflow)
예제 #7
0
 def get_item_types(self):
     result = dict([("", "-")])
     for type_key, ti in capi.iter_type_info():
         workflow = ti.workflow
         if workflow and workflow.has_feature("workspace"):
             name = ti.descriptor_model.display_name
             result[ti.workflow_key] = translate(name, context=self.request)
     return result
예제 #8
0
 def domain_status(self):
     domain_status_map = {}
     for type_key, ti in capi.iter_type_info():
         workflow = ti.workflow
         if workflow and workflow.has_feature("schedule"):
             states = workflow.get_state_ids(tagged=["public"])
             domain_status_map[ti.domain_model] = states
     return domain_status_map
예제 #9
0
def check_reload_localization(event):
    """Called once on IWSGIApplicationCreatedEvent and (if in DEVMODE)
    once_per_request on IBeforeTraverseEvent events (ui.publication).
    """
    is_init = (event is None)
    if capi.is_modified_since(PATH_UI_FORMS_SYSTEM):
        localize_descriptors(PATH_UI_FORMS_SYSTEM, is_init)
    for type_key, ti in capi.iter_type_info(scope="custom"):
        check_reload_descriptor_file(type_key, is_init)
예제 #10
0
 def domain_status(self):
     domain_status_map = {}
     for type_key, ti in capi.iter_type_info():
         workflow = ti.workflow
         if workflow and workflow.has_feature("workspace"):
             states = workflow.get_state_ids(
                 tagged=["public"], not_tagged=["terminal"],
                 conjunction="AND")
             domain_status_map[ti.domain_model] = states
     return domain_status_map
예제 #11
0
def load_notifications():
    setup_message_exchange()
    setup_task_exchange()
    setup_task_workers()
    for type_key, ti in capi.iter_type_info():
        workflow = ti.workflow
        if workflow and workflow.has_feature("notification"):
            load_notification_config("%s.xml" % type_key, ti.domain_model)
    s = kronos.ThreadedScheduler()
    s.add_interval_task(queue_time_based_notifications,
        "time_based_notifications", 0, 3600, kronos.method.threaded, [], None)
    s.start()
예제 #12
0
 def domain_status(self):
     domain_status_map = {}
     workspace_roles = set(get_workspace_roles())
     for type_key, ti in capi.iter_type_info():
         workflow = ti.workflow
         if (workflow and workflow.has_feature("workspace") and
             (not workspace_roles.isdisjoint(set(workflow.roles_used)))):
             states = workflow.get_state_ids(
                 tagged=["public"], not_tagged=["terminal"],
                 conjunction="AND")
             domain_status_map[ti.domain_model] = states
     return domain_status_map
예제 #13
0
def main(argv):
    output_folder = ""
    if len(argv):
        output_folder = argv[0]
        if not output_folder.endswith("/"):
            output_folder = output_folder + "/"
    
    seen = set()
    for key, ti in capi.iter_type_info():
        wf = ti.workflow 
        if wf and wf not in seen:
            seen.add(wf)
            write_file(output_folder, "%s.dot" % ti.workflow_key, dot(wf))
예제 #14
0
def get_search_doc_types(context):
    """get types searchable in a context"""
    types = []
    if IWorkspaceSection.providedBy(context):
        ws_config = zope.component.getUtility(IWorkspaceTabsUtility)
        roles = get_workspace_roles()
        wf_types = set()
        for role in roles:
            types = []
            wf_types.update(*[ wsp.keys() 
                for wsp in ws_config.workspaces[role].values() ])
        types = [ capi.get_type_info(typ) for typ in wf_types ]
    else:
        types = [ info for key, info in capi.iter_type_info() ]
    return types
예제 #15
0
 def __call__(self, context):
     terms = []
     for type_key, info in capi.iter_type_info():
         if info.workflow and info.workflow.has_feature("workspace"):
             terms.append(
                 schema.vocabulary.SimpleTerm(
                     value=type_key, token=type_key, title=naming.split_camel(info.domain_model.__name__)
                 )
             )
     terms.sort(key=lambda item: item.value)
     all_types = ",".join([t.value for t in terms])
     terms.insert(
         0, schema.vocabulary.SimpleTerm(value=all_types, token=all_types, title=_(u"* all document types"))
     )
     return schema.vocabulary.SimpleVocabulary(terms)
예제 #16
0
def on_wsgi_application_created_event(application, event):
    """Additional setup on IWSGIApplicationCreatedEvent.
    """
    # !+ui.app.on_wsgi_application_created_event ALWAYS gets called prior to this
    log.debug("CORE ON_WSGI_APPLICATION_CREATED_EVENT: %s, %s", application, event) 
    
    # execute application setup, creating sections, etc.
    app_setup = IBungeniSetup(application)
    app_setup.setUp()
    
    # additional workflow validation
    for type_key, ti in capi.iter_type_info():
        if ti.workflow:
            ti.workflow.validate_permissions_roles()
    
    # import events module, registering handlers
    import bungeni.core.workflows.events
    
    # load workspaces
    load_workspaces()
    
    # load notifications
    load_notifications()
    
    # load email notifications
    load_email()
    
    # !+SERIALIZER(ah, 21-06-2013) This has been moved to a separate app
    # set up serialization notifications
    #serialization_notifications()
    
    # import events modules, registering handlers
    import bungeni.core.events
    
    # write configuration parameters to xml
    import bungeni.utils.xmlconfexport as confexp
    confexp.write_all()
    
    log.info("on_wsgi_application_created_event: _features: %s", 
        getConfigContext()._features)
    
    from bungeni.alchemist.utils import set_vocabulary_factory
    log.info("on_wsgi_application_created_event: Dynamic Vocabularies:\n    %s",
        "\n    ".join(sorted([ "%s%s%s" % (
                        v.__name__, probing.saccadic_padding(v.__name__), v)
                    for v in set_vocabulary_factory.registered ])))
예제 #17
0
 def get_status(self, item_type):
     result = {}
     for type_key, ti in capi.iter_type_info():
         # !+ why compare workflow_key to item_type ?!
         if (ti.workflow_key == item_type):
             states = ti.workflow.get_state_ids(
                 tagged=["public"], not_tagged=["terminal"],
                 conjunction="AND")
             for state in states:
                 state_title = translate(
                     ti.workflow.get_state(state).title,
                     domain="bungeni",
                     context=self.request
                 )
                 result[state] = state_title
             break
     return result
예제 #18
0
def on_wsgi_application_created_event(application, event):
    """Additional setup on IWSGIApplicationCreatedEvent.
    """
    # !+ui.app.on_wsgi_application_created_event ALWAYS gets called prior to this
    log.debug("CORE ON_WSGI_APPLICATION_CREATED_EVENT: %s, %s", application, event) 
    
    # additional workflow validation
    for type_key, ti in capi.iter_type_info():
        if ti.workflow:
            ti.workflow.validate_permissions_roles()
    
    #set up retract transitions in workflows
    setup_retract_transitions()
    
    # import events module, registering handlers
    import bungeni.core.workflows.events
    
    # load workspaces
    load_workspaces()
    
    # load notifications
    load_notifications()

    # load email notifications
    load_email()

    # set up serialization notifications
    serialization_notifications()
    
    # import events modules, registering handlers
    import bungeni.core.events
    
    app_setup = model_interfaces.IBungeniSetup(application)
    app_setup.setUp()
    
    # write configuration parameters to xml
    try:
        import bungeni.utils.xmlconfexport as confexp
        confexp.write_all()
    except:
        log.debug(("on_wsgi_application_created :"
            "error while exporting config parameters to xml"))
    
    log.debug("on_wsgi_application_created_event: _features: %s" % (
        getConfigContext()._features))
예제 #19
0
 def build_context(self):
     default_filters = {
         "sort_dir": u"asc", 
         "filter_status_date": u"%s->%s" % (
             self.start_date.isoformat(), self.end_date.isoformat()
         ), 
         "sort_on": u"status_date", 
         "filter_type": u"",
     }
     doc_container = self.context.publishTraverse(self.request, "documents")
     for type_key, ti in capi.iter_type_info():
         workflow = ti.workflow
         if workflow and workflow.has_feature("workspace"):
             # add generators of various doctypes
             container_name = naming.plural(type_key)
             filters = dict(default_filters)
             filters["filter_type"] = type_key
             setattr(self, container_name, doc_container.query(**filters)[0])
예제 #20
0
def get_schedulable_types(skip_permission_check=False):
    """Get types that may be scheduled. Limit to those that the current user
    has the right to transition to a scheduled state.
    You can skip the `limit to allowed types` behaviour by calling with 
    `skip_permission_check` set to `True`
    """
    schedulable_types = []
    for (key, type_info) in capi.iter_type_info():
        if type_info.workflow and type_info.workflow.has_feature("schedule"):
            schedulable_types.append((key, type_info))
    return dict([
        (type_key, dict(
            title=type_info.descriptor_model.container_name,
            domain_model=type_info.domain_model,
            workflow=type_info.workflow,
            display_name=type_info.descriptor_model.display_name
        ))
        for (type_key, type_info) in schedulable_types
        if (skip_permission_check or can_schedule(type_info.workflow))
    ])
예제 #21
0
 def getMenuItems(self, context, request):
     results = []
     unproxied = proxy.removeSecurityProxy(context.__parent__)
     items = []
     for key, info in capi.iter_type_info():
         if IScheduleContent.implementedBy(info.domain_model):
             name = naming.plural(key)
             traverser = component.getMultiAdapter((unproxied, request),
                 IPublishTraverse)
             try:
                 item = traverser.publishTraverse(request, name)
                 items.append((name, item))
             except NotFound:
                 continue
     for key, item in items:
         if not IAlchemistContainer.providedBy(item):
             continue
         if not IScheduleContent.implementedBy(item.domain_model):
             continue
         type_info = capi.get_type_info(item.domain_model)
         permission = "bungeni.%s.Add" % (
             type_info.workflow_key or 
             naming.type_key("model_name", item.domain_model.__name__)
         )
         if not checkPermission(permission, context):
             continue
         dc_adapter = IDCDescriptiveProperties(item, None)
         if dc_adapter:
             _title = dc_adapter.title
         else:
             _title = getattr(item, "title", "Unknown")
         results.append(dict(
             title=_title,
             description=_title,
             action = url.absoluteURL(item, request),
             selected=False,
             icon=None,
             extra={"id": "nav_calendar_content_%s" % key},
             submenu=None,
         ))
     return results
def load_email():
    for type_key, ti in capi.iter_type_info():
        workflow = ti.workflow
        if workflow and workflow.has_feature("email"):
            if not workflow.has_feature("notification"):
                raise EmailError("Email notifications feature for %r cannot be "
                    "enabled without first enabling the notification "
                    "feature" % (type_key)) # !+FEATURE_DEPENDENCIES
    mq_utility = component.getUtility(IMessageQueueConfig)
    connection = get_mq_connection()
    if not connection:
        return
    channel = connection.channel()
    channel.queue_declare(queue="bungeni_email_queue", durable=True)
    channel.queue_bind(queue="bungeni_email_queue",
                       exchange=str(mq_utility.get_message_exchange()),
                       routing_key="")
    for i in range(mq_utility.get_number_of_workers()):
        task_thread = Thread(target=email_worker)
        task_thread.daemon = True
        task_thread.start()
예제 #23
0
def batch_serialize(type_key="*"):
    """Serialize all objects of `type_key` or all types if with a
    wildcard(*) as the type key.
    """
    #keep count of serialized objects for feedback
    serialized_count = 0
    #list of domain classes to be serialized
    domain_models = []
    if type_key == "*":
        for (type_key, info) in capi.iter_type_info():
            if info.workflow:
                domain_models.append(info.domain_model)
    else:
        info = capi.get_type_info(type_key)
        if info.workflow:
            domain_models.append(info.domain_model)
    session = Session()
    for domain_model in domain_models:
        objects = session.query(domain_model).all()
        map(queue_object_serialization, objects)
        serialized_count += len(objects)
    return serialized_count
예제 #24
0
 def getMenuItems(self, context, request):
     results = []
     unproxied = proxy.removeSecurityProxy(context.__parent__)
     try:
         items = unproxied.items()
     except AttributeError:
         items = []
         for key, info in capi.iter_type_info():
             if IScheduleContent.implementedBy(info.domain_model):
                 name = naming.plural(key)
                 if hasattr(unproxied, name):
                     items.append((name, getattr(unproxied, name)))
     for key, item in items:
         if not IAlchemistContainer.providedBy(item): continue
         if not IScheduleContent.implementedBy(item.domain_model): continue
         type_info = capi.get_type_info(item.domain_model)
         permission = "bungeni.%s.Add" % (
             type_info.workflow_key or 
             naming.type_key("model_name", item.domain_model.__name__)
         )
         if not checkPermission(permission, context): continue
         dc_adapter = IDCDescriptiveProperties(item, None)
         if dc_adapter:
             _title = dc_adapter.title
         else:
             _title = getattr(item, "title", "Unknown")
         results.append(dict(
             title=_title,
             description=_title,
             action = url.absoluteURL(item, request),
             selected=False,
             icon=None,
             extra={},
             submenu=None
             
         ))
     return results
예제 #25
0
 def buildContext(self):
     if IWorkspaceScheduling.providedBy(self.request):
         self.buildSittings()
     elif IWorkspaceUnderConsideration.providedBy(self.context):
         default_filters = {
             'sort_dir': u'asc', 
             'filter_status_date': u'%s->%s' %(
                 self.start_date.isoformat(), self.end_date.isoformat()
             ), 
             'sort_on': u'status_date', 
             'filter_type': u'',
         }
         doc_container = self.context.publishTraverse(self.request,
             "documents")
         for type_key, ti in capi.iter_type_info():
             workflow = ti.workflow
             if workflow and workflow.has_feature("workspace"):
                 #add generators of various doctypes
                 container_name = naming.plural(type_key)
                 filters = dict(default_filters)
                 filters['filter_type'] = type_key
                 setattr(self, container_name,
                     doc_container.query(**filters)[0]
                 )
예제 #26
0
class MemberItemsViewlet(browser.BungeniItemsViewlet):
    """A tab with bills, motions etc for an MP 
    (the "parliamentary activities" tab of of the "member" view)
    """
    states = _get_public_states_for( *[ ti 
        for (key, ti) in capi.iter_type_info() 
        if ti.custom and issubclass(ti.domain_model, domain.Doc) ] )
    
    render = ViewPageTemplateFile("templates/mp-item-viewlet.pt")

    def __init__(self, context, request, view, manager):
        super(MemberItemsViewlet, self).__init__(
            context, request, view, manager)
        user_id = self.context.user_id
        parliament_id = self.context.group_id
        self.query = Session().query(domain.Doc).filter(
            sql.and_(
                domain.Doc.owner_id == user_id,
                domain.Doc.parliament_id == parliament_id,
                domain.Doc.status.in_(self.states),
            ))
        #self.for_display = (self.query.count() > 0)
        self.formatter = self.get_date_formatter("date", "medium")
    
    def update(self):
        user_id = self.context.user_id
        parliament_id = self.context.group_id
        wf = capi.get_type_info("signatory").workflow
        session = Session()
        # add cosigned items
        signed_pi_ids = [sgn.head_id for sgn in
            session.query(domain.Signatory).filter(
                sql.and_(domain.Signatory.user_id == user_id,
                    domain.Signatory.status.in_(
                        wf.get_state_ids(tagged=["public"])
                    ),
                )
            ).all()
        ]
        if len(signed_pi_ids) > 0:
            self.query = self.query.union(
                session.query(domain.Doc).filter(
                    sql.and_(
                        domain.Doc.parliament_id == parliament_id,
                        domain.Doc.status.in_(self.states),
                        domain.Doc.doc_id.in_(
                            signed_pi_ids
                        )
                    )
                )
            )
        self.query = self.query.order_by(
            domain.Doc.doc_id.desc()
        )
    
    @property
    def items(self):
        for item in self.query.all():
            _url = "/business/%ss/obj-%i" % (item.type,
                item.doc_id)
            yield {"type": item.type,
                "title": item.title,
                "status": misc.get_wf_state(item),
                "submission_date" : item.submission_date,
                "url": _url }
예제 #27
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")))
        
        # ensure indexing facilities are setup(lazy)
        import index
        index.setupFieldDefinitions(index.indexer)
        
        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_current_parliament, "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_current_parliament, "sittings"),
            title=_("section_scheduling_sittings", default=u"Sittings"),
            description=_(u"Plenary Sittings"))
        ws_sched["agendaitems"] = QueryContent(
            container_getter(get_current_parliament, "agendaitems"),
            title=_("section_scheduling_agenda_items", 
                default=u"Agenda items"),
            #marker=interfaces.IAgendaItemAddContext,
            description=_(u"Manage agenda items"))
        
        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 key, info in capi.iter_type_info():
            if model_interfaces.IScheduleContent.implementedBy(info.domain_model):
                container_name = "%ss" % key
                container = "%sContainer" % info.domain_model.__name__
                ws_sched[container_name] = getattr(domain, container)()
                to_locatable_container(info.domain_model, ws_sched[container_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)
        alsoProvides(admin, interfaces.ISearchableSection)
        
        content = admin["content"] = Section(
            title=_(u"Content"),
            description=_(u"browse bungeni content"),
            marker=model_interfaces.IBungeniAdmin,
            default_name="browse-admin")
        
        admin["email-settings"] = Section(
            title=_(u"email settings"),
            description=_(u"manage email settings"),
            marker=model_interfaces.IBungeniAdmin,
            default_name="email-settings")
        
        admin["xapian-settings"] = Section(
            title=_(u"search index settings"),
            description=_(u"manage search index settings"),
            marker=model_interfaces.IBungeniAdmin,
            default_name="xapian-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"users"] = domain.UserContainer()
        to_locatable_container(domain.User, content[u"users"])

        api = self.context["api"] = APISection(
            title=_(u"Bungeni API"),
            description=_(u"Bungeni REST API"),
            default_name="index.html",
        )
        api["oauth"] = OAuthSection(
            title=_(u"Bungeni OAuth API"),
            description=_(u"Bungeni OAuth API"),
            default_name="index.html",
        )
        admin[u"applications"] = domain.OAuthApplicationContainer()
        to_locatable_container(domain.OAuthApplication, admin[u"applications"])
예제 #28
0
def setup_customization_ui():
    """Called from ui.app.on_wsgi_application_created_event -- must be called
    late, at least as long as there other ui zcml directives (always executed 
    very late) that need to have been executed prior to this e.g. 
    creation of specific menus such as "context_actions".
    """
    def register_menu_item(type_key,
                           privilege,
                           title,
                           for_,
                           action,
                           menu="context_actions",
                           order=10,
                           layer="bungeni.ui.interfaces.IBungeniSkin"):
        naming.MSGIDS.add(title)  # for i18n extraction
        UI_ZC_DECLS.append(register_menu_item.TMPL.format(**locals()))

    register_menu_item.TMPL = """
            <browser:menuItem menu="{menu}"
                for="{for_}"
                action="{action}"
                title="{title}"
                order="{order}"
                permission="bungeni.{type_key}.{privilege}"
                layer="{layer}"
            />"""

    def register_form_view(type_key,
                           privilege,
                           name,
                           for_,
                           class_,
                           layer="bungeni.ui.interfaces.IBungeniSkin"):
        UI_ZC_DECLS.append(register_form_view.TMPL.format(**locals()))

    register_form_view.TMPL = """
            <browser:page name="{name}"
                for="{for_}"
                class="{class_}"
                permission="bungeni.{type_key}.{privilege}"
                layer="{layer}"
            />"""

    def register_api_view(type_key, for_):
        UI_ZC_DECLS.append(register_api_view.TMPL.format(**locals()))

    register_api_view.TMPL = """
            <browser:page name="view"
                for="{for_}"
                class="bungeni.ui.api.APIObjectView"
                permission="bungeni.{type_key}.View"
                layer="bungeni.ui.interfaces.IBungeniAPILayer"
            />"""

    def model_title(type_key):
        return naming.split_camel(naming.model_name(type_key))

    UI_ZC_DECLS[:] = []
    # we assume that non-custom types have already been set up as needed
    for type_key, ti in capi.iter_type_info(scope="custom"):
        UI_ZC_DECLS.append("""
            
            <!-- {type_key} -->""".format(type_key=type_key))

        type_title = model_title(type_key)
        # model interface is defined, but container interface is not yet
        model_interface_qualname = naming.qualname(ti.interface)
        container_interface_qualname = "bungeni.models.interfaces.%s" % (
            naming.container_interface_name(type_key))

        # generic forms (independent of any feature)
        # add
        register_form_view(type_key, "Add", "add",
                           container_interface_qualname,
                           "bungeni.ui.forms.common.AddForm")
        # view
        register_form_view(type_key, "View", "view", model_interface_qualname,
                           "bungeni.ui.forms.common.DisplayForm")

        register_api_view(type_key, model_interface_qualname)
        # edit !+DiffEditForm prior to r10032, doc-archetyped types were being
        # *declared* to use bungeni.ui.forms.forms.DiffEditForm, but this
        # is not the edit view tht was actually being used!
        #register_form_view(type_key, "Edit", "edit", model_interface_qualname,
        #    "bungeni.ui.forms.common.EditForm")
        if issubclass(ti.interface, IBungeniGroup):
            register_form_view(type_key, "Edit", "edit",
                               model_interface_qualname,
                               "bungeni.ui.forms.common.GroupEditForm")
        else:
            register_form_view(type_key, "Edit", "edit",
                               model_interface_qualname,
                               "bungeni.ui.forms.common.EditForm")
        # delete
        register_form_view(type_key, "Delete", "delete",
                           model_interface_qualname,
                           "bungeni.ui.forms.common.DeleteForm")

        # plone content menu (for custom types)
        # !+ doc-types were previously being layered on IWorkspaceOrAdminSectionLayer
        # !+ there was previously no reg for IReportConatiner and one of the member
        # containers, plus there was inconsistency in permission for
        # IOfficeMemberContainer (was bungeni.office.Add).
        register_menu_item(type_key,
                           "Add",
                           "Add %s..." % (type_title),
                           container_interface_qualname,
                           "./add",
                           menu="plone_contentmenu",
                           layer="bungeni.ui.interfaces.IAdminSectionLayer")

        # workspace
        if ti.workflow.has_feature("workspace"):
            log.debug("Setting up UI for feature %r for type %r", "workspace",
                      type_key)

            # add menu item
            # !+workspace_feature_add(mr, oct-2012) note that an enabled
            # workspace feature also implies "add" functionality for the type
            first_tab = capi.workspace_tabs[0]
            action = "../../{first_tab}/add_{k}".format(first_tab=first_tab,
                                                        k=type_key)
            register_menu_item(type_key,
                               "Add",
                               type_title,
                               "*",
                               action,
                               menu="workspace_add_parliamentary_content",
                               order=7)

            # add menu item -> for admin ?!
            # !+ why a duplicated (almost identical) menu item for admin?
            # !+ criteria here is having workspace enabled... but, cirterion
            # should be simply that of being "parliamentary"? Do we need to
            # formalize this distinction?
            # !+ need a formal "container attribute" naming convention!
            action = "{k}/add".format(k=naming.plural(type_key))
            register_menu_item(type_key,
                               "Add",
                               type_title,
                               "*",
                               action,
                               menu="context_add_parliamentary_content",
                               order=7)

            # edit menu item
            # !+ edit/delete used to be on layer="bungeni.ui.interfaces.IWorkspaceOrAdminSectionLayer"
            title = "Edit {t}".format(t=type_title)
            register_menu_item(type_key,
                               "Edit",
                               title,
                               model_interface_qualname,
                               "edit",
                               menu="context_actions",
                               order=10)

            # delete menu item
            title = "Delete {t}".format(t=type_title)
            register_menu_item(type_key,
                               "Delete",
                               title,
                               model_interface_qualname,
                               "delete",
                               menu="context_actions",
                               order=99)

            # add view
            name = "add_{type_key}".format(type_key=type_key)
            register_form_view(type_key, "Add", name,
                               "bungeni.core.interfaces.IWorkspaceTab",
                               "bungeni.ui.workspace.WorkspaceAddForm")

        # events
        if ti.workflow.has_feature("event"):
            log.debug("Setting up UI for feature %r for type %r", "event",
                      type_key)
            for event_type_key in ti.workflow.get_feature(
                    "event").params["types"]:
                if capi.has_type_info(event_type_key):
                    container_property_name = naming.plural(event_type_key)
                    # add menu item
                    title = "{t} {e}".format(t=type_title,
                                             e=model_title(event_type_key))
                    register_menu_item(
                        event_type_key,
                        "Add",
                        "Add %s" % (title),
                        model_interface_qualname,
                        "./%s/add" % (container_property_name),
                        menu="additems",
                        order=21,
                        layer=
                        "bungeni.ui.interfaces.IWorkspaceOrAdminSectionLayer")
                else:
                    log.warn(
                        'IGNORING feature "event" ref to disabled type %r',
                        event_type_key)

        # register other non-workspace menu items for custom types (only once)
        # custom events !+GET_ARCHETYPE
        if issubclass(ti.domain_model, domain.Event):
            # edit menu item
            register_menu_item(
                type_key,
                "Edit",
                "Edit {t}".format(t=type_title),
                model_interface_qualname,
                "edit",
                menu="context_actions",
                order=10,
                layer="bungeni.ui.interfaces.IWorkspaceOrAdminSectionLayer")
            # delete menu item
            register_menu_item(
                type_key,
                "Delete",
                "Delete {t}".format(t=type_title),
                model_interface_qualname,
                "delete",
                menu="context_actions",
                order=99,
                layer="bungeni.ui.interfaces.IWorkspaceOrAdminSectionLayer")

        # address
        if ti.workflow.has_feature("address"):
            log.debug("Setting up UI for feature %r for type %r", "address",
                      type_key)
            if issubclass(ti.domain_model, domain.Group):
                title = "Add {t} Address".format(t=type_title)
                #layer="bungeni.ui.interfaces.IWorkspaceOrAdminSectionLayer"
                # add address in the "add items..." menu
                register_menu_item("address",
                                   "Add",
                                   title,
                                   model_interface_qualname,
                                   "./addresses/add",
                                   menu="additems",
                                   order=80)
            elif issubclass(ti.domain_model, domain.User):
                # !+ User not a custom type (so should never pass here)
                assert False, "Type %s may not be a custom type" % (
                    ti.domain_model)
예제 #29
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"])
예제 #30
0
def load_workspaces():
    for type_key, ti in capi.iter_type_info():
        if ti.workflow and ti.workflow.has_feature("workspace"):
            load_workspace("%s.xml" % type_key, ti.domain_model, ti.workflow)
        kw["class"] = kw.get("css_class")
        del kw["css_class"]
    _element = etree.SubElement(parent, tag, **kw)
    if text: 
        _element.text = str(text)
    return _element

SITTING_EXTRAS = []

class ExtendedProperty(object):
    def __init__(self, key, class_):
        self.key = key
        self.mapper = class_
        self.uselist = True

for type_key, type_info in capi.iter_type_info():
    if type_info.workflow and type_info.workflow.has_feature("schedule"):
        SITTING_EXTRAS.append(
            ExtendedProperty("%ss" % type_key, type_info.domain_model)
        )

PROCESSED_PROPS = {}

def generate_doc_for(domain_class, title=None, expand=True):
    doc = etree.fromstring(SIMPLE_LIST)
    dc_adapter = None
    if title:
        add_sub_element(doc, "li", title)
    if not isinstance(domain_class, Mapper):
        dc_adapter = IDCDescriptiveProperties(domain_class(), None)
        mapped = class_mapper(domain_class)
예제 #32
0
def load_workspaces():
    for type_key, ti in capi.iter_type_info():
        if ti.workflow and ti.workflow.has_feature("workspace"):
            load_workspace("%s.xml" % type_key, ti.domain_model, ti.workflow)
예제 #33
0
def catalyse_system_descriptors(module):
    """Catalyze system descriptor classes (with by-name-convention associated 
    model class) in specified module.
    
    Called when ui.descriptor is initially imported, so before descriptors for 
    custom types have been created (that happens on first call to 
    localization.localize_descriptors on application created event).
    
    !+CATALYSE_SYSTEM_DESCRIPTORS(mr, feb-2013) drop this, reworking it into
    catalysing on first time to localize each descriptor.
    """
    import sys
    import inspect
    from bungeni.alchemist.descriptor import IModelDescriptor
    from bungeni.models import domain
    from bungeni.capi import capi
    from bungeni.ui.utils import debug
    
    def descriptor_classes():
        """A generator of descriptor classes in this module, preserving the
        order of definition.
        """
        # dir() returns names in alphabetical order
        decorated = []
        for key in dir(module):
            cls = getattr(module, key)
            try:
                assert IModelDescriptor.implementedBy(cls)
                # we decorate with the source code line number for the cls
                decorated.append((inspect.getsourcelines(cls)[1], cls))
            except (TypeError, AttributeError, AssertionError):
                debug.log_exc(sys.exc_info(), log_handler=log.debug)
        # we yield each cls in order of definition
        for cls in [ cls for (line_num, cls) in sorted(decorated) ]:
            yield cls
    
    def is_model_mapped(domain_model):
        # try get mapper to force UnmappedClassError
        try:
            orm.class_mapper(domain_model)
            return True
        except orm.exc.UnmappedClassError:
            # unmapped class e.g. Address, Version
            return False
    
    for descriptor_model in descriptor_classes():
        descriptor_name = descriptor_model.__name__
        type_key = naming.type_key("descriptor_class_name", descriptor_name)
        # Associate each descriptor to the dedicated domain type via naming 
        # convention, and only catalysze (descriptor, model) pairs 
        # for which the domain type is mapped. Otherwise, ignore.
        domain_model = getattr(domain, naming.model_name(type_key), None)
        if not (domain_model and is_model_mapped(domain_model)):
            log.warn("Not catalysing: %s", descriptor_name)
            continue
        # type_info, register descriptor_model, domain_model
        ti = capi.get_type_info(type_key)
        utils.inisetattr(ti, "domain_model", domain_model)
        utils.inisetattr(ti, "descriptor_model", descriptor_model)
        # catalyse each (domain_model, descriptor_model) pair
        catalyse(ti)
    
    # !+remove?
    m = "\n\nDone all setup of system types... running with:\n\n%s\n\n" % (
            "\n\n".join(sorted(
                [ "%s: %s" % (key, ti) for key, ti in capi.iter_type_info() ])
            ))
    log.debug(m)
예제 #34
0
def setup_customization_ui():
    """Called from ui.app.on_wsgi_application_created_event -- must be called
    late, at least as long as there other ui zcml directives (always executed 
    very late) that need to have been executed prior to this e.g. 
    creation of specific menus such as "context_actions".
    """
    
    def register_menu_item(type_key, privilege, title, for_, action,
            menu="context_actions", 
            order=10,
            layer="bungeni.ui.interfaces.IBungeniSkin"
        ):
        naming.MSGIDS.add(title) # for i18n extraction
        UI_ZC_DECLS.append(register_menu_item.TMPL.format(**locals()))
    register_menu_item.TMPL = """
            <browser:menuItem menu="{menu}"
                for="{for_}"
                action="{action}"
                title="{title}"
                order="{order}"
                permission="bungeni.{type_key}.{privilege}"
                layer="{layer}"
            />"""
    
    def register_form_view(type_key, privilege, name, for_, class_,
            layer="bungeni.ui.interfaces.IBungeniSkin"
        ):
        UI_ZC_DECLS.append(register_form_view.TMPL.format(**locals()))
    register_form_view.TMPL = """
            <browser:page name="{name}"
                for="{for_}"
                class="{class_}"
                permission="bungeni.{type_key}.{privilege}"
                layer="{layer}"
            />"""

    def register_api_view(type_key, for_):
        UI_ZC_DECLS.append(register_api_view.TMPL.format(**locals()))
    register_api_view.TMPL = """
            <browser:page name="index"
                for="{for_}"
                class="bungeni.ui.api.APIObjectView"
                permission="bungeni.{type_key}.View"
                layer="bungeni.ui.interfaces.IBungeniAPILayer"
            />"""

    def model_title(type_key):
        return naming.split_camel(naming.model_name(type_key))
    
    UI_ZC_DECLS[:] = []
    # we assume that non-custom types have already been set up as needed
    for type_key, ti in capi.iter_type_info(scope="custom"):
        UI_ZC_DECLS.append("""
            
            <!-- {type_key} -->""".format(type_key=type_key))
        
        type_title = model_title(type_key)
        # model interface is defined, but container interface is not yet
        model_interface_qualname = naming.qualname(ti.interface)
        container_interface_qualname = "bungeni.models.interfaces.%s" % (
                naming.container_interface_name(type_key))
        
        # generic forms (independent of any feature)
        # add
        register_form_view(type_key, "Add", "add", container_interface_qualname,
            "bungeni.ui.forms.common.AddForm")
        # view
        register_form_view(type_key, "View", "index", model_interface_qualname,
            "bungeni.ui.forms.common.DisplayForm")
        
        register_api_view(type_key, model_interface_qualname)
        # edit !+DiffEditForm prior to r10032, doc-archetyped types were being
        # *declared* to use bungeni.ui.forms.forms.DiffEditForm, but this
        # is not the edit view tht was actually being used!
        #register_form_view(type_key, "Edit", "edit", model_interface_qualname,
        #    "bungeni.ui.forms.common.EditForm")
        if issubclass(ti.interface, IBungeniGroup):
            register_form_view(type_key, "Edit", "edit",
                model_interface_qualname,
                "bungeni.ui.forms.common.GroupEditForm")
        else:
            register_form_view(type_key, "Edit", "edit",
            model_interface_qualname,
            "bungeni.ui.forms.common.EditForm")
        # delete
        register_form_view(type_key, "Delete", "delete", model_interface_qualname,
            "bungeni.ui.forms.common.DeleteForm")
        
        # plone content menu (for custom types)
        # !+ doc-types were previously being layered on IWorkspaceOrAdminSectionLayer
        # !+ there was previously no reg for IReportConatiner and one of the member
        # containers, plus there was inconsistency in permission for 
        # IOfficeMemberContainer (was bungeni.office.Add).
        register_menu_item(type_key, "Add", "Add %s..." % (type_title), 
            container_interface_qualname,
            "./add",
            menu="plone_contentmenu",
            layer="bungeni.ui.interfaces.IAdminSectionLayer")
        
        # workspace
        if ti.workflow.has_feature("workspace"):
            log.debug("Setting up UI for feature %r for type %r", "workspace", type_key)
            
            # add menu item
            # !+workspace_feature_add(mr, oct-2012) note that an enabled
            # workspace feature also implies "add" functionality for the type
            first_tab = capi.workspace_tabs[0]
            action = "../../{first_tab}/add_{k}".format(first_tab=first_tab,
                k=type_key)
            register_menu_item(type_key, "Add", type_title, "*", action,
                menu="workspace_add_parliamentary_content", order=7)
            
            # add menu item -> for admin ?!
            # !+ why a duplicated (almost identical) menu item for admin?
            # !+ criteria here is having workspace enabled... but, cirterion 
            # should be simply that of being "parliamentary"? Do we need to 
            # formalize this distinction?
            # !+ need a formal "container attribute" naming convention!
            action = "{k}/add".format(k=naming.plural(type_key)) 
            register_menu_item(type_key, "Add", type_title, "*", action,
                menu="context_add_parliamentary_content", order=7)
            
            # edit menu item
            # !+ edit/delete used to be on layer="bungeni.ui.interfaces.IWorkspaceOrAdminSectionLayer"
            title = "Edit {t}".format(t=type_title)
            register_menu_item(type_key, "Edit", title, model_interface_qualname, "edit",
                menu="context_actions", order=10)
            
            # delete menu item
            title = "Delete {t}".format(t=type_title)
            register_menu_item(type_key, "Delete", title, model_interface_qualname, "delete",
                menu="context_actions", order=99)
            
            # add view
            name = "add_{type_key}".format(type_key=type_key)
            register_form_view(type_key, "Add", name,
                "bungeni.core.interfaces.IWorkspaceTab",
                "bungeni.ui.workspace.WorkspaceAddForm")
        
        # events
        if ti.workflow.has_feature("event"):
            log.debug("Setting up UI for feature %r for type %r", "event", type_key)
            for event_type_key in ti.workflow.get_feature("event").params["types"]:
                if capi.has_type_info(event_type_key):
                    container_property_name = naming.plural(event_type_key)
                    # add menu item
                    title = "{t} {e}".format(t=type_title, e=model_title(event_type_key))
                    register_menu_item(event_type_key, "Add", "Add %s" %(title),
                        model_interface_qualname, 
                        "./%s/add" % (container_property_name), 
                        menu="additems", 
                        order=21,
                        layer="bungeni.ui.interfaces.IWorkspaceOrAdminSectionLayer")
                else:
                    log.warn('IGNORING feature "event" ref to disabled type %r', 
                        event_type_key)
        
        # register other non-workspace menu items for custom types (only once)
        # custom events !+GET_ARCHETYPE
        if issubclass(ti.domain_model, domain.Event):
            # edit menu item
            register_menu_item(type_key, "Edit", "Edit {t}".format(t=type_title),
                model_interface_qualname,
                "edit",
                menu="context_actions",
                order=10,
                layer="bungeni.ui.interfaces.IWorkspaceOrAdminSectionLayer")
            # delete menu item
            register_menu_item(type_key, "Delete", "Delete {t}".format(t=type_title),
                model_interface_qualname,
                "delete",
                menu="context_actions",
                order=99,
                layer="bungeni.ui.interfaces.IWorkspaceOrAdminSectionLayer")
        
        # address
        if ti.workflow.has_feature("address"):
            log.debug("Setting up UI for feature %r for type %r", "address", type_key)
            if issubclass(ti.domain_model, domain.Group):
                title = "Add {t} Address".format(t=type_title)
                #layer="bungeni.ui.interfaces.IWorkspaceOrAdminSectionLayer"
                # add address in the "add items..." menu
                register_menu_item("address", "Add", title, model_interface_qualname, 
                    "./addresses/add", menu="additems", order=80)
            elif issubclass(ti.domain_model, domain.User):
                # !+ User not a custom type (so should never pass here)
                assert False, "Type %s may not be a custom type" % (ti.domain_model)