diff --git a/docs/HISTORY.txt b/docs/HISTORY.txt index ede4576f..494036ca 100644 --- a/docs/HISTORY.txt +++ b/docs/HISTORY.txt @@ -4,7 +4,15 @@ Changelog 5.0.0b4 (unreleased) -------------------- -- Nothing changed yet. +- Set "other" as default link protocol, to lessen the chances that + https://resolveuid/xxxxx are setup with plonefinder. + [gotcha] + +- Unregister ck_ruid_to_url as plone.outputfilters come with the same feature. + [gotcha] + +- Include CKeditor resources only when user is logged in. + [gotcha] 5.0.0b3 (2023-11-13) diff --git a/src/collective/ckeditor/browser/ckeditorsettings.py b/src/collective/ckeditor/browser/ckeditorsettings.py index 7610fd4f..84bd8fea 100644 --- a/src/collective/ckeditor/browser/ckeditorsettings.py +++ b/src/collective/ckeditor/browser/ckeditorsettings.py @@ -191,7 +191,7 @@ class ICKEditorBrowserSchema(Interface): title=_(u"Allow link objects by UID"), description=_(u"Check if you want url with Unique ID " "(no more 404 errors when moving objects). " - "Notice that portal_transforms in standard " + "Notice that plone.outputfilters in standard " "configuration transforms uid links in absolute urls " "in view displays."), default=True, diff --git a/src/collective/ckeditor/browser/ckeditorview.py b/src/collective/ckeditor/browser/ckeditorview.py index 276595ba..ebdea6be 100644 --- a/src/collective/ckeditor/browser/ckeditorview.py +++ b/src/collective/ckeditor/browser/ckeditorview.py @@ -354,6 +354,7 @@ def cke_params(self): params['filebrowserFlashBrowseUrl'] = flash_url # the basehref must be set in wysiwyg template # params['baseHref'] = self.cke_basehref + params['linkDefaultProtocol'] = "''" params.update(self.cke_toolbars()) return params diff --git a/src/collective/ckeditor/config.py b/src/collective/ckeditor/config.py index f5f7c80d..164c82c5 100644 --- a/src/collective/ckeditor/config.py +++ b/src/collective/ckeditor/config.py @@ -51,11 +51,6 @@ 'Link', 'Unlink','-','About'] ]""" -# quintagroup.com (from qPloneResolveUID product) -DOCUMENT_DEFAULT_OUTPUT_TYPE = "text/x-html-safe" -REQUIRED_TRANSFORM = "ck_ruid_to_url" - -# taken from collective/ckeditor/_src/ckeditor/_source/plugins/scayt/plugin.js # XXX warning order language correctly because if several values for the same # main language, the first defined language will be used as fallback when # trying to find SCAYT language to use when enableScaytOnStartup is True diff --git a/src/collective/ckeditor/profiles/default/metadata.xml b/src/collective/ckeditor/profiles/default/metadata.xml index 8c98cf62..72e482a8 100644 --- a/src/collective/ckeditor/profiles/default/metadata.xml +++ b/src/collective/ckeditor/profiles/default/metadata.xml @@ -1,6 +1,6 @@ - 5000 + 5010 profile-collective.plonefinder:default profile-collective.quickupload:default diff --git a/src/collective/ckeditor/profiles/default/registry.xml b/src/collective/ckeditor/profiles/default/registry.xml index 17769d37..a2114c8b 100644 --- a/src/collective/ckeditor/profiles/default/registry.xml +++ b/src/collective/ckeditor/profiles/default/registry.xml @@ -168,6 +168,7 @@ False ckeditor_vars.js 2021-10-15 12:30:00 + python: member is not None collective.ckeditor.ckeditor_vars @@ -175,6 +176,7 @@ False ++resource++ckeditor/ckeditor.js 2021-10-15 12:30:00 + python: member is not None collective.ckeditor.ckeditor_js @@ -182,5 +184,6 @@ False ++resource++ckeditor_for_plone/ckeditor_plone.js 2021-10-15 12:30:00 + python: member is not None diff --git a/src/collective/ckeditor/profiles/to5010/registry.xml b/src/collective/ckeditor/profiles/to5010/registry.xml new file mode 100644 index 00000000..8d1e078d --- /dev/null +++ b/src/collective/ckeditor/profiles/to5010/registry.xml @@ -0,0 +1,12 @@ + + + + python: member is not None + + + python: member is not None + + + python: member is not None + + diff --git a/src/collective/ckeditor/setuphandlers.py b/src/collective/ckeditor/setuphandlers.py index 94c41566..0cf4115b 100644 --- a/src/collective/ckeditor/setuphandlers.py +++ b/src/collective/ckeditor/setuphandlers.py @@ -1,6 +1,4 @@ from collective.ckeditor import LOG -from collective.ckeditor.config import DOCUMENT_DEFAULT_OUTPUT_TYPE, \ - REQUIRED_TRANSFORM from Products.CMFPlone.utils import getToolByName from Products.CMFPlone.interfaces import INonInstallable from plone.registry.interfaces import IRegistry @@ -15,10 +13,6 @@ def importFinalSteps(context): if context.readDataFile('collective.ckeditor.txt') is None: return site = context.getSite() - registerTransform(site, 'ck_ruid_to_url', - 'collective.ckeditor.transforms.ck_ruid_to_url') - registerTransformPolicy(site, DOCUMENT_DEFAULT_OUTPUT_TYPE, - REQUIRED_TRANSFORM) LOG.info('CKEditor for Plone installed') @@ -29,40 +23,9 @@ def uninstallSteps(context): uninstallControlPanel(site) uninstallFromRegistry(site) uninstallMemberProperties(site) - unregisterTransform(site, 'ck_ruid_to_url') - unregisterTransformPolicy(site, DOCUMENT_DEFAULT_OUTPUT_TYPE, - REQUIRED_TRANSFORM) LOG.info('CKEditor for Plone uninstalled') -def registerTransform(context, name, module): - transforms = getToolByName(context, 'portal_transforms') - if name not in transforms.objectIds(): - transforms.manage_addTransform(name, module) - LOG.info("Registered transform '%s'" % name) - else: - LOG.info("Transform '%s' always registered" % name) - - -def registerTransformPolicy(context, output_mimetype, required_transform): - transforms = getToolByName(context, 'portal_transforms') - tpolicies = transforms.listPolicies() - mimetype_registered = False - for p in tpolicies: - out_type = p[0] - if out_type == output_mimetype: - policies = list(p[1]) - if required_transform not in policies: - policies.append(required_transform) - transforms.manage_delPolicies([output_mimetype]) - transforms.manage_addPolicy(output_mimetype, policies) - mimetype_registered = True - break - if not mimetype_registered: - transforms.manage_addPolicy(output_mimetype, [required_transform]) - LOG.info("Registered policy for '%s' mimetype" % output_mimetype) - - def uninstallControlPanel(context): """ Uninstall CKeditor control panel @@ -164,4 +127,5 @@ def getNonInstallableProfiles(self): "collective.ckeditor:uninstall", "collective.ckeditor:to4350", "collective.ckeditor:to4330", + "collective.ckeditor:to5010", ] diff --git a/src/collective/ckeditor/tests/installation.txt b/src/collective/ckeditor/tests/installation.txt index e2256c1b..a4492e75 100644 --- a/src/collective/ckeditor/tests/installation.txt +++ b/src/collective/ckeditor/tests/installation.txt @@ -55,28 +55,3 @@ Control resource bundles in registry >>> ckbundles = [name for name in bundles if name.startswith("collective.ckeditor")] >>> len(ckbundles) == 3 True - -Control portal_transforms installation --------------------------------------- - - >>> transforms = getToolByName(portal, 'portal_transforms') - >>> output_mimetype = 'text/x-html-safe' - >>> cke_transform = 'ck_ruid_to_url' - -Control if cke_transform is here - - >>> cke_transform in transforms.objectIds() - True - -Control if ckeditor policies are registered - >>> tpolicies = transforms.listPolicies() - >>> mimetype_registered = False - >>> for p in tpolicies : - ... out_type = p[0] - ... if out_type == output_mimetype : - ... policies = p[1] - ... if cke_transform in policies : - ... mimetype_registered = True - ... break - >>> mimetype_registered - True diff --git a/src/collective/ckeditor/tests/test_doctests.py b/src/collective/ckeditor/tests/test_doctests.py index b388f395..877a15ad 100644 --- a/src/collective/ckeditor/tests/test_doctests.py +++ b/src/collective/ckeditor/tests/test_doctests.py @@ -16,7 +16,6 @@ 'ckeditor_jsconfig.txt', 'uninstall.txt', 'widget.txt', - 'transform_uids.txt', ] diff --git a/src/collective/ckeditor/tests/test_transform.py b/src/collective/ckeditor/tests/test_transform.py deleted file mode 100644 index 1ad86c80..00000000 --- a/src/collective/ckeditor/tests/test_transform.py +++ /dev/null @@ -1,207 +0,0 @@ -import unittest - - -class TestReplaceUids(unittest.TestCase): - - def testFindTagImg(self): - from collective.ckeditor.transforms import ck_ruid_to_url - # single quotes - text = "'" - tags, unique = ck_ruid_to_url.find_tags_with_resolveuid(text) - self.assertEquals(len(tags), 1) - self.assertEquals(tags[0], ("", - 'abcdef', 'resolveuid/abcdef')) - self.assertEquals(len(unique), 1) - self.assertEquals(unique, set(["abcdef"])) - # double quotes - text = '' - tags, unique = ck_ruid_to_url.find_tags_with_resolveuid(text) - self.assertEquals(len(tags), 1) - self.assertEquals(tags[0], ('', - 'abcdef', 'resolveuid/abcdef')) - self.assertEquals(len(unique), 1) - self.assertEquals(unique, set(["abcdef"])) - - def testFindTagA(self): - from collective.ckeditor.transforms import ck_ruid_to_url - # single quotes - text = "Link" - tags, unique = ck_ruid_to_url.find_tags_with_resolveuid(text) - self.assertEquals(len(tags), 1) - self.assertEquals(tags[0], ("", - 'abcdef', 'resolveuid/abcdef')) - self.assertEquals(len(unique), 1) - self.assertEquals(unique, set(["abcdef"])) - # double quotes - text = 'Link' - tags, unique = ck_ruid_to_url.find_tags_with_resolveuid(text) - self.assertEquals(len(tags), 1) - self.assertEquals(tags[0], ('', - 'abcdef', 'resolveuid/abcdef')) - self.assertEquals(len(unique), 1) - self.assertEquals(unique, set(["abcdef"])) - - def testFindTagEmbed(self): - from collective.ckeditor.transforms import ck_ruid_to_url - # single quotes - text = "" - tags, unique = ck_ruid_to_url.find_tags_with_resolveuid(text) - self.assertEquals(len(tags), 1) - self.assertEquals(tags[0], ("", - 'abcdef', 'resolveuid/abcdef')) - self.assertEquals(len(unique), 1) - self.assertEquals(unique, set(["abcdef"])) - # double quotes - text = '' - tags, unique = ck_ruid_to_url.find_tags_with_resolveuid(text) - self.assertEquals(len(tags), 1) - self.assertEquals(tags[0], ('', - 'abcdef', 'resolveuid/abcdef')) - self.assertEquals(len(unique), 1) - self.assertEquals(unique, set(["abcdef"])) - - def testFindTagWithStyle(self): - from collective.ckeditor.transforms import ck_ruid_to_url - # single quotes - text = ( - "
" - "content
" - ) - tags, unique = ck_ruid_to_url.find_tags_with_resolveuid(text) - self.assertEquals(len(tags), 1) - self.assertEquals( - tags[0], - ("
", - 'abcdef', 'resolveuid/abcdef') - ) - self.assertEquals(len(unique), 1) - self.assertEquals(unique, set(["abcdef"])) - # double quotes - text = ( - '
' - "content
" - ) - tags, unique = ck_ruid_to_url.find_tags_with_resolveuid(text) - self.assertEquals(len(tags), 1) - self.assertEquals( - tags[0], - ('
', - 'abcdef', 'resolveuid/abcdef') - ) - self.assertEquals(len(unique), 1) - self.assertEquals(unique, set(["abcdef"])) - - def testFindTagWithMoreStyle(self): - from collective.ckeditor.transforms import ck_ruid_to_url - # single quotes - text = ( - "
" - "content
" - ) - tags, unique = ck_ruid_to_url.find_tags_with_resolveuid(text) - self.assertEquals(len(tags), 1) - self.assertEquals( - tags[0], - ("
", - 'abcdef', 'resolveuid/abcdef') - ) - self.assertEquals(len(unique), 1) - self.assertEquals(unique, set(["abcdef"])) - # double quotes - text = ( - '
' - "content
" - ) - tags, unique = ck_ruid_to_url.find_tags_with_resolveuid(text) - self.assertEquals(len(tags), 1) - self.assertEquals( - tags[0], - ('
', - 'abcdef', 'resolveuid/abcdef') - ) - self.assertEquals(len(unique), 1) - self.assertEquals(unique, set(["abcdef"])) - - def testFindTagWithEvenMoreStyle(self): - from collective.ckeditor.transforms import ck_ruid_to_url - # single quotes - text = ( - "
" - "content
" - ) - tags, unique = ck_ruid_to_url.find_tags_with_resolveuid(text) - self.assertEquals(len(tags), 1) - self.assertEquals( - tags[0], - ("
", - 'abcdef', 'resolveuid/abcdef') - ) - self.assertEquals(len(unique), 1) - self.assertEquals(unique, set(["abcdef"])) - # double quotes - text = ( - '
' - "content
" - ) - tags, unique = ck_ruid_to_url.find_tags_with_resolveuid(text) - self.assertEquals(len(tags), 1) - self.assertEquals( - tags[0], - ('
', - 'abcdef', 'resolveuid/abcdef') - ) - self.assertEquals(len(unique), 1) - self.assertEquals(unique, set(["abcdef"])) - - def testMakeUid(self): - from collective.ckeditor.transforms import ck_ruid_to_url - unique = set(['abcdef']) - - def mocked(uid): - return '/Plone/ABCDEF' - - uid_to_absolute_url = ck_ruid_to_url.make_uid_to_absolute_url( - unique, compute_url=mocked) - self.assertEquals(uid_to_absolute_url, dict(abcdef='/Plone/ABCDEF')) - - def testReplaceResolveUid(self): - from collective.ckeditor.transforms import ck_ruid_to_url - - def mocked(uid): - return '/Plone/ABCDEF' - - original = "Link" - final = ck_ruid_to_url.replace_resolveuid_urls_with_absolute_urls( - original, compute_url=mocked) - self.assertEquals(final, "Link") - - original = "" - final = ck_ruid_to_url.replace_resolveuid_urls_with_absolute_urls( - original, compute_url=mocked) - self.assertEquals(final, "") - - original = ( - "
" - "content
" - ) - final = ck_ruid_to_url.replace_resolveuid_urls_with_absolute_urls( - original, compute_url=mocked) - self.assertEquals( - final, - "
content
") diff --git a/src/collective/ckeditor/tests/transform_uids.txt b/src/collective/ckeditor/tests/transform_uids.txt deleted file mode 100644 index bd873367..00000000 --- a/src/collective/ckeditor/tests/transform_uids.txt +++ /dev/null @@ -1,64 +0,0 @@ -Transforms url uids -------------------- - -each urls like './resolveuid/abcdef' or 'http://localhost/plone/resolveUID/' -or 'http://localhost/plone/resolveuid/download' -must be transformed on page view by absolute url of each objects resolved uid. - -Log in as manager - - >>> from plone.testing.z2 import Browser - >>> from plone.app.testing import SITE_OWNER_NAME - >>> from plone.app.testing import SITE_OWNER_PASSWORD - >>> app = layer['app'] - >>> portal = layer['portal'] - >>> browser = Browser(app) - >>> browser.open('http://nohost/plone/login_form') - >>> browser.getControl('Login Name').value = SITE_OWNER_NAME - >>> browser.getControl('Password').value = SITE_OWNER_PASSWORD - >>> browser.getControl('Log in').click() - -Create a document used to be linked ------------------------------------ - - >>> from Products.CMFPlone import utils as ploneutils - >>> doc = ploneutils._createObjectByType('Document', portal, 'abcd') - >>> import transaction - >>> transaction.commit() - -Get its uid - - >>> uid = portal['abcd'].UID() - -Create a document with resolveuid urls --------------------------------------- - - >>> portal_url = portal.absolute_url() - >>> browser.open('%s/++add++Document' %portal_url) - >>> browser.getControl(name='form.widgets.IDublinCore.title').value = 'Test Doc' - >>> html_text = ''' - ...

