def group_items(self): """Prepare and remember item aggregations, for convenient access from within templates. Grouping aggregations are keyed on the *pluralized* name of: a) the item's type key b) (if different to type key) its custom archetype key c) (if different to custom archetype key) its system archetype key. Example, an item of type "assembly_question" (that has custom archetype "question", and system archetype "doc") will be included in the following aggregation list attributes on this instance: a) es.assembly_questions b) es.questions c) es.docs """ for scheduled in self.sitting.item_schedule: type_key = scheduled.item.type ti = capi.get_type_info(type_key) grouping_type_keys = [type_key] for tk in (ti.custom_archetype_key, ti.sys_archetype_key): if tk is not None and tk not in grouping_type_keys: grouping_type_keys.append(tk) for tk in grouping_type_keys: grouping_name = naming.plural(tk) log.debug( "[Reports] Adding %s to grouping %r in expanded sitting %s", scheduled, grouping_name, self) self.grouped.setdefault(grouping_name, []).append(scheduled.item)
def __str__(self): doc = removeSecurityProxy(self.context) base_url = ui_utils.url.absoluteURL(getSite(), self.request) return "%s/admin/content/chambers/obj-%s/%s/%s" % ( base_url, doc.chamber_id, naming.plural(naming.polymorphic_identity( type(doc))), stringKey(doc))
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
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])
def __str__(self): doc = removeSecurityProxy(self.context) base_url = ui_utils.url.absoluteURL(getSite(), self.request) return "%s/admin/content/chambers/obj-%s/%s/%s" % ( base_url, doc.chamber_id, naming.plural(naming.polymorphic_identity(type(doc))), stringKey(doc))
def parse_container(container_elem): target_type_key, rel_attr_name = xas(container_elem, "match").split(".", 1) return ( xas(container_elem, "name") or naming.plural(target_type_key), target_type_key, rel_attr_name, xas(container_elem, "indirect_key") )
def __str__(self): member = removeSecurityProxy(self.context) base_url = ui_utils.url.absoluteURL(getSite(), self.request) return "%s/%s/%s/%s" % ( base_url, super(GroupMemberAdminAbsoluteURLView, self)._group_url_path(member.group), naming.plural(naming.polymorphic_identity(type(member))), stringKey(member))
def __str__(self): member = removeSecurityProxy(self.context) base_url = ui_utils.url.absoluteURL(getSite(), self.request) return "%s/%s/%s/%s" % ( base_url, super(GroupMemberAdminAbsoluteURLView, self)._group_url_path(member.group), naming.plural(naming.polymorphic_identity( type(member))), stringKey(member))
def decorate_ui(self, model): # container property per enabled event type for event_type_key in self.get_param("types"): if capi.has_type_info(event_type_key): container_property_name = naming.plural(event_type_key) add_info_container_to_descriptor(model, container_property_name, event_type_key, "head_id") else: log.warn("IGNORING feature %r ref to disabled type %r", self.name, event_type_key)
def _group_url_path(self, group): url_comps = [] group = removeSecurityProxy(group) while group: url_comps.insert(0, "%s/%s" % ( naming.plural(naming.polymorphic_identity(type(group))), stringKey(group))) group = removeSecurityProxy(group.parent_group) return "/".join(url_comps)
def _group_url_path(self, group): url_comps = [] group = removeSecurityProxy(group) while group: url_comps.insert( 0, "%s/%s" % (naming.plural(naming.polymorphic_identity( type(group))), stringKey(group))) group = removeSecurityProxy(group.parent_group) return "/".join(url_comps)
def decorate_ui(self, model): add_info_container_to_descriptor(model, "sittings", "sitting", "group_id") add_info_container_to_descriptor(model, "headings", "heading", "group_id") add_info_container_to_descriptor(model, "editorial_notes", "editorial_note", "group_id") # add_info_container_to_descriptor(model, "agenda_items", "agenda_item", "group_id") # container property per enabled calendar_doc_type for calendar_doc_type_key in self.get_param("calendar_doc_types"): if capi.has_type_info(calendar_doc_type_key): container_property_name = naming.plural(calendar_doc_type_key) add_info_container_to_descriptor(model, container_property_name, calendar_doc_type_key, "group_id") else: log.warn("IGNORING feature %r ref to disabled type %r", self.name, calendar_doc_type_key)
def child(context, type_key): """Get the child document of the specified type. !+ assumes only one; if more than one, glazes over the issue and just takes the "latest", approximately; if None returns None. """ container_property_name = naming.plural(type_key) container = getattr(context, container_property_name) try: return sorted(container.values())[-1] except IndexError: return None
def decorate_ui(self, model): add_info_container_to_descriptor(model, "sittings", "sitting", "group_id") add_info_container_to_descriptor(model, "headings", "heading", "group_id") add_info_container_to_descriptor(model, "editorial_notes", "editorial_note", "group_id") #add_info_container_to_descriptor(model, "agenda_items", "agenda_item", "group_id") # container property per enabled calendar_doc_type for calendar_doc_type_key in self.get_param("calendar_doc_types"): if capi.has_type_info(calendar_doc_type_key): container_property_name = naming.plural(calendar_doc_type_key) add_info_container_to_descriptor(model, container_property_name, calendar_doc_type_key, "group_id") else: log.warn("IGNORING feature %r ref to disabled type %r", self.name, calendar_doc_type_key)
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])
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 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 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])
def feature_event(kls, feature): """Decorator for domain types to support "event" feature. For Doc types (other than Event itself). """ # !+ feature "descriptor/processing/validation", move elsewhere? # parameter "types": # - may "allow" multiple event types # - if none specified, "event" is assumed as the default. feature.params["types"] = feature.params.get("types", "event").split() # domain.Event itself may NOT support events assert not interfaces.IEvent.implementedBy(kls) interface.classImplements(kls, interfaces.IFeatureEvent) # container property per enabled event type for event_type_key in feature.params["types"]: if capi.has_type_info(event_type_key): container_property_name = naming.plural(event_type_key) container_class_name = naming.container_class_name(event_type_key) add_container_property_to_model(kls, container_property_name, "bungeni.models.domain.%s" % (container_class_name), "head_id") else: log.warn('IGNORING feature "event" ref to disabled type %r', event_type_key)
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
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] )
def container_name(cls): return naming.plural(cls.display_name) # !+unicode
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)
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"])
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 model_title(type_key): # return naming.split_camel(naming.model_name(type_key)) # clear accumulation of generated zcml code -- but retain the same GLOBAL # list variable instance UI_ZC_DECLS[:] = [] # setup bungeni_custom resource UI_ZC_DECLS.append(""" <browser:resourceDirectory name="reporting-static" directory="%s/reporting/static" />""" % (capi.get_root_path())) # 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 = ti.label or ti.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") # api add register_form_view(type_key, "Add", "add", container_interface_qualname, "bungeni.ui.api.APIAddForm", "bungeni.ui.interfaces.IBungeniAPILayer") # view register_form_view(type_key, "View", "index", model_interface_qualname, "bungeni.ui.forms.common.DisplayForm") # api view register_form_view(type_key, "View", "index", model_interface_qualname, "bungeni.ui.api.APIObjectView", "bungeni.ui.interfaces.IBungeniAPILayer") # 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.domain_model, domain.Group): # groups 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") register_form_view(type_key, "Edit", "edit", model_interface_qualname, "bungeni.ui.api.APIEditForm", "bungeni.ui.interfaces.IBungeniAPILayer") # 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 register_menu_item(type_key, "Add", "Add %s..." % (type_title), container_interface_qualname, "./add", menu="plone_contentmenu", layer="bungeni.ui.interfaces.IAdminSectionLayer") # group if issubclass(ti.domain_model, domain.Group): if ti.workflow.has_feature("sitting"): # !+CHAMBER_SITTING clarify/regularize for chamber (e.g. can # already add an agenda item via workspace menus, etc). # add sitting register_menu_item("sitting", "Add", "Add sitting...", model_interface_qualname, "./sittings/add", menu="additems", order=40, layer="bungeni.ui.interfaces.IWorkspaceOrAdminSectionLayer") # add calendar "createable" add doc menu items sitting_feature = ti.workflow.get_feature("sitting") for calendar_doc_type_key in sitting_feature.get_param("calendar_doc_types"): CALENDAR_DOC_TYPE_KEYS.add(calendar_doc_type_key) calendar_doc_ti = capi.get_type_info(calendar_doc_type_key) container_property_name = naming.plural(calendar_doc_type_key) register_menu_item(calendar_doc_type_key, "Add", "Add %s..." % (calendar_doc_ti.label), #!+MENUITEM_TITLE model_interface_qualname, "./%s/add" % (container_property_name), menu="additems", order=41, layer="bungeni.ui.interfaces.IWorkspaceOrAdminSectionLayer") # group CalendarView register_form_view(type_key, "View", "schedule", model_interface_qualname, "bungeni.ui.calendar.browser.CalendarView") # member if issubclass(ti.domain_model, domain.GroupMember): group_ti = capi.get_type_info(ti.within_type_key) group_model_interface_qualname = naming.qualname(group_ti.interface) # add register_menu_item(type_key, "Add", "Add %s..." % (type_title), group_model_interface_qualname, "./%s/add" % (naming.plural(type_key)), menu="additems", order=61, layer="bungeni.ui.interfaces.IWorkspaceOrAdminSectionLayer") # group, member if issubclass(ti.domain_model, (domain.Group, domain.GroupMember)): # edit register_menu_item(type_key, "Edit", "Edit %s..." % (type_title), model_interface_qualname, "edit", menu="context_actions", order=10, layer="bungeni.ui.interfaces.IWorkspaceOrAdminSectionLayer") # delete register_menu_item(type_key, "Delete", "Delete %s..." % (type_title), model_interface_qualname, "delete", menu="context_actions", order=99, layer="bungeni.ui.interfaces.IWorkspaceOrAdminSectionLayer") # create/register custom container viewlets # !+descriptor/restore.py ti.descriptor_model is None when running this utility if ti.descriptor_model: for i, ic in enumerate(ti.descriptor_model.info_containers): if ic.viewlet: sfv_cls = new_container_sub_form_viewlet_cls(type_key, ic, i) register_container_viewlet( type_key, ic.viewlet_name, model_interface_qualname) # workspace if ti.workflow.has_feature("workspace"): log.debug("Setting up UI for feature %r for type %r", "workspace", type_key) # add menu item # !+AUTO_UI_ZCML_MENU_ITEMS: workspace_add_parliamentary_content # !+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_verb = "add_{k}".format(k=type_key) action = "../../{first_tab}/{action_verb}".format( first_tab=first_tab, action_verb=action_verb) # !+MENUITEM_TITLE_r11350(mr, jun-2014) am switching the title of these # two menuItems to use the type_key instead of the ti label, as it seems # ZCML does not allow to have a same @title value for multiple menuItem # declarations for the same menu + target interface (even if @action, # @permission are different). # bungeni.models.interfaces.IGroup, bungeni.core.interfaces.IWorkspaceContainer register_menu_item(type_key, "Add", type_title, # !+MENUITEM_TITLE "bungeni.models.interfaces.ISUBMENU_workspace_add_parliamentary_content", action, menu="workspace_add_parliamentary_content", filter_="python: context.is_type_workspaced(%r)" % (type_key), order=7) ''' !+MENUITEM_TITLE_r11350(mr, jun-2014) -- disabling to monitor if needed; re-enable or delete... # add menu item -> for admin ?! # !+AUTO_UI_ZCML_MENU_ITEMS: context_add_parliamentary_content # !+ why a duplicated (almost identical) menu item for admin? # !+ criteria here is having workspace enabled... but, criterion # 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, "bungeni.models.interfaces.IGroup", action, menu="context_add_parliamentary_content", filter_="python: context.is_type_workspaced(%r)" % (type_key), 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") # api add register_form_view(type_key, "Add", name, "bungeni.core.interfaces.IWorkspaceTab", "bungeni.ui.api.APIWorkspaceAddForm", "bungeni.ui.interfaces.IBungeniAPILayer") # workspace add titles to strings for i18n for ws_tab in capi.workspace_tabs: naming.MSGIDS.add(("section_workspace_%s" % ws_tab, ws_tab)) # events if ti.workflow.has_feature("event"): log.debug("Setting up UI for feature %r for type %r", "event", type_key) event_feature = ti.workflow.get_feature("event") for event_type_key in event_feature.get_param("types"): if capi.has_type_info(event_type_key): container_property_name = naming.plural(event_type_key) event_type_ti = capi.get_type_info(event_type_key) # add menu item title = "{t} {e}".format( t=type_title, e=(event_type_ti.label or event_type_ti.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 %r ref to disabled type %r", "event", event_type_key) # register other non-workspace menu items for custom types (only once) # custom events !+GET_ARCHETYPE !+ARCHETYPE_INSTANTIATABLE 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) # once-only processing for calendar_doc_type_key in CALENDAR_DOC_TYPE_KEYS: # !+CALENDAR_DOC_TYPES calendar_doc_ti = capi.get_type_info(calendar_doc_type_key) container_property_name = naming.plural(calendar_doc_type_key) # !+SchedulingContext why do they need to be different? # plenary scheduling register_menu_item(calendar_doc_type_key, "Add", "Add %s..." % (calendar_doc_ti.label), #!+MENUITEM_TITLE "bungeni.core.schedule.WorkspaceSchedulingContext", "./%s/add" % (container_property_name), menu="plone_contentmenu", #order=41, layer="bungeni.ui.interfaces.IWorkspaceSectionLayer") # group (committee) scheduling register_menu_item(calendar_doc_type_key, "Add", "Add %s..." % (calendar_doc_ti.label), #!+MENUITEM_TITLE "bungeni.core.schedule.GroupSchedulingContext", "./../%s/add" % (container_property_name), menu="plone_contentmenu", #order=41, layer="bungeni.ui.interfaces.IWorkspaceOrAdminSectionLayer")
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"])
def localize_descriptor(type_key, descriptor_elem, scope="system"): """Localize descriptor from descriptor XML element. Return the created/modified descriptor class. """ ti = capi.get_type_info(type_key) # !+ ensure domain_model has already been set assert ti.domain_model, type_key order = xai(descriptor_elem, "order") fields = new_descriptor_fields(descriptor_elem) info_containers = [] for c_elem in descriptor_elem.findall("container"): # !+ @view_title:i18n_key, @view_id:token, @weight:int ? target_type_key, rel_attr_name = xas(c_elem, "match").split(".", 1) container_attr_name = xas(c_elem, "name") or naming.plural(target_type_key) indirect_key = xas(c_elem, "indirect_key") viewlet = xab(c_elem, "viewlet", False) add_info_container(type_key, info_containers, container_attr_name, target_type_key, rel_attr_name, indirect_key, viewlet=viewlet, _origin="container") integrity = descriptor_elem.find("integrity") if integrity is not None: constraints = [ capi.get_form_constraint(c) for c in xas(integrity, "constraints", "").split() ] validations = [ capi.get_form_validator(v) for v in xas(integrity, "validations", "").split() ] else: constraints, validations = (), () if scope=="custom": try: cls = update_descriptor_cls(type_key, order, fields, info_containers, constraints, validations) except AttributeError: # first time around, no such descriptor - so create a new custom descriptor archetype_key = naming.polymorphic_identity(ti.archetype) cls = new_descriptor_cls(type_key, archetype_key, order, fields, info_containers, constraints, validations) if xas(descriptor_elem, "sort_on"): cls.sort_on = xas(descriptor_elem, "sort_on").split() # !+ assert each name is a field in the descriptor if xas(descriptor_elem, "sort_dir"): # default cls.sort_dir: "desc" cls.sort_dir = xas(descriptor_elem, "sort_dir") update_new_descriptor_cls_from_ti(ti) else: # non-custom cls = update_descriptor_cls(type_key, order, fields, info_containers, constraints, validations) # finish model/descriptor setup from feature configuration if ti.workflow: for feature in ti.workflow.features: feature.setup_ui(ti.domain_model) # custom container order - re-sort info_containers such that "container" # ones precede all "feature" ones, plus make the list immutable i.e. no # further changes allowed. ics = ti.descriptor_model.info_containers ti.descriptor_model.info_containers = tuple(sorted(ics, # False sorts before True (as 0 sorts before 1) key=lambda ic: ic._origin == "feature" )) log.debug("Localized descriptor [%s] %s", type_key, ti) return cls
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)