예제 #1
0
def new_custom_domain_model(type_key, domain_interface, archetype_key):
    domain_model_name = naming.model_name(type_key)
    assert archetype_key, \
        "Custom descriptor %r does not specify an archetype" % (type_key)
    archetype = getattr(MODEL_MODULE,
                        naming.model_name(archetype_key))  # AttributeError
    # !+ assert archetype constraints
    domain_model = type(domain_model_name, (archetype, ), {
        "__module__": MODEL_MODULE.__name__,
        "extended_properties": [],
    })
    # apply domain_interface
    classImplements(domain_model, domain_interface)
    # set on MODEL_MODULE (register on type_info downstream)
    setattr(MODEL_MODULE, domain_model_name, domain_model)
    # db map custom domain class
    from sqlalchemy.orm import mapper
    mapper(
        domain_model,
        inherits=archetype,
        polymorphic_on=utils.get_local_table(archetype).c.type,
        polymorphic_identity=
        type_key,  #naming.polymorphic_identity(domain_model),
    )
    log.info("new_custom_domain_model [%s] %s.%s" %
             (type_key, MODEL_MODULE.__name__, domain_model_name))
    return domain_model
예제 #2
0
def new_custom_domain_model(type_key, domain_interface, archetype_key):
    domain_model_name = naming.model_name(type_key)
    assert archetype_key, \
        "Custom descriptor %r does not specify an archetype" % (type_key)
    archetype = getattr(MODEL_MODULE, naming.model_name(archetype_key)) # AttributeError
    # !+ assert archetype constraints
    domain_model = type(domain_model_name,
        (archetype,),
        {
            "__module__": MODEL_MODULE.__name__,
            "extended_properties": [],
        }
    )
    # apply domain_interface
    classImplements(domain_model, domain_interface)
    # set on MODEL_MODULE (register on type_info downstream)
    setattr(MODEL_MODULE, domain_model_name, domain_model)
    # db map custom domain class
    from sqlalchemy.orm import mapper
    mapper(domain_model, 
        inherits=archetype,
        polymorphic_on=utils.get_local_table(archetype).c.type,
        polymorphic_identity=type_key, #naming.polymorphic_identity(domain_model),
    )
    log.info("new_custom_domain_model [%s] %s.%s" % (
            type_key, MODEL_MODULE.__name__, domain_model_name))
    return domain_model
예제 #3
0
def register_new_custom_type(type_key, workflow_key, archetype_key):
    """Retrieve (create if needed) a domain interface and model for type_key,
    and register as new entry on TYPE_REGISTER.
    """
    
    # generate custom domain interface
    domain_iface_name = naming.model_interface_name(type_key)
    try:
        domain_iface = resolve("%s.%s" % (INTERFACE_MODULE.__name__, domain_iface_name))
        log.warn("Custom interface ALREADY EXISTS: %s" % (domain_iface))
    except ImportError:
        domain_iface = new_custom_domain_interface(type_key, domain_iface_name)
    
    # generate custom domain_model
    domain_model_name = naming.model_name(type_key)
    try:
        domain_model = resolve("%s.%s" % (MODEL_MODULE.__name__, domain_model_name))
        log.warn("Custom domain model ALREADY EXISTS: %s" % (domain_model))
    except ImportError:
        domain_model = new_custom_domain_model(type_key, domain_iface, archetype_key)
    
    # type_info entry
    ti = TI(workflow_key, domain_iface, domain_model)
    ti.custom = True
    TYPE_REGISTRY.append((type_key, ti))
    
    log.info("Registered custom type [%s]: %s" % (archetype_key, type_key))
    return type_key, ti
예제 #4
0
def register_new_custom_type(type_key, workflow_key, archetype_key):
    """Retrieve (create if needed) a domain interface and model for type_key,
    and register as new entry on TYPE_REGISTER.
    """

    # generate custom domain interface
    domain_iface_name = naming.model_interface_name(type_key)
    try:
        domain_iface = resolve("%s.%s" %
                               (INTERFACE_MODULE.__name__, domain_iface_name))
        log.warn("Custom interface ALREADY EXISTS: %s" % (domain_iface))
    except ImportError:
        domain_iface = new_custom_domain_interface(type_key, domain_iface_name)

    # generate custom domain_model
    domain_model_name = naming.model_name(type_key)
    try:
        domain_model = resolve("%s.%s" %
                               (MODEL_MODULE.__name__, domain_model_name))
        log.warn("Custom domain model ALREADY EXISTS: %s" % (domain_model))
    except ImportError:
        domain_model = new_custom_domain_model(type_key, domain_iface,
                                               archetype_key)

    # type_info entry
    ti = TI(workflow_key, domain_iface, domain_model)
    ti.custom = True
    TYPE_REGISTRY.append((type_key, ti))

    log.info("Registered custom type [%s]: %s" % (archetype_key, type_key))
    return type_key, ti
