src/pyams_portal/zmi/layout.py
changeset 147 7fb2efbf0b63
parent 140 95bee9c0ae3f
child 175 f91042366ca4
--- a/src/pyams_portal/zmi/layout.py	Tue Jul 03 15:19:50 2018 +0200
+++ b/src/pyams_portal/zmi/layout.py	Tue Jul 03 15:51:19 2018 +0200
@@ -9,6 +9,8 @@
 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
 # FOR A PARTICULAR PURPOSE.
 #
+from pyams_utils.unicode import translate_string
+from pyams_utils.url import absolute_url
 
 __docformat__ = 'restructuredtext'
 
@@ -23,7 +25,7 @@
     IPortalTemplateContainerConfiguration, IPortalPortletsConfiguration, IPortalContext, IPortalPage, \
     MANAGE_TEMPLATE_PERMISSION
 from pyams_skin.interfaces import IInnerPage, IPageHeader
-from pyams_skin.interfaces.viewlet import IToolbarAddingMenu, IMenuHeader
+from pyams_skin.interfaces.viewlet import IToolbarAddingMenu, IMenuHeader, IContextActions
 from pyams_skin.layer import IPyAMSLayer
 from pyams_zmi.interfaces.menu import IPropertiesMenu, IContentManagementMenu
 from pyams_zmi.layer import IAdminLayer
@@ -33,6 +35,7 @@
 # import packages
 from pyams_cache.beaker import get_cache
 from pyams_form.form import AJAXAddForm, AJAXEditForm, ajax_config
+from pyams_form.schema import CloseButton
 from pyams_pagelet.pagelet import pagelet_config
 from pyams_portal.portlet import PORTLETS_CACHE_REGION, PORTLETS_CACHE_NAME
 from pyams_portal.zmi.template import PortalTemplateHeaderAdapter
@@ -40,7 +43,7 @@
 from pyams_skin.viewlet.toolbar import JsToolbarMenuItem, ToolbarMenuDivider, ToolbarMenuItem
 from pyams_template.template import template_config
 from pyams_utils.adapter import adapter_config
-from pyams_utils.registry import query_utility
+from pyams_utils.registry import query_utility, get_utility
 from pyams_utils.traversing import get_parent
 from pyams_viewlet.manager import viewletmanager_config
 from pyams_viewlet.viewlet import viewlet_config
@@ -50,7 +53,8 @@
 from pyramid.events import subscriber
 from pyramid.exceptions import NotFound
 from pyramid.view import view_config
-from z3c.form import field
+from z3c.form import field, button
+from zope.copy import copy
 from zope.interface import implementer, Invalid, Interface
 
 from pyams_portal import _
@@ -547,3 +551,94 @@
     config = IPortalTemplateConfiguration(request.context)
     config.delete_portlet(int(request.params.get('portlet_id')))
     return {'status': 'success'}
+
+
+#
+# Portal template duplication form
+#
+
+@viewlet_config(name='duplication.divider', context=IPortalTemplate, layer=IPyAMSLayer,
+                view=PortalTemplateLayoutView, manager=IContextActions, permission=MANAGE_TEMPLATE_PERMISSION, weight=99)
+class PortalTemplateDuplicationMenuDivider(ToolbarMenuDivider):
+    """Portal template duplication menu divider"""
+
+    def __new__(cls, context, request, view, manager):
+        container = get_parent(context, IPortalTemplateContainer)
+        if container is None:
+            return None
+        return ToolbarMenuDivider.__new__(cls)
+
+
+@viewlet_config(name='duplication.menu', context=IPortalTemplate, layer=IPyAMSLayer,
+                view=PortalTemplateLayoutView, manager=IContextActions, permission=MANAGE_TEMPLATE_PERMISSION, weight=100)
+class PortalTemplateDuplicationMenu(ToolbarMenuItem):
+    """Portal template duplication menu item"""
+
+    def __new__(cls, context, request, view, manager):
+        container = get_parent(context, IPortalTemplateContainer)
+        if container is None:
+            return None
+        return ToolbarMenuDivider.__new__(cls)
+
+    label = _("Duplicate template...")
+    label_css_class = 'fa fa-fw fa-files-o'
+
+    url = 'duplicate.html'
+    modal_target = True
+
+
+class IPortalTemplateDuplicationButtons(Interface):
+    """Portal template duplication form buttons"""
+
+    close = CloseButton(name='close', title=_("Cancel"))
+    duplicate = button.Button(name='duplicate', title=_("Duplicate this template"))
+
+
+@pagelet_config(name='duplicate.html', context=IPortalTemplate, layer=IPyAMSLayer,
+                permission=MANAGE_TEMPLATE_PERMISSION)
+@ajax_config(name='duplicate.json', context=IPortalTemplate, layer=IPyAMSLayer, base=AJAXAddForm)
+class PortalTemplateDuplicationForm(AdminDialogAddForm):
+    """Portal template duplicate form"""
+
+    legend = _("Duplicate template")
+    icon_css_class = 'fa fa-fw fa-files-o'
+
+    fields = field.Fields(IPortalTemplate)
+    buttons = button.Buttons(IPortalTemplateDuplicationButtons)
+
+    edit_permission = MANAGE_TEMPLATE_PERMISSION
+
+    def updateWidgets(self, prefix=None):
+        super(PortalTemplateDuplicationForm, self).updateWidgets(prefix)
+        if 'name' in self.widgets:
+            self.widgets['name'].label = _("New template name")
+
+    def updateActions(self):
+        super(PortalTemplateDuplicationForm, self).updateActions()
+        if 'duplicate' in self.actions:
+            self.actions['duplicate'].addClass('btn-primary')
+
+    def create(self, data):
+        return copy(self.context)
+
+    def add(self, template):
+        container = get_utility(IPortalTemplateContainer)
+        container[translate_string(template.name, spaces='-')] = template
+
+    def nextURL(self):
+        return absolute_url(self.request.root, self.request, 'admin#portal-templates.html')
+
+    def get_ajax_output(self, changes):
+        return {
+            'status': 'redirect',
+            'location': self.nextURL()
+        }
+
+
+@subscriber(IDataExtractedEvent, form_selector=PortalTemplateDuplicationForm)
+def handle_new_template_data_extraction(event):
+    """Handle new template form data extraction"""
+    container = get_utility(IPortalTemplateContainer)
+    name = translate_string(event.data.get('name'), spaces='-')
+    if name in container:
+        event.form.widgets.errors += (Invalid(_("Specified name is already used!")),)