Test

- ...

Test

- ... ''' % (uid, uid) - >>> browser.getControl(name='form.widgets.IRichTextBehavior.text').value = html_text - >>> browser.getControl('Save').click() - >>> 'Item created' in browser.contents - True - - -Browse document ---------------- - - >>> browser.open('http://nohost/plone/folder_contents') - >>> 'plone/abcd' in browser.contents - True - >>> 'plone/test-doc' in browser.contents - True - - >>> browser.open('http://nohost/plone/test-doc/view') - >>> 'resolveuid' in browser.contents - False - >>> '' in browser.contents - True - >>> '' in browser.contents - True diff --git a/src/collective/ckeditor/tests/uninstall.txt b/src/collective/ckeditor/tests/uninstall.txt index 515f7ef3..4b62f3fc 100644 --- a/src/collective/ckeditor/tests/uninstall.txt +++ b/src/collective/ckeditor/tests/uninstall.txt @@ -55,29 +55,3 @@ Control resource bundles in registry >>> bundles = registry.collectionOfInterface(IBundleRegistry, prefix="plone.bundles") >>> [name for name in bundles if name.startswith("collective.ckeditor")] [] - -Control portal_transforms uninstalls ------------------------------------- - - >>> from Products.CMFCore.utils import getToolByName - >>> transforms = getToolByName(portal, 'portal_transforms') - >>> output_mimetype = 'text/x-html-safe' - >>> cke_transform = 'ck_ruid_to_url' - -Control if cke_transform is removed - - >>> cke_transform in transforms.objectIds() - False - -Control if ckeditor policies are removed - >>> tpolicies = transforms.listPolicies() - >>> mimetype_registered = False - >>> for p in tpolicies : - ... out_type = p[0] - ... if out_type == output_mimetype : - ... policies = p[1] - ... if cke_transform in policies : - ... mimetype_registered = True - ... break - >>> mimetype_registered - False diff --git a/src/collective/ckeditor/transforms/ck_ruid_to_url.py b/src/collective/ckeditor/transforms/ck_ruid_to_url.py index b520f7c3..1f50b923 100644 --- a/src/collective/ckeditor/transforms/ck_ruid_to_url.py +++ b/src/collective/ckeditor/transforms/ck_ruid_to_url.py @@ -1,6 +1,3 @@ -# Author: Melnychuk Taras -# Copyright: quintagroup.com - from zope.interface import implementer import re try: @@ -8,75 +5,12 @@ except ImportError: from Products.PortalTransforms.z3.interfaces import ITransform -from plone.app.uuid.utils import uuidToURL - - -def replace_resolveuid_urls_with_absolute_urls(text, compute_url=uuidToURL): - tags_with_resolveuid, unique_uids = find_tags_with_resolveuid(text) - if unique_uids: - uid_to_absolute_url = make_uid_to_absolute_url(unique_uids, compute_url) - for tag, uid, url in tags_with_resolveuid: - if uid in uid_to_absolute_url: - new_url = uid_to_absolute_url[uid] - new_tag = tag.replace(url, new_url) - text = text.replace(tag, new_tag) - return text - - -TAG_WITH_URL_RE = r'(\<(img|a|embed)[^>]*>)' -TAG_WITH_URL = re.compile(TAG_WITH_URL_RE, re.I | re.S) - -TAG_WITH_STYLE_RE = r'(\<[^>]*style=[^>]*url\([^>]*>)' -TAG_WITH_STYLE = re.compile(TAG_WITH_STYLE_RE, re.I | re.S) - -RUID_URL = 'resolveuid' - -RUID_URL_BETWEEN_QUOTES_RE = ( - r'(?P[^\"\']*%s/(?P[^\/\"\'#? ]*))' % RUID_URL - ) -RUID_URL_BETWEEN_QUOTES = re.compile(RUID_URL_BETWEEN_QUOTES_RE, re.I | re.S) - -RUID_URL_BETWEEN_PARENS_RE = ( - r'[^(]*\((?P[^\"\')]*%s/(?P[^\/\"\')#? ]*))' % RUID_URL - ) -RUID_URL_BETWEEN_PARENS = re.compile(RUID_URL_BETWEEN_PARENS_RE, re.I | re.S) - - -def find_tags_with_resolveuid(data): - tags_with_resolveuid = [] - unique_uids = set() - - for m in TAG_WITH_URL.finditer(data): - ruid = re.search(RUID_URL_BETWEEN_QUOTES, m.group(0)[:3000]) - if ruid: - tags_with_resolveuid.append( - (m.group(0), ruid.group('uid'), ruid.group('url_with_uid')) - ) - - for m in TAG_WITH_STYLE.finditer(data): - ruid = re.search(RUID_URL_BETWEEN_PARENS, m.group(0)[:3000]) - if ruid: - tags_with_resolveuid.append( - (m.group(0), ruid.group('uid'), ruid.group('url_with_uid')) - ) - - for tu in tags_with_resolveuid: - unique_uids.add(tu[1]) - return tags_with_resolveuid, unique_uids - - -def make_uid_to_absolute_url(unique_uids, compute_url=uuidToURL): - uid_to_absolute_url = {} - for uid in unique_uids: - url = compute_url(uid) - if url is not None: - uid_to_absolute_url[uid] = url - return uid_to_absolute_url - @implementer(ITransform) class ck_ruid_to_url: - """Transform which replaces resolve uid in absolute urls""" + """Dummy transform kept to enable uninstallation. + Might be tottaly removed later. + """ __name__ = "ck_ruid_to_url" inputs = ('text/html',) @@ -90,8 +24,7 @@ def name(self): return self.__name__ def convert(self, orig, data, **kwargs): - converted = replace_resolveuid_urls_with_absolute_urls(orig) - data.setData(converted) + data.setData(orig) return data diff --git a/src/collective/ckeditor/upgrades.py b/src/collective/ckeditor/upgrades.py index 183bf8e8..4eaf617c 100644 --- a/src/collective/ckeditor/upgrades.py +++ b/src/collective/ckeditor/upgrades.py @@ -2,6 +2,8 @@ from Products.CMFPlone.utils import safe_unicode from plone import api import sys +from collective.ckeditor.setuphandlers import unregisterTransform +from collective.ckeditor.setuphandlers import unregisterTransformPolicy PROFILE = "profile-collective.ckeditor:default" @@ -355,3 +357,14 @@ def safe_string(value): return binary_type() else: return result + + +DOCUMENT_DEFAULT_OUTPUT_TYPE = "text/x-html-safe" +REQUIRED_TRANSFORM = "ck_ruid_to_url" + + +def no_transform(context): + site = api.portal.get() + unregisterTransform(site, 'ck_ruid_to_url') + unregisterTransformPolicy(site, DOCUMENT_DEFAULT_OUTPUT_TYPE, + REQUIRED_TRANSFORM) diff --git a/src/collective/ckeditor/upgrades.zcml b/src/collective/ckeditor/upgrades.zcml index f07eb8a2..d802d6c4 100644 --- a/src/collective/ckeditor/upgrades.zcml +++ b/src/collective/ckeditor/upgrades.zcml @@ -76,7 +76,7 @@ /> - + + + + + + + + + + +