예제 #5
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")    
예제 #6
0
def retrieve_domain_model(type_key):
    """Infer and retrieve the target domain model class from the type key.
    Raise AttributeError if not defined on model module.
    !+ mv to catalyst.utils?
    """
    return resolve("%s.%s" %
                   (MODEL_MODULE.__name__, naming.model_name(type_key)))
예제 #7
0
def register_new_custom_type(type_key, workflow_key, custom_archetype_key,
                             sys_archetype_key):
    """Retrieve (create if needed) a domain interface and model for type_key,
    and register as new entry on TYPE_REGISTER.
    """
    archetype_model = resolve(
        "%s.%s" %
        (MODEL_MODULE.__name__, naming.model_name(custom_archetype_key)))
    # validate that custom archetype uses correct system archetype
    if custom_archetype_key != sys_archetype_key:
        sys_archetype_model = resolve(
            "%s.%s" %
            (MODEL_MODULE.__name__, naming.model_name(sys_archetype_key)))
        assert issubclass(archetype_model, sys_archetype_model), \
            "Custom archetype %r for type %r is not a sub-type of %r." % (
                custom_archetype_key, type_key, sys_archetype_key)

    # generate custom domain interface
    domain_iface_name = naming.model_interface_name(type_key)
    try:
        domain_iface = resolve("%s.%s" %
                               (INTERFACE_MODULE.__name__, domain_iface_name))
        log.warn("Custom interface ALREADY EXISTS: %s" % (domain_iface))
    except ImportError:
        domain_iface = new_custom_domain_interface(type_key, domain_iface_name)

    # generate custom domain_model
    domain_model_name = naming.model_name(type_key)
    try:
        domain_model = resolve("%s.%s" %
                               (MODEL_MODULE.__name__, domain_model_name))
        log.warn("Custom domain model ALREADY EXISTS: %s" % (domain_model))
    except ImportError:
        domain_model = new_custom_domain_model(type_key, domain_iface,
                                               custom_archetype_key)

    # type_info entry
    ti = TI(workflow_key, domain_iface, domain_model, archetype_model)
    ti.custom = True
    TYPE_REGISTRY.append((type_key, ti))

    log.info("Registered custom type [%s]: %s" %
             (custom_archetype_key, type_key))
    return type_key, ti
예제 #8
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")
예제 #9
0
def get_feature_cls(feature_name):
    """Get the Feature implementation class by the feature name.
    
    All retrieval of Feature classes MUST be done vis this utility.
    """
    feature_cls_name = naming.model_name(feature_name)
    try:
        return globals()[feature_cls_name]
    except KeyError:
        feature_module_name = "feature_%s" % (feature_name)
        feature_module = __import__("bungeni.feature.%s" % (feature_module_name), fromlist=[feature_module_name])
        return getattr(feature_module, feature_cls_name)
예제 #10
0
def get_feature_cls(feature_name):
    """Get the Feature implementation class by the feature name.
    
    All retrieval of Feature classes MUST be done vis this utility.
    """
    feature_cls_name = naming.model_name(feature_name)
    try:
        return globals()[feature_cls_name]
    except KeyError:
        feature_module_name = "feature_%s" % (feature_name)
        feature_module = __import__("bungeni.feature.%s" % (feature_module_name),
            fromlist=[feature_module_name])
        return getattr(feature_module, feature_cls_name)
