--- a/src/pyams_portal/template.py Thu Oct 08 12:26:42 2015 +0200
+++ b/src/pyams_portal/template.py Mon Jan 18 18:09:46 2016 +0100
@@ -16,9 +16,9 @@
# import standard library
# import interfaces
-from pyams_portal.interfaces import IPortalTemplate, IPortalTemplateConfiguration, IPortalContext, IPortalPage, \
- IPortletConfiguration, IPortlet, IPortalTemplateContainer, IPortalWfTemplate, IPortalTemplateContainerConfiguration
-from pyams_workflow.interfaces import IWorkflowVersions
+from pyams_portal.interfaces import IPortalTemplateContainer, IPortalTemplateContainerConfiguration, \
+ IPortalTemplate, IPortalTemplateConfiguration, IPortalPortletsConfiguration, IPortlet, IPortletConfiguration, \
+ PORTLETS_CONFIGURATION_KEY, TEMPLATE_CONTAINER_CONFIGURATION_KEY, TEMPLATE_CONFIGURATION_KEY
from zope.annotation.interfaces import IAnnotations
from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectRemovedEvent
from zope.traversing.interfaces import ITraversable
@@ -27,9 +27,10 @@
from persistent import Persistent
from persistent.list import PersistentList
from persistent.mapping import PersistentMapping
+from pyams_portal.portlet import PortalPortletsConfiguration
from pyams_portal.slot import SlotConfiguration
from pyams_utils.adapter import adapter_config, ContextAdapter
-from pyams_utils.registry import get_local_registry
+from pyams_utils.registry import get_local_registry, get_utility
from pyams_utils.request import check_request
from pyramid.events import subscriber
from pyramid.threadlocal import get_current_registry
@@ -39,79 +40,85 @@
from zope.copy import clone
from zope.interface import implementer
from zope.lifecycleevent import ObjectCreatedEvent
-from zope.location.location import locate
+from zope.location import locate
from zope.schema.fieldproperty import FieldProperty
from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm, getVocabularyRegistry
+#
+# Portal templates container
+#
+
@implementer(IPortalTemplateContainer)
class PortalTemplateContainer(Folder):
- """Portal template container"""
+ """Portal templates container"""
+
+ last_portlet_id = FieldProperty(IPortalTemplateContainer['last_portlet_id'])
+
+ def get_portlet_id(self):
+ self.last_portlet_id += 1
+ return self.last_portlet_id
@implementer(IPortalTemplateContainerConfiguration)
class PortalTemplateContainerConfiguration(Persistent, Contained):
"""Portal template container configuration"""
- selected_portlets = FieldProperty(IPortalTemplateContainerConfiguration['selected_portlets'])
-
-
-PORTAL_TEMPLATE_CONTAINER_CONFIGURATION_KEY = 'pyams_portal.container.configuration'
+ toolbar_portlets = FieldProperty(IPortalTemplateContainerConfiguration['toolbar_portlets'])
@adapter_config(context=IPortalTemplateContainer, provides=IPortalTemplateContainerConfiguration)
-def PortalTemplateContainerConfigurationFactory(context):
+def PortalTemplateContainerConfigurationAdapter(context):
"""Portal template container configuration factory"""
annotations = IAnnotations(context)
- config = annotations.get(PORTAL_TEMPLATE_CONTAINER_CONFIGURATION_KEY)
+ config = annotations.get(TEMPLATE_CONTAINER_CONFIGURATION_KEY)
if config is None:
- config = annotations[PORTAL_TEMPLATE_CONTAINER_CONFIGURATION_KEY] = PortalTemplateContainerConfiguration()
+ config = annotations[TEMPLATE_CONTAINER_CONFIGURATION_KEY] = PortalTemplateContainerConfiguration()
get_current_registry().notify(ObjectCreatedEvent(config))
locate(config, context)
return config
+#
+# Portal template base class
+#
+
@implementer(IPortalTemplate)
class PortalTemplate(Persistent, Contained):
- """Portal template persistent class"""
+ """Portal template class"""
name = FieldProperty(IPortalTemplate['name'])
-@implementer(IPortalWfTemplate)
-class PortalWfTemplate(Persistent, Contained):
- """Portal template workflow manager class"""
-
- content_class = PortalTemplate
- workflow_name = 'PyAMS portal template workflow'
- view_permission = None
-
-
-@subscriber(IObjectAddedEvent, context_selector=IPortalWfTemplate)
+@subscriber(IObjectAddedEvent, context_selector=IPortalTemplate)
def handle_added_template(event):
"""Register shared template"""
registry = get_local_registry()
if (registry is not None) and IPortalTemplateContainer.providedBy(event.newParent):
- registry.registerUtility(event.object, IPortalWfTemplate, name=event.object.__name__)
+ registry.registerUtility(event.object, IPortalTemplate, name=event.object.name)
-@subscriber(IObjectRemovedEvent, context_selector=IPortalWfTemplate)
+@subscriber(IObjectRemovedEvent, context_selector=IPortalTemplate)
def handle_removed_template(event):
"""Unregister removed template"""
registry = get_local_registry()
if (registry is not None) and IPortalTemplateContainer.providedBy(event.oldParent):
- registry.unregisterUtility(event.object, IPortalWfTemplate, name=event.object.__name__)
+ registry.unregisterUtility(event.object, IPortalTemplate, name=event.object.name)
class PortalTemplatesVocabulary(UtilityVocabulary):
"""Portal templates vocabulary"""
- interface = IPortalWfTemplate
+ interface = IPortalTemplate
nameOnly = True
getVocabularyRegistry().register('PyAMS portal templates', PortalTemplatesVocabulary)
+#
+# Portal template configuration
+#
+
@implementer(IPortalTemplateConfiguration)
class PortalTemplateConfiguration(Persistent, Contained):
"""Portal template configuration"""
@@ -119,25 +126,21 @@
rows = FieldProperty(IPortalTemplateConfiguration['rows'])
_slot_names = FieldProperty(IPortalTemplateConfiguration['slot_names'])
_slot_order = FieldProperty(IPortalTemplateConfiguration['slot_order'])
- _slots = FieldProperty(IPortalTemplateConfiguration['slots'])
- slot_config = FieldProperty(IPortalTemplateConfiguration['slot_config'])
- portlet_config = FieldProperty(IPortalTemplateConfiguration['portlet_config'])
+ _slot_config = FieldProperty(IPortalTemplateConfiguration['slot_config'])
def __init__(self):
self._slot_names = PersistentList()
self._slot_order = PersistentMapping()
self._slot_order[0] = PersistentList()
- self._slots = PersistentMapping()
- self._slots[0] = PersistentMapping()
self.slot_config = PersistentMapping()
- self.portlet_config = PersistentMapping()
+
+ # rows management
def add_row(self):
"""Add new row and return last row index (0 based)"""
self.rows += 1
last_index = self.rows - 1
self.slot_order[last_index] = PersistentList()
- self.slots[last_index] = PersistentMapping()
return last_index
def set_row_order(self, order):
@@ -145,35 +148,31 @@
if not isinstance(order, (list, tuple)):
order = list(order)
old_slot_order = self.slot_order
- old_slots = self.slots
assert len(order) == self.rows
new_slot_order = PersistentMapping()
- new_slots = PersistentMapping()
for index, row_id in enumerate(order):
new_slot_order[index] = old_slot_order.get(row_id) or PersistentList()
- new_slots[index] = old_slots.get(row_id) or PersistentMapping()
if self.slot_order != new_slot_order:
self.slot_order = new_slot_order
- self.slots = new_slots
def delete_row(self, row_id):
"""Delete template row"""
- assert row_id in self.slots
- for slot_name in self.slots.get(row_id, {}).keys():
+ assert row_id in self.slot_order
+ for slot_name in self.slot_order.get(row_id, ()):
+ config = IPortalPortletsConfiguration(self.__parent__)
+ config.delete_portlet_configuration(self.slot_config[slot_name].portlet_ids)
if slot_name in self.slot_names:
self.slot_names.remove(slot_name)
if slot_name in self.slot_config:
del self.slot_config[slot_name]
- if slot_name in self.portlet_config:
- del self.portlet_config[slot_name]
for index in range(row_id, self.rows-1):
self.slot_order[index] = self.slot_order[index+1]
- self.slots[index] = self.slots[index+1]
if self.rows > 0:
del self.slot_order[self.rows-1]
- del self.slots[self.rows-1]
self.rows -= 1
+ # slots management
+
@property
def slot_names(self):
if IPortalTemplate.providedBy(self.__parent__):
@@ -197,15 +196,15 @@
self._slot_order = value
@property
- def slots(self):
+ def slot_config(self):
if IPortalTemplate.providedBy(self.__parent__):
- return self._slots
+ return self._slot_config
else:
- return IPortalTemplateConfiguration(self.__parent__).slots
+ return IPortalTemplateConfiguration(self.__parent__).slot_config
- @slots.setter
- def slots(self, value):
- self._slots = value
+ @slot_config.setter
+ def slot_config(self, value):
+ self._slot_config = value
def add_slot(self, slot_name, row_id=None):
assert slot_name not in self.slot_names
@@ -216,10 +215,6 @@
if row_id not in self.slot_order:
self.slot_order[row_id] = PersistentList()
self.slot_order[row_id].append(slot_name)
- # init slots portlets
- if row_id not in self.slots:
- self.slots[row_id] = PersistentMapping()
- self.slots[row_id][slot_name] = PersistentList()
# init slots configuration
slot = self.slot_config[slot_name] = SlotConfiguration(slot_name)
locate(slot, self.__parent__)
@@ -228,18 +223,11 @@
def set_slot_order(self, order):
"""Set slots order"""
old_slot_order = self.slot_order
- old_slots = self.slots
new_slot_order = PersistentMapping()
- new_slots = PersistentMapping()
for row_id in sorted(map(int, order.keys())):
new_slot_order[row_id] = PersistentList(order[row_id])
- new_slots[row_id] = PersistentMapping()
- for slot_name in order[row_id]:
- old_row_id = self.get_slot_row(slot_name)
- new_slots[row_id][slot_name] = old_slots[old_row_id][slot_name]
if new_slot_order != old_slot_order:
self.slot_order = new_slot_order
- self.slots = new_slots
def get_slot_row(self, slot_name):
for row_id in self.slot_order:
@@ -280,102 +268,58 @@
"""Delete slot and associated portlets"""
assert slot_name in self.slot_names
row_id = self.get_slot_row(slot_name)
- del self.portlet_config[slot_name]
+ # delete portlet configuration
+ config = IPortalPortletsConfiguration(self.__parent__)
+ config.delete_portlet_configuration(self.slot_config[slot_name].portlet_ids)
+ # delete slot configuration
del self.slot_config[slot_name]
- del self.slots[row_id][slot_name]
self.slot_order[row_id].remove(slot_name)
self.slot_names.remove(slot_name)
+ # portlets management
+
def add_portlet(self, portlet_name, slot_name):
"""Add portlet to given slot"""
assert slot_name in self.slot_names
- row_id = self.get_slot_row(slot_name)
- if slot_name not in self.slots.get(row_id):
- self.slots[row_id][slot_name] = PersistentList()
- self.slots[row_id][slot_name].append(portlet_name)
- if slot_name not in self.portlet_config:
- self.portlet_config[slot_name] = PersistentMapping()
- position = len(self.slots[row_id][slot_name]) - 1
+ # get new portlet configuration
portlet = get_current_registry().getUtility(IPortlet, name=portlet_name)
config = IPortletConfiguration(portlet)
- config.slot_name = slot_name
- config.position = position
- locate(config, self.__parent__, '++portlet++{0}::{1}'.format(slot_name, position))
- self.portlet_config[slot_name][position] = config
+ # store portlet configuration
+ manager = get_utility(IPortalTemplateContainer)
+ IPortalPortletsConfiguration(self.__parent__).set_portlet_configuration(manager.get_portlet_id(), config)
+ # update slots configuration
+ self.slot_config[slot_name].portlet_ids.append(config.portlet_id)
return {'portlet_name': portlet_name,
+ 'portlet_id': config.portlet_id,
'slot_name': slot_name,
- 'position': position,
+ 'position': len(self.slot_config[slot_name].portlet_ids) - 1,
'label': check_request().localizer.translate(portlet.label)}
+ def get_portlet_slot(self, portlet_id):
+ """Get portlet slot"""
+ for slot_name, config in self.slot_config.items():
+ if portlet_id in config.portlet_ids:
+ return self.get_slot_row(slot_name), slot_name
+ return None, None
+
def set_portlet_order(self, order):
"""Set portlet order"""
- source = order['from']
- source_slot = source['slot']
- source_row = self.get_slot_row(source_slot)
- target = order['to']
- target_slot = target['slot']
+ from_row, from_slot = self.get_portlet_slot(order['from'])
+ if from_slot is None:
+ return
+ target_slot = order['to']['slot']
target_row = self.get_slot_row(target_slot)
- portlet_config = self.portlet_config
- old_config = portlet_config[source_slot].pop(source['position'])
- target_config = PersistentMapping()
- for index, (slot_name, portlet_name, position) in enumerate(zip(target['slots'], target['names'],
- target['positions'])):
- if (slot_name == source_slot) and (position == source['position']):
- target_config[index] = old_config
- else:
- target_config[index] = portlet_config[slot_name][position]
- target_config[index].slot_name = target_slot
- target_config[index].position = index
- locate(target_config[index], self.__parent__, '++portlet++{0}::{1}'.format(slot_name, index))
- portlet_config[target_slot] = target_config
- # re-order source portlets
- config = portlet_config[source_slot]
- for index, key in enumerate(sorted(config)):
- if index != key:
- config[index] = config.pop(key)
- config[index].position = index
- locate(config[index], self.__parent__, '++portlet++{0}::{1}'.format(source_slot, index))
- # re-order target portlets
- if target_slot != source_slot:
- config = portlet_config[target_slot]
- for index, key in enumerate(sorted(config)):
- config[index] = config.pop(key)
- config[index].position = index
- locate(config[index], self.__parent__, '++portlet++{0}::{1}'.format(target_slot, index))
- self.portlet_config = portlet_config
- del self.slots[source_row][source_slot][source['position']]
- self.slots[target_row][target_slot] = PersistentList(target['names'])
+ if target_row is None:
+ return
+ self.slot_config[from_slot].portlet_ids.remove(order['from'])
+ self.slot_config[target_slot].portlet_ids = PersistentList(order['to']['portlet_ids'])
- def get_portlet_configuration(self, slot_name, position):
- """Get portlet configuration"""
- if slot_name not in self.slot_names:
- return None
- config = self.portlet_config.get(slot_name, {}).get(position)
- if config is None:
- if IPortalTemplate.providedBy(self.__parent__):
- portlet_name = self.slots[slot_name][position]
- portlet = get_current_registry().queryUtility(IPortlet, name=portlet_name)
- config = IPortletConfiguration(portlet)
- else:
- config = clone(IPortalTemplateConfiguration(self.__parent__).get_portlet_configuration(slot_name,
- position))
- config.inherit_parent = True
- self.portlet_config[slot_name][position] = config
- locate(config, self.__parent__)
- return config
-
- def delete_portlet(self, slot_name, position):
+ def delete_portlet(self, portlet_id):
"""Delete portlet"""
- assert slot_name in self.slot_names
- row_id = self.get_slot_row(slot_name)
- config = self.portlet_config[slot_name]
- del config[position]
- if len(config) and (position < max(tuple(config.keys()))):
- for index, key in enumerate(sorted(config)):
- config[index] = config.pop(key)
- config[index].position = index
- locate(config[index], self.__parent__, '++portlet++{0}::{1}'.format(slot_name, index))
- del self.slots[row_id][slot_name][position]
+ row_id, slot_name = self.get_portlet_slot(portlet_id)
+ if slot_name is not None:
+ self.slot_config[slot_name].portlet_ids.remove(portlet_id)
+ IPortalPortletsConfiguration(self.__parent__).delete_portlet_configuration(portlet_id)
class PortalTemplateSlotsVocabulary(SimpleVocabulary):
@@ -389,25 +333,9 @@
getVocabularyRegistry().register('PyAMS template slots', PortalTemplateSlotsVocabulary)
-@adapter_config(name='portlet', context=IPortalTemplate, provides=ITraversable)
-class PortalTemplatePortletTraverser(ContextAdapter):
- """++portlet++ namespace traverser"""
-
- def traverse(self, name, furtherpath=None):
- config = IPortalTemplateConfiguration(self.context)
- if name:
- slot_name, position = name.split('::')
- return config.get_portlet_configuration(slot_name, int(position))
- else:
- return config
-
-
-TEMPLATE_CONFIGURATION_KEY = 'pyams_portal.template'
-
-
@adapter_config(context=IPortalTemplate, provides=IPortalTemplateConfiguration)
def PortalTemplateConfigurationFactory(context):
- """Portal template configuration factory"""
+ """Portal template configuration adapter"""
annotations = IAnnotations(context)
config = annotations.get(TEMPLATE_CONFIGURATION_KEY)
if config is None:
@@ -417,25 +345,29 @@
return config
-@adapter_config(context=IPortalContext, provides=IPortalTemplateConfiguration)
-def PortalContextConfigurationFactory(context):
- """Portal context configuration factory"""
- page = IPortalPage(context)
- if page.use_local_template:
- template = IWorkflowVersions(page.template).get_last_versions()[0]
- config = IPortalTemplateConfiguration(template)
- else:
- annotations = IAnnotations(context)
- config = annotations.get(TEMPLATE_CONFIGURATION_KEY)
- if config is None:
- # we clone template configuration
- config = annotations[TEMPLATE_CONFIGURATION_KEY] = clone(IPortalTemplateConfiguration(page.template))
- get_current_registry().notify(ObjectCreatedEvent(config))
- locate(config, context)
- return config
+@adapter_config(name='portlet', context=IPortalTemplate, provides=ITraversable)
+class PortalTemplatePortletTraverser(ContextAdapter):
+ """++portlet++ template traverser"""
+
+ def traverse(self, name, furtherpath=None):
+ config = IPortalPortletsConfiguration(self.context)
+ if name:
+ return config.get_portlet_configuration(int(name))
+ else:
+ return config
-@adapter_config(context=IPortletConfiguration, provides=IPortalTemplateConfiguration)
-def PortalPortletConfigurationFactory(context):
- """Portal portlet configuration factory"""
- return IPortalTemplateConfiguration(context.__parent__)
+#
+# Template portlets configuration
+#
+
+@adapter_config(context=IPortalTemplate, provides=IPortalPortletsConfiguration)
+def PortalTemplatePortletsConfigurationAdapter(template):
+ """Portal template portlets configuration adapter"""
+ annotations = IAnnotations(template)
+ config = annotations.get(PORTLETS_CONFIGURATION_KEY)
+ if config is None:
+ config = annotations[PORTLETS_CONFIGURATION_KEY] = PortalPortletsConfiguration()
+ get_current_registry().notify(ObjectCreatedEvent(config))
+ locate(config, template)
+ return config