src/pyams_content/component/links/__init__.py
changeset 1351 045be80a5645
parent 1258 49da29eef086
--- a/src/pyams_content/component/links/__init__.py	Wed Sep 25 09:47:48 2019 +0200
+++ b/src/pyams_content/component/links/__init__.py	Wed Sep 25 09:50:05 2019 +0200
@@ -10,20 +10,20 @@
 # FOR A PARTICULAR PURPOSE.
 #
 
-__docformat__ = 'restructuredtext'
-
 from html import escape
 
-from pyramid.encode import url_quote
-from zope.interface import implementer
+from pyramid.encode import url_quote, urlencode
+from pyramid.events import subscriber
+from zope.interface import alsoProvides, implementer, directlyProvidedBy, noLongerProvides
+from zope.lifecycleevent import IObjectAddedEvent, IObjectModifiedEvent
 from zope.schema.fieldproperty import FieldProperty
 from zope.schema.vocabulary import SimpleTerm, SimpleVocabulary
 
-from pyams_content import _
 from pyams_content.component.association import AssociationItem
-from pyams_content.component.association.interfaces import IAssociationContainer, IAssociationContainerTarget, \
-    IAssociationInfo
-from pyams_content.component.links.interfaces import IBaseLink, IExternalLink, IInternalLink, IMailtoLink
+from pyams_content.component.association.interfaces import IAssociationContainer, \
+    IAssociationContainerTarget, IAssociationInfo
+from pyams_content.component.links.interfaces import IBaseLink, IExternalLink, IInternalLink, \
+    IInternalLinkCustomInfoTarget, IMailtoLink, IInternalLinkCustomInfo, ICustomInternalLinkTarget
 from pyams_content.features.checker import BaseContentChecker
 from pyams_content.features.checker.interfaces import ERROR_VALUE, IContentChecker
 from pyams_content.interfaces import IBaseContent
@@ -42,6 +42,11 @@
 from pyams_workflow.interfaces import IWorkflow, IWorkflowPublicationInfo
 
 
+__docformat__ = 'restructuredtext'
+
+from pyams_content import _
+
+
 #
 # Links vocabulary
 #
@@ -55,7 +60,8 @@
         target = get_parent(context, IAssociationContainerTarget)
         if target is not None:
             terms = [SimpleTerm(link.__name__, title=IAssociationInfo(link).inner_title)
-                     for link in IAssociationContainer(target).values() if IBaseLink.providedBy(link)]
+                     for link in IAssociationContainer(target).values() if
+                     IBaseLink.providedBy(link)]
         super(ContentLinksVocabulary, self).__init__(terms)
 
 
@@ -106,7 +112,7 @@
         request = check_request()
         translate = request.localizer.translate
         return II18n(self.context).query_attribute('title', request) or \
-            '({0})'.format(translate(self.context.icon_hint).lower())
+               '({0})'.format(translate(self.context.icon_hint).lower())
 
 
 #
@@ -157,14 +163,48 @@
         if target is not None:
             if request is None:
                 request = check_request()
+            params = None
+            if IInternalLinkCustomInfoTarget.providedBy(target):
+                custom_info = IInternalLinkCustomInfo(self, None)
+                if custom_info is not None:
+                    params = custom_info.get_url_params()
+                    if params:
+                        params = urlencode(params)
             if self.force_canonical_url:
-                return canonical_url(target, request, view_name)
+                return canonical_url(target, request, view_name, query=params)
             else:
-                return relative_url(target, request, view_name=view_name)
+                return relative_url(target, request, view_name=view_name, query=params)
         else:
             return ''
 
 
+@subscriber(IObjectAddedEvent, context_selector=IInternalLink)
+def handle_new_internal_link(event):
+    """Check if link target is providing custom info"""
+    link = event.object
+    target = link.target
+    if target is not None:
+        info = IInternalLinkCustomInfoTarget(target, None)
+        if info is not None:
+            alsoProvides(link, info.internal_link_marker_interface)
+
+
+@subscriber(IObjectModifiedEvent, context_selector=IInternalLink)
+def handle_updated_internal_link(event):
+    """Check when modified if new link target is providing custom info"""
+    link = event.object
+    # remove previous provided interfaces
+    ifaces = tuple([iface for iface in directlyProvidedBy(link)
+                    if issubclass(iface, IInternalLinkCustomInfo)])
+    for iface in ifaces:
+        noLongerProvides(link, iface)
+    target = link.target
+    if target is not None:
+        info = IInternalLinkCustomInfoTarget(target, None)
+        if info is not None:
+            alsoProvides(link, info.internal_link_marker_interface)
+
+
 @adapter_config(context=IInternalLink, provides=IAssociationInfo)
 class InternalLinkAssociationInfoAdapter(BaseLinkInfoAdapter):
     """Internal link association info adapter"""
@@ -206,8 +246,10 @@
             if workflow is not None:
                 target = self.context.get_target(state=workflow.published_states)
                 if target is None:
-                    output.append(translate(ERROR_VALUE).format(field=IInternalLink['reference'].title,
-                                                                message=translate(_("target is not published"))))
+                    output.append(
+                        translate(ERROR_VALUE).format(field=IInternalLink['reference'].title,
+                                                      message=translate(
+                                                          _("target is not published"))))
         return output