예제 #11
0
def register_new_custom_type(type_key, workflow_key, 
        custom_archetype_key, sys_archetype_key
    ):
    """Retrieve (create if needed) a domain interface and model for type_key,
    and register as new entry on TYPE_REGISTER.
    """
    archetype_model = resolve("%s.%s" % (
            MODEL_MODULE.__name__, naming.model_name(custom_archetype_key)))
    # validate that custom archetype uses correct system archetype
    if custom_archetype_key != sys_archetype_key:
        sys_archetype_model = resolve("%s.%s" % (
                MODEL_MODULE.__name__, naming.model_name(sys_archetype_key)))
        assert issubclass(archetype_model, sys_archetype_model), \
            "Custom archetype %r for type %r is not a sub-type of %r." % (
                custom_archetype_key, type_key, sys_archetype_key)
    
    # generate custom domain interface
    domain_iface_name = naming.model_interface_name(type_key)
    try:
        domain_iface = resolve("%s.%s" % (INTERFACE_MODULE.__name__, domain_iface_name))
        log.warn("Custom interface ALREADY EXISTS: %s" % (domain_iface))
    except ImportError:
        domain_iface = new_custom_domain_interface(type_key, domain_iface_name)
    
    # generate custom domain_model
    domain_model_name = naming.model_name(type_key)
    try:
        domain_model = resolve("%s.%s" % (MODEL_MODULE.__name__, domain_model_name))
        log.warn("Custom domain model ALREADY EXISTS: %s" % (domain_model))
    except ImportError:
        domain_model = new_custom_domain_model(type_key, domain_iface, custom_archetype_key)
    
    # type_info entry
    ti = TI(workflow_key, domain_iface, domain_model, archetype_model)
    ti.custom = True
    TYPE_REGISTRY.append((type_key, ti))
    
    log.info("Registered custom type [%s]: %s" % (custom_archetype_key, type_key))
    return type_key, ti
예제 #12
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")    
예제 #13
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")
예제 #14
0
def get_vp_kls(extended_type):
    kls_name = naming.model_name(extended_type)
    return getattr(MODEL_MODULE.vp, kls_name)
