def localize_domain_model_from_descriptor_class(domain_model, descriptor_cls): """Localize the domain model for configuration information in the descriptor i.e. any extended/derived attributes. For any model/descriptor this should be called only once! """ type_key = naming.polymorphic_identity(domain_model) # localize models from descriptors only once! assert type_key not in localize_domain_model_from_descriptor_class.DONE, \ "May not re-localize [%s] domain model from descriptor" % (type_key) localize_domain_model_from_descriptor_class.DONE.append(type_key) #!+GET_ARCHETYPE #!+archetype_key = naming.polymorphic_identity(domain_model.__bases__[0]) multiple inheritance... archetype_key = naming._type_key_from_descriptor_class_name( descriptor_cls.__bases__[0].__name__) for field in descriptor_cls.fields: # extended if field.extended is not None: add_extended_property_to_model(domain_model, field.name, field.extended, archetype_key) # derived if field.derived is not None: add_derived_property_to_model(domain_model, field.name, field.derived) # !+if domain_model.extended_properties: ? # !+instrument_extended_properties, archetype_key => table... instrument_extended_properties(domain_model, archetype_key) mapper_add_relation_vertical_properties(domain_model) # !+AUDIT_EXTENDED_ATTRIBUTES as audit class was created prior to # extended attributes being updated on domain type, need to push onto # it any extended attrs that were read from model's descriptor if interfaces.IFeatureAudit.implementedBy(domain_model): # either defined manually or created dynamically in feature_audit() audit_kls = getattr(MODEL_MODULE, "%sAudit" % (domain_model.__name__)) # propagate any extended attributes on head kls also to its audit_kls import bungeni.models.domain audit_table_name = bungeni.models.domain.get_audit_table_name(domain_model) instrument_extended_properties( audit_kls, audit_table_name, from_class=domain_model) # containers from bungeni.capi import capi for name, target_type_key, rel_attr in descriptor_cls.info_containers: try: tti = capi.get_type_info(target_type_key) except KeyError: # target type not enabled log.warn("Ignoring %r container property %r to disabled type: %s.%s", type_key, name, target_type_key, rel_attr) continue container_qualname = "bungeni.models.domain.%s" % ( naming.container_class_name(target_type_key)) add_container_property_to_model(domain_model, name, container_qualname, rel_attr)
def generate_container_class(ti): """Generate a zope3 container class for a domain model. """ type_key = naming.polymorphic_identity(ti.domain_model) container_name = naming.container_class_name(type_key) container_iname = naming.container_interface_name(type_key) base_interfaces = (IAlchemistContainer, ) # !+achetype.container_interface? # logging variables msg = (ti.domain_model.__name__, CONTAINER_MODULE.__name__, container_name) # container class - if we already have one, exit if getattr(CONTAINER_MODULE, container_name, None): log.info( "generate_container_class [model=%s] found container %s.%s, skipping", *msg) ti.container_class = getattr(CONTAINER_MODULE, container_name) return container_class = type( container_name, (AlchemistContainer, ), dict(_class=ti.domain_model, __module__=CONTAINER_MODULE.__name__)) # set on CONTAINER_MODULE, register on type_info setattr(CONTAINER_MODULE, container_name, container_class) ti.container_class = container_class log.info("generate_container_class [model=%s] generated container %s.%s", *msg) # container interface - if we already have one, skip creation # !+ should always be newly created? container_iface = getattr(INTERFACE_MODULE, container_iname, None) msg = (ti.domain_model.__name__, CONTAINER_MODULE.__name__, container_iname) if container_iface is not None: assert issubclass(container_iface, IAlchemistContainer) log.info( "generate_container_class [model=%s] skipping container interface %s.%s for", *msg) else: container_iface = interface.interface.InterfaceClass( container_iname, bases=base_interfaces, __module__=INTERFACE_MODULE.__name__) # set on INTERFACE_MODULE, register on type_info setattr(INTERFACE_MODULE, container_iname, container_iface) ti.container_interface = container_iface log.info( "generate_container_class [model=%s] generated container interface %s.%s", *msg) # setup security for n, d in container_iface.namesAndDescriptions(all=True): protectName(container_class, n, "zope.Public") # apply implementedBy if not container_iface.implementedBy(container_class): interface.classImplements(container_class, container_iface)
def localize_domain_model_from_descriptor_class(domain_model, descriptor_cls): """Localize the domain model for configuration information in the descriptor i.e. any extended/derived attributes. For any model/descriptor this should be called only once! """ type_key = naming.polymorphic_identity(domain_model) # localize models from descriptors only once! assert type_key not in localize_domain_model_from_descriptor_class.DONE, \ "May not re-localize [%s] domain model from descriptor" % (type_key) localize_domain_model_from_descriptor_class.DONE.append(type_key) log.info("localize_domain_model_from_descriptor_class: (%s, %s)", domain_model.__name__, descriptor_cls.__name__) # ensure cls has own dedicated "extended_properties" list property # i.e. a "extended_properties" key in own cls.__dict__, # and that it is initialized with current (possibly inherited) values domain_model.extended_properties = domain_model.extended_properties[:] for field in descriptor_cls.fields: # extended if field.extended is not None: add_extended_property_to_model(domain_model, field.name, field.extended) # derived if field.derived is not None: add_derived_property_to_model(domain_model, field.name, field.derived) # !+if domain_model.extended_properties: ? instrument_extended_properties(domain_model) mapper_add_relation_vertical_properties(domain_model) # !+AUDIT_EXTENDED_ATTRIBUTES as audit class was created prior to # extended attributes being updated on domain type, need to push onto # it any extended attrs that were read from model's descriptor if IFeatureAudit.implementedBy(domain_model): # either defined manually or created dynamically in feature_audit() audit_kls = getattr(MODEL_MODULE, "%sAudit" % (domain_model.__name__)) # ensure cls has own dedicated "extended_properties" list property audit_kls.extended_properties = domain_model.extended_properties[:] # propagate any extended attributes on head kls also to its audit_kls instrument_extended_properties(audit_kls) # containers for ic in descriptor_cls.info_containers: container_qualname = "bungeni.models.domain.%s" % ( naming.container_class_name(ic.target_type_key)) add_container_property_to_model(domain_model, ic.container_attr_name, container_qualname, ic.rel_attr_name, ic.indirect_key)
def generate_container_class(ti): """Generate a zope3 container class for a domain model. """ type_key = naming.polymorphic_identity(ti.domain_model) container_name = naming.container_class_name(type_key) container_iname = naming.container_interface_name(type_key) base_interfaces = (IAlchemistContainer,) # logging variables msg = (ti.domain_model.__name__, CONTAINER_MODULE.__name__, container_name) # container class - if we already have one, exit if getattr(CONTAINER_MODULE, container_name, None): log.info("generate_container_class [model=%s] found container %s.%s, skipping" % msg) ti.container_class = getattr(CONTAINER_MODULE, container_name) return container_class = type(container_name, (AlchemistContainer,), dict(_class=ti.domain_model, __module__=CONTAINER_MODULE.__name__) ) # set on CONTAINER_MODULE, register on type_info setattr(CONTAINER_MODULE, container_name, container_class) ti.container_class = container_class log.info("generate_container_class [model=%s] generated container %s.%s" % msg) # container interface - if we already have one, skip creation # !+ should always be newly created? container_iface = getattr(INTERFACE_MODULE, container_iname, None) msg = (ti.domain_model.__name__, CONTAINER_MODULE.__name__, container_iname) if container_iface is not None: assert issubclass(container_iface, IAlchemistContainer) log.info("generate_container_class [model=%s] skipping container interface %s.%s for" % msg) else: container_iface = interface.interface.InterfaceClass( container_iname, bases=base_interfaces, __module__=INTERFACE_MODULE.__name__ ) # set on INTERFACE_MODULE, register on type_info setattr(INTERFACE_MODULE, container_iname, container_iface) ti.container_interface = container_iface log.info("generate_container_class [model=%s] generated container interface %s.%s" % msg) # setup security for n, d in container_iface.namesAndDescriptions(all=True): protectName(container_class, n, "zope.Public") # apply implementedBy if not container_iface.implementedBy(container_class): interface.classImplements(container_class, container_iface)
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 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(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"])