예제 #15
0
def _load(workflow_name, workflow):
    """ (workflow_name:str, workflow:etree_doc) -> Workflow
    """
    workflow_title = xas(workflow, "title")
    naming.MSGIDS.add(workflow_title)
    workflow_description = xas(workflow, "description")
    naming.MSGIDS.add(workflow_description)
    transitions = []
    states = []
    note = xas(workflow, "note")
    
    # initial_state, in XML indicated with a transition.@source=""
    initial_state = None
    
    ZCML_PROCESSED = bool(workflow_name in ZCML_WORKFLOWS_PROCESSED)
    if not ZCML_PROCESSED:
        ZCML_WORKFLOWS_PROCESSED.add(workflow_name)
        ZCML_LINES.append(ZCML_INDENT)
        ZCML_LINES.append(ZCML_INDENT)
        ZCML_LINES.append("%s<!-- %s -->" % (ZCML_INDENT, workflow_name))
    
    def validate_id(id, tag):
        """Ensure that ID values are unique within the same XML doc scope.
        """
        m = "Invalid element <%s> id=%r in workflow %r" % (tag, id, workflow_name)
        assert id not in validate_id.wuids, "%s -- id not unique in workflow document" % (m)
        validate_id.wuids.add(id)
    validate_id.wuids = set() # unique IDs in this XML workflow file
    
    def get_from_state(state_id):
        if state_id is None:
            return
        for state in states:
            if state.id == state_id:
                return state
        raise ValueError("Invalid value: permissions_from_state=%r" % (state_id))
    
    def check_not_global_grant(pid, role):
        # ensure global and local assignments are distinct
        # (global: global_pid_roles, workflow_name)
        global_proles = global_pid_roles.get(pid, "")
        assert role not in global_proles, ("Workflow [%s] may not mix "
            "global and local granting of a same permission [%s] to a "
            "same role [%s].") % (workflow_name, pid, role)
    
    # permission_actions -> permissions for this type
    for (key, permission_action) in capi.schema.qualified_permission_actions(
            workflow_name, xas(workflow, "permission_actions", "").split()
        ):
        pid = "bungeni.%s.%s" % (key, permission_action)
        title = "%s %s" % (
            permission_action, naming.split_camel(naming.model_name(key)))
        # !+ add to a Workflow.defines_permissions list
        ZCML_LINES.append(
            '%s<permission id="%s" title="%s" />' % (ZCML_INDENT, pid, title))
        provideUtility(Permission(pid), IPermission, pid)
    
    # global grants
    global_pid_roles = {} # {pid: [role]}
    global_grants = get_permissions_from_allows(workflow_name, workflow)
    for (setting, pid, role) in global_grants:
        # for each global permission, build list of roles it is set to
        global_pid_roles.setdefault(pid, []).append(role)
        assert setting and pid and role, \
            "Global grant must specify valid permission/role" #!+RNC
        # !+ add to a Workflow.global_grants list
        ZCML_LINES.append(
            '%s<grant permission="%s" role="%s" />' % (ZCML_INDENT, pid, role))
        # no real need to check that the permission and role of a global grant 
        # are properly registered in the system -- an error should be raised 
        # by the zcml if either is not defined.
        rpm.grantPermissionToRole(pid, role, check=False)

    for perm, roles in global_pid_roles.items():
        # assert roles mix limitations for state permissions
        assert_distinct_permission_scopes(perm, roles, workflow_name, "global grants")
    
    # all workflow features (enabled AND disabled)
    workflow_features = load_features(workflow_name, workflow)
    enabled_feature_names = [None] + [ 
        f.name for f in workflow_features if f.enabled ]
    # !+EVENT_FEATURE_TYPES add each as enabled_feature_names, or extend the 
    # facet quailifer by feature_name(sub_type_key).facet_ref?
    # workflow facets
    workflow_facets = load_facets(workflow_name, workflow)
    
    # states
    for s in workflow.iterchildren("state"):
        # @id
        state_id = xas(s, "id")
        assert state_id, "Workflow State must define @id" #!+RNC
        validate_id(state_id, "state")
        
        # @actions - transition-to-state actions
        state_actions = []
        for action_name in xas(s, "actions", "").split():
            state_actions.append(capi.get_workflow_action(action_name))
        
        # @permissions_from_state
        permissions = [] # [ tuple(bool:int, permission:str, role:str) ]
        # state.@permissions_from_state : to reduce repetition and enhance 
        # maintainibility of workflow XML files, a state may inherit ALL 
        # permissions defined by the specified state. NO other permissions 
        # may be specified by this state. 
        from_state = get_from_state(xas(s, "permissions_from_state"))
        parent_permissions = xab(s, "parent_permissions")
        if parent_permissions:
            pass # no own permission definitions allowed
        elif from_state:
            # assimilate (no more no less) the state's permissions !+tuple, use same?
            permissions[:] = from_state.permissions
        else:
            used_facets_fq = resolve_state_facets(
                workflow_name, workflow_facets, enabled_feature_names, s)
            # assimilate permissions from facets from None and all enabled features
            def add_facet_permissions(facet):
                for perm in facet.permissions:
                    check_add_assign_permission(workflow_name, permissions, perm)
                    check_not_global_grant(perm[1], perm[2])
            for (feature_name, qtk) in used_facets_fq:
                # debug check that feature is enabled
                assert feature_name in enabled_feature_names
                facet = used_facets_fq[(feature_name, qtk)]
                if facet is not None:
                    add_facet_permissions(facet)
        
        # states
        state_title = xas(s, "title")
        naming.MSGIDS.add(state_title)
        states.append(
            State(state_id, state_title,
                xas(s, "note"),
                state_actions, permissions,
                parent_permissions,
                xab(s, "obsolete"),
            )
        )
    
    STATE_IDS = [ s.id for s in states ]
    
    # transitions
    for t in workflow.iterchildren("transition"):
        title = xas(t, "title")
        naming.MSGIDS.add(title)
        # sources, empty string -> initial_state
        sources = t.get("source").split() or [initial_state]
        assert len(sources) == len(set(sources)), \
            "Transition contains duplicate sources [%s]" % (sources)
        for source in sources:
            if source is not initial_state:
                assert source in STATE_IDS, \
                    "Unknown transition source state [%s]" % (source)
        # destination must be a valid state
        destination = t.get("destination")
        assert destination in STATE_IDS, \
            "Unknown transition destination state [%s]" % (destination)
        
        # optionals -- only set on kw IFF explicitly defined
        kw = {}
        for i in TRANS_ATTRS_OPTIONALS:
            val = xas(t, i)
            if not val:
                # we let setting of defaults be handled downstream
                continue
            kw[i] = val
        
        # data up-typing
        #
        # trigger
        if "trigger" in kw:
            kw["trigger"] = trigger_value_map[kw["trigger"]]
        # roles -> permission - one-to-one per transition
        roles = capi.schema.qualified_roles(kw.pop("roles", ""))
        if not is_zcml_permissionable(t):
            assert not roles, "Workflow [%s] - non-permissionable transition " \
                "does not allow @roles [%s]." % (workflow_name, roles) #!+RNC
            kw["permission"] = None # None -> CheckerPublic
        # !+CAN_EDIT_AS_DEFAULT_TRANSITION_PERMISSION(mr, oct-2011) this feature
        # is functional (uncomment following elif clause) but as yet not enabled. 
        #
        # Advantage would be that it would be easier to keep transitions 
        # permissions in sync with object permissions (set in state) as the 
        # majority of transition require exactly this as privilege; for the 
        # occassional transition needing a different privilege, the current 
        # transition.@roles mechanism may be used to make this explicit. 
        #
        # Need to consider implications further; the zope_principal_role_map db 
        # table, that caches contextual roles for principals, should probably 
        # first be reworked to be db-less (as for zope_role_permission_map).
        #
        #elif not roles:
        #    # then as fallback transition permission use can modify object
        #    kw["permission"] = "bungeni.%s.Edit" % (workflow_name) # fallback permission
        else:
            # Dedicated permission for XML multi-source transition.
            # Given that, irrespective of how sources are grouped into 
            # multi-source XML <transition> elements, there may be only *one* 
            # path from any given *source* to any given *destination* state, 
            # it suffices to use only the first source element + the destination 
            # to guarantee a unique identifier for an XML transition element.
            #
            # Note: the "-" char is not allowed within a permission id 
            # (so we use "." also here).
            #
            tid = "%s.%s" % (sources[0] or "", destination)
            pid = "bungeni.%s.wf.%s" % (workflow_name, tid)
            if not ZCML_PROCESSED:
                zcml_transition_permission(pid, title, roles)
                # remember list of roles from xml
                kw["_roles"] = roles
            kw["permission"] = pid
        # python resolvables
        if "condition" in kw:
            kw["condition"] = capi.get_workflow_condition(kw["condition"])
        # numeric
        if "order" in kw:
            kw["order"] = float(kw["order"]) # ValueError if not numeric
        # bool
        if "require_confirmation" in kw:
            try:
                kw["require_confirmation"] = misc.as_bool(kw["require_confirmation"])
                assert kw["require_confirmation"] is not None #!+RNC
            except:
                raise ValueError("Invalid transition value "
                    '[require_confirmation="%s"]' % (
                        t.get("require_confirmation")))
        # multiple-source transitions are really multiple "transition paths"
        for source in sources:
            args = (title, source, destination)
            transitions.append(Transition(*args, **kw))
            log.debug("[%s] adding transition [%s-%s] [%s]" % (
                workflow_name, source or "", destination, kw))
    
    return Workflow(workflow_name,
        workflow_features, workflow_facets, states, transitions, global_grants,
        workflow_title, workflow_description, note)
예제 #16
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.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. 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 catalyse (descriptor, model) pairs 
        # for which the domain type is mapped. Otherwise, ignore.
        domain_model = getattr(MODEL_MODULE, 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)
예제 #17
0
 def model_title(type_key):
     return naming.split_camel(naming.model_name(type_key))
예제 #18
0
def retrieve_domain_model(type_key):
    """Infer and retrieve the target domain model class from the type key.
    Raise Attribute error if not defined on domain.
    """
    return resolve("%s.%s" %
                   (MODEL_MODULE.__name__, naming.model_name(type_key)))
예제 #19
0
def register_new_custom_type(type_key, sys_archetype_key, custom_archetype_key,
                             workflow_key, descriptor_key, label,
                             container_label):
    """Retrieve (create if needed) a domain interface and model for type_key,
    and register as new entry on TYPE_REGISTER.
    """
    if custom_archetype_key is None:
        custom_archetype_key = sys_archetype_key
    archetype_model = resolve(
        "%s.%s" %
        (MODEL_MODULE.__name__, naming.model_name(custom_archetype_key)))
    # validate that custom archetype uses correct system archetype
    if custom_archetype_key != sys_archetype_key:
        sys_archetype_model = resolve(
            "%s.%s" %
            (MODEL_MODULE.__name__, naming.model_name(sys_archetype_key)))
        assert issubclass(archetype_model, sys_archetype_model), \
            "Custom archetype %r for type %r is not a sub-type of %r." % (
                custom_archetype_key, type_key, sys_archetype_key)

    # generate custom domain interface
    domain_iface_name = naming.model_interface_name(type_key)
    try:
        domain_iface = resolve("%s.%s" %
                               (INTERFACE_MODULE.__name__, domain_iface_name))
        log.warn("Custom interface ALREADY EXISTS: %s", domain_iface)
    except ImportError:
        domain_iface = new_custom_domain_interface(type_key, domain_iface_name,
                                                   archetype_model)

    # generate custom domain_model
    domain_model_name = naming.model_name(type_key)
    try:
        domain_model = resolve("%s.%s" %
                               (MODEL_MODULE.__name__, domain_model_name))
        log.warn("Custom domain model ALREADY EXISTS: %s", domain_model)
    except ImportError:
        domain_model = new_custom_domain_model(type_key, domain_iface,
                                               custom_archetype_key)

    if workflow_key is None:
        workflow_key = type_key
    if descriptor_key is None:
        descriptor_key = type_key

    # ILegislativeContent === sys_archetype_key=="doc"
    # Provide convenience marker to easily distinguish between
    # "system super archetype" and "system sub archetype", specifically
    # between Doc and Event, i.e. we want to mark all types implementing
    # IDoc but not IEvent (that also always implement IDoc).
    if sys_archetype_key == "doc":
        if not interfaces.ILegislativeContent.implementedBy(domain_model):
            classImplements(domain_model, interfaces.ILegislativeContent)

    # !+MENUITEM_TITLE check uniqueness constraint on type labels -- due to
    # zope.componenet registration issues on registering multiple menuitems on
    # same (interface, title) pairs, may be changed in future... possible
    # alternative is to infer a sub-interface to distinguish between "same" pairs
    if label is not None:
        for tk, ti in _iter():
            assert not label == ti.label, \
                "Label %r for custom type %r is not unique (see type %r)" % (
                    label, type_key, tk)

    # type_info entry
    ti = TI(type_key, workflow_key, domain_iface, domain_model,
            archetype_model)
    ti.descriptor_key = descriptor_key
    ti.label = label
    ti.container_label = container_label
    ti.custom = True
    ti.custom_archetype_key = custom_archetype_key
    ti.sys_archetype_key = sys_archetype_key
    TYPE_REGISTRY.append(ti)

    log.info("Registered custom type [%s]: %s", custom_archetype_key, type_key)
    return type_key, ti
예제 #20
0
def register_new_custom_type(type_key, sys_archetype_key, custom_archetype_key, 
        workflow_key, descriptor_key,
        label, container_label
    ):
    """Retrieve (create if needed) a domain interface and model for type_key,
    and register as new entry on TYPE_REGISTER.
    """
    if custom_archetype_key is None:
        custom_archetype_key = sys_archetype_key
    archetype_model = resolve("%s.%s" % (
            MODEL_MODULE.__name__, naming.model_name(custom_archetype_key)))
    # validate that custom archetype uses correct system archetype
    if custom_archetype_key != sys_archetype_key:
        sys_archetype_model = resolve("%s.%s" % (
                MODEL_MODULE.__name__, naming.model_name(sys_archetype_key)))
        assert issubclass(archetype_model, sys_archetype_model), \
            "Custom archetype %r for type %r is not a sub-type of %r." % (
                custom_archetype_key, type_key, sys_archetype_key)
    
    # generate custom domain interface
    domain_iface_name = naming.model_interface_name(type_key)
    try:
        domain_iface = resolve("%s.%s" % (INTERFACE_MODULE.__name__, domain_iface_name))
        log.warn("Custom interface ALREADY EXISTS: %s", domain_iface)
    except ImportError:
        domain_iface = new_custom_domain_interface(type_key, domain_iface_name, archetype_model)
    
    # generate custom domain_model
    domain_model_name = naming.model_name(type_key)
    try:
        domain_model = resolve("%s.%s" % (MODEL_MODULE.__name__, domain_model_name))
        log.warn("Custom domain model ALREADY EXISTS: %s", domain_model)
    except ImportError:
        domain_model = new_custom_domain_model(type_key, domain_iface, custom_archetype_key)
    
    if workflow_key is None:
        workflow_key = type_key
    if descriptor_key is None:
        descriptor_key = type_key    
    
    # ILegislativeContent === sys_archetype_key=="doc"
    # Provide convenience marker to easily distinguish between 
    # "system super archetype" and "system sub archetype", specifically 
    # between Doc and Event, i.e. we want to mark all types implementing
    # IDoc but not IEvent (that also always implement IDoc).
    if sys_archetype_key == "doc":
        if not interfaces.ILegislativeContent.implementedBy(domain_model):
            classImplements(domain_model, interfaces.ILegislativeContent)
    
    # !+MENUITEM_TITLE check uniqueness constraint on type labels -- due to 
    # zope.componenet registration issues on registering multiple menuitems on 
    # same (interface, title) pairs, may be changed in future... possible 
    # alternative is to infer a sub-interface to distinguish between "same" pairs
    if label is not None:
        for tk, ti in _iter():
            assert not label == ti.label, \
                "Label %r for custom type %r is not unique (see type %r)" % (
                    label, type_key, tk)
    
    # type_info entry
    ti = TI(type_key, workflow_key, domain_iface, domain_model, archetype_model)
    ti.descriptor_key = descriptor_key
    ti.label = label
    ti.container_label = container_label
    ti.custom = True
    ti.custom_archetype_key = custom_archetype_key
    ti.sys_archetype_key = sys_archetype_key
    TYPE_REGISTRY.append(ti)
    
    log.info("Registered custom type [%s]: %s", custom_archetype_key, type_key)
    return type_key, ti
예제 #21
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=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(  # !+CUSTOM
            container_getter(get_chamber_for_context, "committees"),
            title=_("section_scheduling_committees", default=u"Committees"),
            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(  # !+FEATURE
            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["publications"] = QueryContent(
            container_getter(get_chamber_for_context, "publications"),
            title=_("section_scheduling_publications",
                    default=u"Publications"),
            description=_(u"Publications"))
        # !+CALENDAR_DOC_TYPES finish off setup_customization_ui steps that need
        # application sections to be created...
        import bungeni.feature.ui
        for calendar_doc_type_key in bungeni.feature.ui.CALENDAR_DOC_TYPE_KEYS:
            calendar_doc_ti = capi.get_type_info(calendar_doc_type_key)
            container_property_name = naming.plural(calendar_doc_type_key)
            # add section containers to workspace/scheduling
            ws_sched[container_property_name] = QueryContent(
                container_getter(get_chamber_for_context,
                                 container_property_name),
                title=_("section_scheduling_${container_property_name}",
                        mapping={
                            "container_property_name": container_property_name
                        },
                        default=calendar_doc_ti.container_label),
                description=_(u"Manage ${container_label}",
                              mapping={
                                  "container_label":
                                  calendar_doc_ti.container_label
                              }))

        workspace["groups"] = WorkspaceSection(
            title=_("section_groups", default=u"My groups"),
            description=_(u"My 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 I am 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 IScheduleContent.implementedBy(ti.domain_model):
                container_property_name = naming.plural(type_key)
                container_name = naming.model_name(container_property_name)
                if not ws_sched.has_key(container_property_name):
                    ws_sched[container_property_name] = QueryContent(
                        container_getter(get_chamber_for_context,
                                         container_property_name),
                        title=container_name,
                        description=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=IBungeniAdmin)

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

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

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

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

        content = admin["content"] = Section(
            title=_(u"Content"),
            description=_(u"browse bungeni content"),
            marker=IBungeniAdmin,
            default_name="browse-admin")
        alsoProvides(content, interfaces.ISearchableSection)
        # !+CUSTOM form descriptor container on legislature
        content[u"legislatures"] = domain.LegislatureContainer()
        ''' !+LEGISLATURE requires that all chamber/government/joint_committee
        groups be created *under* the legislature in admin (or use demo data 
        dump from circa r11500 or newer).
        
        content[u"chambers"] = domain.ChamberContainer()
        to_locatable_container(domain.Chamber, content[u"chambers"])
        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"])
        # !+/CUSTOM

        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"])
예제 #22
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)
예제 #23
0
def retrieve_domain_model(type_key):
    """Infer and retrieve the target domain model class from the type key.
    Raise AttributeError if not defined on model module.
    !+ mv to catalyst.utils?
    """
    return resolve("%s.%s" % (MODEL_MODULE.__name__, naming.model_name(type_key)))
예제 #24
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}"
            />"""
    
    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 = naming.split_camel(naming.model_name(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")
        # 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")
        # 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)
            title = "Add {t} Event".format(t=type_title)
            register_menu_item("event", "Add", title, model_interface_qualname, 
                "./events/add", menu="additems", order=21,
                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)
예제 #25
0
def retrieve_domain_model(type_key):
    """Infer and retrieve the target domain model class from the type key.
    Raise Attribute error if not defined on domain.
    """
    return resolve("%s.%s" % (MODEL_MODULE.__name__, naming.model_name(type_key)))
예제 #26
0
def get_feature_interface(feature_name):
    return getattr(interfaces, "IFeature%s" % naming.model_name(feature_name))
예제 #27
0
def get_feature_interface(feature_name):
    return getattr(interfaces, "IFeature%s" % naming.model_name(feature_name))
예제 #28
0
 def display_name(cls):
     cls_name = naming.model_name(
         naming.type_key("descriptor_class_name", cls.__name__))
     return naming.split_camel(cls_name) # !+unicode
예제 #29
0
def get_vp_kls(extended_type):
    kls_name = naming.model_name(extended_type)
    return getattr(MODEL_MODULE.vp, kls_name)
예제 #30
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=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( # !+CUSTOM
            container_getter(get_chamber_for_context, "committees"),
            title=_("section_scheduling_committees", default=u"Committees"),
            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( # !+FEATURE
            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["publications"] = QueryContent(
            container_getter(get_chamber_for_context, "publications"),
            title=_("section_scheduling_publications", 
                default=u"Publications"),
            description=_(u"Publications"))
        # !+CALENDAR_DOC_TYPES finish off setup_customization_ui steps that need 
        # application sections to be created...
        import bungeni.feature.ui
        for calendar_doc_type_key in bungeni.feature.ui.CALENDAR_DOC_TYPE_KEYS:
            calendar_doc_ti = capi.get_type_info(calendar_doc_type_key)
            container_property_name = naming.plural(calendar_doc_type_key)
            # add section containers to workspace/scheduling
            ws_sched[container_property_name] = QueryContent(
                container_getter(get_chamber_for_context, container_property_name),
                title=_("section_scheduling_${container_property_name}", 
                    mapping={"container_property_name": container_property_name}, 
                    default=calendar_doc_ti.container_label),
                description=_(u"Manage ${container_label}",
                    mapping={"container_label": calendar_doc_ti.container_label}))
        
        workspace["groups"] = WorkspaceSection(
            title=_("section_groups", default=u"My groups"),
            description=_(u"My 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 I am 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 IScheduleContent.implementedBy(ti.domain_model):
                container_property_name = naming.plural(type_key)
                container_name = naming.model_name(container_property_name)
                if not ws_sched.has_key(container_property_name):
                    ws_sched[container_property_name] = QueryContent(
                        container_getter(get_chamber_for_context, container_property_name),
                        title=container_name,
                        description=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=IBungeniAdmin)
        
        admin["email-settings"] = Section(
            title=_(u"email settings"),
            description=_(u"manage email settings"),
            marker=IBungeniAdmin,
            default_name="email-settings")
        
        admin["search-settings"] = Section(
            title=_(u"search settings"),
            description=_(u"manage bungeni email settings"),
            marker=IBungeniAdmin,
            default_name="search-settings")
        
        admin["registry-settings"] = Section(
            title=_(u"registry settings"),
            description=_(u"manage registry settings"),
            marker=IBungeniAdmin,
            default_name="registry-settings")
        
        admin["serialization-manager"] = Section(
            title=_(u"serialization manager"),
            description=_(u"batch serialization of content"),
            marker=IBungeniAdmin,
            default_name="serialization-manager")
        
        content = admin["content"] = Section(
            title=_(u"Content"),
            description=_(u"browse bungeni content"),
            marker=IBungeniAdmin,
            default_name="browse-admin")
        alsoProvides(content, interfaces.ISearchableSection)
        # !+CUSTOM form descriptor container on legislature
        content[u"legislatures"] = domain.LegislatureContainer()
        ''' !+LEGISLATURE requires that all chamber/government/joint_committee
        groups be created *under* the legislature in admin (or use demo data 
        dump from circa r11500 or newer).
        
        content[u"chambers"] = domain.ChamberContainer()
        to_locatable_container(domain.Chamber, content[u"chambers"])
        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"])
        # !+/CUSTOM
        
        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"])
예제 #31
0
 def model_title(type_key):
     return naming.split_camel(naming.model_name(type_key))