diff --git a/news/3953.breaking b/news/3953.breaking
new file mode 100644
index 000000000..d5550759a
--- /dev/null
+++ b/news/3953.breaking
@@ -0,0 +1,2 @@
+Move plone.app.contenttypes views to plone.app.layout
+[frapell]
diff --git a/setup.py b/setup.py
index 266249480..72fbb4e36 100644
--- a/setup.py
+++ b/setup.py
@@ -56,7 +56,6 @@
"Products.MimetypesRegistry",
"Products.PortalTransforms",
"Products.statusmessages",
- "plone.app.layout",
"plone.app.textfield",
"plone.app.uuid",
"plone.autoform",
diff --git a/src/plone/app/contenttypes/browser/collection.py b/src/plone/app/contenttypes/browser/collection.py
index c4f2a4e37..9ac366118 100644
--- a/src/plone/app/contenttypes/browser/collection.py
+++ b/src/plone/app/contenttypes/browser/collection.py
@@ -1,85 +1,9 @@
-from Acquisition import aq_inner
-from plone.app.contenttypes import _
-from plone.app.contenttypes.behaviors.collection import ICollection
-from plone.app.contenttypes.behaviors.leadimage import ILeadImage
-from plone.app.contenttypes.browser.folder import FolderView
-from plone.app.contenttypes.interfaces import IFolder
-from plone.app.contenttypes.interfaces import IImage
-from plone.memoize.view import memoize
+import zope.deferredimport
-class CollectionView(FolderView):
- @property
- def collection_behavior(self):
- return ICollection(aq_inner(self.context))
+zope.deferredimport.initialize()
- @property
- def b_size(self):
- return getattr(self, "_b_size", self.collection_behavior.item_count)
-
- def results(self, **kwargs):
- """Return a content listing based result set with results from the
- collection query.
-
- :param **kwargs: Any keyword argument, which can be used for catalog
- queries.
- :type **kwargs: keyword argument
-
- :returns: plone.app.contentlisting based result set.
- :rtype: ``plone.app.contentlisting.interfaces.IContentListing`` based
- sequence.
- """
- # Extra filter
- contentFilter = dict(self.request.get("contentFilter", {}))
- contentFilter.update(kwargs.get("contentFilter", {}))
- kwargs.setdefault("custom_query", contentFilter)
- kwargs.setdefault("batch", True)
- kwargs.setdefault("b_size", self.b_size)
- kwargs.setdefault("b_start", self.b_start)
-
- results = self.collection_behavior.results(**kwargs)
- return results
-
- def batch(self):
- # collection is already batched.
- return self.results()
-
- @property
- @memoize
- def _album_results(self):
- """Get results to display an album with subalbums."""
- results = self.results()
- images = []
- folders = []
- for it in results:
- # TODO: potentially expensive!
- ob = it.getObject()
- if IFolder.providedBy(ob):
- folders.append(it)
- elif IImage.providedBy(ob) or ILeadImage.providedBy(ob):
- images.append(it)
- return {"images": images, "folders": folders}
-
- @property
- def album_images(self):
- """Get all images within this collection."""
- return self._album_results["images"]
-
- @property
- def album_folders(self):
- """Get all folders within this collection."""
- return self._album_results["folders"]
-
- def tabular_fields(self):
- """Return a list of all metadata fields from the catalog that were
- selected.
- """
- context = aq_inner(self.context)
- wrapped = ICollection(context)
- fields = wrapped.selectedViewFields()
- fields = [field[0] for field in fields]
- return fields
-
- @property
- def no_items_message(self):
- return _("description_no_results_found", default="No results were found.")
+zope.deferredimport.deprecated(
+ "Please use from plone.app.layout.contenttypes.collection import CollectionView instead.",
+ CollectionView="plone.app.layout.contenttypes.collection:CollectionView",
+)
diff --git a/src/plone/app/contenttypes/browser/configure.zcml b/src/plone/app/contenttypes/browser/configure.zcml
index b3e2c7ba3..1e3c16314 100644
--- a/src/plone/app/contenttypes/browser/configure.zcml
+++ b/src/plone/app/contenttypes/browser/configure.zcml
@@ -8,7 +8,14 @@
+
+
+
+
+
+
+
diff --git a/src/plone/app/contenttypes/browser/file.py b/src/plone/app/contenttypes/browser/file.py
index 0a5ffa7c1..681886f68 100644
--- a/src/plone/app/contenttypes/browser/file.py
+++ b/src/plone/app/contenttypes/browser/file.py
@@ -1,33 +1,9 @@
-from plone.app.contenttypes.browser.utils import Utils
-from plone.base.utils import human_readable_size
+import zope.deferredimport
-import re
+zope.deferredimport.initialize()
-class FileView(Utils):
- def is_videotype(self):
- ct = self.context.file.contentType
- return "video/" in ct
-
- def is_audiotype(self):
- ct = self.context.file.contentType
- return "audio/" in ct
-
- def human_readable_size(self):
- return human_readable_size(self.context.file.getSize())
-
- def icon(self):
- if "text" in self.context.file.contentType:
- return "contenttype-text"
- if "html" in self.context.file.contentType:
- return "contenttype-text"
- if re.search(r"(archive|zip|compressed)", self.context.file.contentType):
- return "contenttype-archive"
- if "audio" in self.context.file.contentType:
- return "contenttype-audio"
- if "video" in self.context.file.contentType:
- return "contenttype-video"
- if "pdf" in self.context.file.contentType:
- return "contenttype-pdf"
- else:
- return "contenttype-file"
+zope.deferredimport.deprecated(
+ "Please use from plone.app.layout.contenttypes.file import FileView instead.",
+ FileView="plone.app.layout.contenttypes.file:FileView",
+)
diff --git a/src/plone/app/contenttypes/browser/folder.py b/src/plone/app/contenttypes/browser/folder.py
index 9bdac03b4..b62ba29d6 100644
--- a/src/plone/app/contenttypes/browser/folder.py
+++ b/src/plone/app/contenttypes/browser/folder.py
@@ -1,278 +1,9 @@
-from Acquisition import aq_base
-from Acquisition import aq_inner
-from plone.app.contenttypes import _
-from plone.app.contenttypes.behaviors.leadimage import ILeadImage
-from plone.app.contenttypes.interfaces import IFolder
-from plone.app.contenttypes.interfaces import IImage
-from plone.app.vocabularies.metadatafields import get_field_label
-from plone.base.batch import Batch
-from plone.base.interfaces import ISecuritySchema
-from plone.base.interfaces import ISiteSchema
-from plone.base.utils import safe_callable
-from plone.event.interfaces import IEvent
-from plone.memoize.view import memoize
-from plone.registry.interfaces import IRegistry
-from Products.Five import BrowserView
-from zope.component import getMultiAdapter
-from zope.component import getUtility
-from zope.contentprovider.interfaces import IContentProvider
+import zope.deferredimport
-import random
+zope.deferredimport.initialize()
-class FolderView(BrowserView):
- text_class = None
- _plone_view = None
- _portal_state = None
- _pas_member = None
-
- @property
- def plone_view(self):
- if not self._plone_view:
- self._plone_view = getMultiAdapter(
- (self.context, self.request), name="plone"
- )
- return self._plone_view
-
- @property
- def portal_state(self):
- if not self._portal_state:
- self._portal_state = getMultiAdapter(
- (self.context, self.request), name="plone_portal_state"
- )
- return self._portal_state
-
- @property
- def pas_member(self):
- if not self._pas_member:
- self._pas_member = getMultiAdapter(
- (self.context, self.request), name="pas_member"
- )
- return self._pas_member
-
- @property
- def b_size(self):
- b_size = (
- getattr(self.request, "b_size", None)
- or getattr(self.request, "limit_display", None)
- or 20
- )
- return int(b_size)
-
- @property
- def b_start(self):
- b_start = getattr(self.request, "b_start", None) or 0
- return int(b_start)
-
- def results(self, **kwargs):
- """Return a content listing based result set with contents of the
- folder.
-
- :param **kwargs: Any keyword argument, which can be used for catalog
- queries.
- :type **kwargs: keyword argument
-
- :returns: plone.app.contentlisting based result set.
- :rtype: ``plone.app.contentlisting.interfaces.IContentListing`` based
- sequence.
- """
- # Extra filter
- kwargs.update(self.request.get("contentFilter", {}))
- if "object_provides" not in kwargs: # object_provides is more specific
- kwargs.setdefault("portal_type", self.friendly_types)
- kwargs.setdefault("batch", True)
- kwargs.setdefault("b_size", self.b_size)
- kwargs.setdefault("b_start", self.b_start)
- kwargs.setdefault("orphan", 1)
-
- listing = aq_inner(self.context).restrictedTraverse("@@folderListing", None)
- if listing is None:
- return []
- results = listing(**kwargs)
- return results
-
- def batch(self):
- batch = Batch(self.results(), size=self.b_size, start=self.b_start, orphan=1)
- return batch
-
- def normalizeString(self, text):
- return self.plone_view.normalizeString(text)
-
- def toLocalizedTime(self, time, long_format=None, time_only=None):
- return self.plone_view.toLocalizedTime(time, long_format, time_only)
-
- @property
- def friendly_types(self):
- return self.portal_state.friendly_types()
-
- @property
- def isAnon(self):
- return self.portal_state.anonymous()
-
- @property
- def navigation_root_url(self):
- return self.portal_state.navigation_root_url()
-
- @property
- def use_view_action(self):
- registry = getUtility(IRegistry)
- return registry.get("plone.types_use_view_action_in_listings", [])
-
- @property
- def show_about(self):
- registry = getUtility(IRegistry)
- settings = registry.forInterface(ISecuritySchema, prefix="plone")
- show_about = getattr(settings, "allow_anon_views_about", False)
- return show_about or not self.isAnon
-
- @property
- def text(self):
- textfield = getattr(aq_base(self.context), "text", None)
- text = (
- textfield.output_relative_to(self.context)
- if getattr(textfield, "output_relative_to", None)
- else None
- )
- if text:
- self.text_class = (
- "stx"
- if textfield.mimeType
- in ("text/structured", "text/x-rst", "text/restructured")
- else "plain"
- )
- return text
-
- @property
- def tabular_fields(self):
- ret = []
- ret.append("Title")
- if self.show_about:
- ret.append("Creator")
- ret.append("Type")
- if self.show_about:
- ret.append("ModificationDate")
- return ret
-
- def tabular_field_label(self, field):
- """Return the internationalized label (Message object) corresponding
- to the field.
- """
- return get_field_label(field)
-
- def tabular_fielddata(self, item, fieldname):
- value = getattr(item, fieldname, "")
- if safe_callable(value):
- value = value()
- if fieldname in [
- "CreationDate",
- "ModificationDate",
- "Date",
- "EffectiveDate",
- "ExpirationDate",
- "effective",
- "expires",
- "start",
- "end",
- "created",
- "modified",
- "last_comment_date",
- ]:
- value = self.toLocalizedTime(value, long_format=1)
-
- return {
- # 'title': _(fieldname, default=fieldname),
- "value": value
- }
-
- def is_event(self, obj):
- if getattr(obj, "getObject", False):
- obj = obj.getObject()
- return IEvent.providedBy(obj)
-
- def formatted_date(self, item):
- provider = getMultiAdapter(
- (self.context, self.request, self), IContentProvider, name="formatted_date"
- )
- return provider(item)
-
- @property
- @memoize
- def album_images(self):
- """Get all images within this folder."""
- provides = [
- IImage.__identifier__,
- ILeadImage.__identifier__,
- ]
- images = self.results(batch=False, object_provides=provides)
- return images
-
- @property
- @memoize
- def album_folders(self):
- """Get all folders within this folder."""
- images = self.results(batch=False, object_provides=IFolder.__identifier__)
- return images
-
- @property
- def album_random_image(self):
- """Get random image from this folder."""
- img = None
- images = self.album_images
- if images:
- img = random.choice(images)
- return img
-
- @property
- def album_number_images(self):
- """Get number of images from this folder."""
- images = self.album_images
- return len(images)
-
- @property
- def no_items_message(self):
- return _(
- "description_no_items_in_folder",
- default="There are currently no items in this folder.",
- )
-
- @memoize
- def get_thumb_scale_table(self):
- if getattr(self.context, "suppress_thumbs", False):
- return None
- thsize = getattr(self.context, "thumb_scale_table", None)
- if thsize:
- return thsize
- registry = getUtility(IRegistry)
- settings = registry.forInterface(ISiteSchema, prefix="plone", check=False)
- if settings.no_thumbs_tables:
- return None
- return settings.thumb_scale_table
-
- @memoize
- def get_thumb_scale_list(self):
- if getattr(self.context, "suppress_thumbs", False):
- return None
- thsize = getattr(self.context, "thumb_scale_list", None)
- if thsize:
- return thsize
- registry = getUtility(IRegistry)
- settings = registry.forInterface(ISiteSchema, prefix="plone", check=False)
- if settings.no_thumbs_lists:
- return None
- return settings.thumb_scale_listing
-
- @memoize
- def get_thumb_scale_summary(self):
- if getattr(self.context, "suppress_thumbs", False):
- return None
- thsize = getattr(self.context, "thumb_scale_summary", None)
- if thsize:
- return thsize
- registry = getUtility(IRegistry)
- settings = registry.forInterface(ISiteSchema, prefix="plone", check=False)
- if settings.no_thumbs_summary:
- return None
- return settings.thumb_scale_summary
-
- def show_icons(self):
- return not getattr(self.context, "suppress_icons", False)
+zope.deferredimport.deprecated(
+ "Please use from plone.app.layout.contenttypes.folder import FolderView instead.",
+ FolderView="plone.app.layout.contenttypes.folder:FolderView",
+)
diff --git a/src/plone/app/contenttypes/browser/full_view.py b/src/plone/app/contenttypes/browser/full_view.py
index f2fc191f1..8a39b23a7 100644
--- a/src/plone/app/contenttypes/browser/full_view.py
+++ b/src/plone/app/contenttypes/browser/full_view.py
@@ -1,30 +1,9 @@
-from plone.registry.interfaces import IRegistry
-from Products.Five.browser import BrowserView
-from zope.component import getUtility
-from zope.publisher.interfaces.browser import IBrowserView
+import zope.deferredimport
-class FullViewItem(BrowserView):
- @property
- def default_view(self):
- item_layout = self.context.getLayout()
- default_view = self.context.restrictedTraverse(item_layout)
- return default_view
+zope.deferredimport.initialize()
- @property
- def item_macros(self):
- default_view = self.default_view
- if IBrowserView.providedBy(default_view):
- # IBrowserView
- return default_view.index.macros
- # FSPageTemplate
- return default_view.macros
-
- @property
- def item_url(self):
- registry = getUtility(IRegistry)
- use_view_action = registry.get("plone.types_use_view_action_in_listings", [])
- url = self.context.absolute_url()
- if self.context.portal_type in use_view_action:
- url = f"{url}/view"
- return url
+zope.deferredimport.deprecated(
+ "Please use from plone.app.layout.contenttypes.full_view import FullViewItem instead.",
+ FullViewItem="plone.app.layout.contenttypes.full_view:FullViewItem",
+)
diff --git a/src/plone/app/contenttypes/browser/images/icon_export_ical.png b/src/plone/app/contenttypes/browser/images/icon_export_ical.png
deleted file mode 100644
index df034b203..000000000
Binary files a/src/plone/app/contenttypes/browser/images/icon_export_ical.png and /dev/null differ
diff --git a/src/plone/app/contenttypes/browser/images/icon_export_vcal.png b/src/plone/app/contenttypes/browser/images/icon_export_vcal.png
deleted file mode 100644
index d91f94b92..000000000
Binary files a/src/plone/app/contenttypes/browser/images/icon_export_vcal.png and /dev/null differ
diff --git a/src/plone/app/contenttypes/browser/link_redirect_view.py b/src/plone/app/contenttypes/browser/link_redirect_view.py
index 1ebc0ea88..fa637dbc6 100644
--- a/src/plone/app/contenttypes/browser/link_redirect_view.py
+++ b/src/plone/app/contenttypes/browser/link_redirect_view.py
@@ -1,163 +1,13 @@
-from plone.app.contenttypes.utils import replace_link_variables_by_paths
-from plone.app.uuid.utils import uuidToObject
-from plone.base.interfaces import ITypesSchema
-from plone.registry.interfaces import IRegistry
-from Products.CMFCore.utils import getToolByName
-from Products.Five.browser import BrowserView
-from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
-from urllib.parse import urlparse
-from zope.component import getUtility
+import zope.deferredimport
-# links starting with these URL scheme should not be redirected to
-NON_REDIRECTABLE_URL_SCHEMES = [
- "mailto:",
- "tel:",
- "callto:", # nonstandard according to RFC 3966. used for skype.
- "webdav:",
- "caldav:",
-]
-# links starting with these URL scheme should not be resolved to paths
-NON_RESOLVABLE_URL_SCHEMES = NON_REDIRECTABLE_URL_SCHEMES + [
- "file:",
- "ftp:",
-]
+zope.deferredimport.initialize()
-
-def normalize_uid_from_path(url=None):
- """
- Args:
- url (string): a path or orl
-
- Returns:
- tuple: tuple of (uid, fragment) a fragment is an anchor id e.g. #head1
- """
- uid = None
- fragment = None
-
- if not url:
- return uid, fragment
-
- # resolve uid
- paths = url.split("/")
- paths_lower = [_item.lower() for _item in paths]
-
- if "resolveuid" in paths_lower:
- ri = paths_lower.index("resolveuid")
- if ri + 1 != len(paths):
- uid = paths[ri + 1]
- if uid == "":
- uid = None
-
- if not uid:
- return uid, fragment
-
- # resolve fragment
- parts = urlparse(uid)
-
- uid = parts.path
-
- fragment = f"#{parts.fragment}" if parts.fragment else None
-
- return uid, fragment
-
-
-class LinkRedirectView(BrowserView):
- index = ViewPageTemplateFile("templates/link.pt")
-
- def _url_uses_scheme(self, schemes, url=None):
- url = url or self.context.remoteUrl.strip()
- for scheme in schemes:
- if url.startswith(scheme):
- return True
- return False
-
- @property
- def can_edit(self):
- context = self.context
- mtool = getToolByName(context, "portal_membership")
- return mtool.checkPermission("Modify portal content", context)
-
- def __call__(self):
- """Redirect to the Link target URL, if and only if:
- - redirect_links property is enabled in
- configuration registry
- - the link is of a redirectable type (no mailto:, etc)
- - AND current user doesn't have permission to edit the Link"""
-
- registry = getUtility(IRegistry)
- settings = registry.forInterface(ITypesSchema, prefix="plone")
- redirect_links = settings.redirect_links
-
- redirect_links = redirect_links and not self._url_uses_scheme(
- NON_REDIRECTABLE_URL_SCHEMES
- )
-
- if redirect_links and not self.can_edit:
- return self.request.RESPONSE.redirect(self.absolute_target_url())
- return self.index()
-
- def url(self):
- """Returns the url with link variables replaced."""
- url = replace_link_variables_by_paths(
- self.context, self.context.remoteUrl.strip()
- )
- return url
-
- def display_link(self):
- """Format the url for display"""
-
- url = self.url()
- if "resolveuid" in url:
- uid = url.split("/")[-1]
- obj = uuidToObject(uid)
- if obj:
- title = obj.Title()
- meta = obj.absolute_url_path()
- return {
- "title": title,
- "meta": meta,
- }
-
- parsed = urlparse(url)
- if parsed.scheme == "mailto":
- return {
- "title": parsed.path,
- "meta": "",
- }
-
- return {
- "title": url,
- "meta": "",
- }
-
- def absolute_target_url(self):
- """Compute the absolute target URL."""
- url = self.url()
-
- if self._url_uses_scheme(NON_RESOLVABLE_URL_SCHEMES):
- # For non http/https url schemes, there is no path to resolve.
- return url
-
- if url.startswith("."):
- # we just need to adapt ../relative/links, /absolute/ones work
- # anyway -> this requires relative links to start with ./ or
- # ../
- context_state = self.context.restrictedTraverse("@@plone_context_state")
- url = "/".join([context_state.canonical_object_url(), url])
- else:
- if "resolveuid" in url:
- uid, fragment = normalize_uid_from_path(url)
- obj = uuidToObject(uid)
- if obj is None:
- # uid can't resolve, return the url
- return url
-
- url = obj.absolute_url()
- if fragment is not None:
- url = f"{url}{fragment}"
-
- if not url.startswith(("http://", "https://")):
- url = self.request["SERVER_URL"] + url
-
- return url
+zope.deferredimport.deprecated(
+ "Please use from plone.app.layout.contenttypes.link_redirect_view import "
+ "LinkRedirectView, normalize_uid_from_path instead.",
+ NON_REDIRECTABLE_URL_SCHEMES="plone.app.layout.contenttypes.link_redirect_view:NON_REDIRECTABLE_URL_SCHEMES",
+ NON_RESOLVABLE_URL_SCHEMES="plone.app.layout.contenttypes.link_redirect_view:NON_RESOLVABLE_URL_SCHEMES",
+ normalize_uid_from_path="plone.app.layout.contenttypes.link_redirect_view:normalize_uid_from_path",
+ LinkRedirectView="plone.app.layout.contenttypes.link_redirect_view:LinkRedirectView",
+)
diff --git a/src/plone/app/contenttypes/browser/migration.py b/src/plone/app/contenttypes/browser/migration.py
index ff829623a..4731d96f1 100644
--- a/src/plone/app/contenttypes/browser/migration.py
+++ b/src/plone/app/contenttypes/browser/migration.py
@@ -1,112 +1,14 @@
-from plone.app.contenttypes.utils import changed_base_classes
-from plone.app.contenttypes.utils import get_old_class_name_string
-from plone.app.contenttypes.utils import migrate_base_class_to_new_class
-from plone.base import PloneMessageFactory as _
-from plone.z3cform.layout import wrap_form
-from Products.CMFCore.utils import getToolByName
-from Products.statusmessages.interfaces import IStatusMessage
-from z3c.form import button
-from z3c.form import field
-from z3c.form import form
-from z3c.form.browser.checkbox import CheckBoxFieldWidget
-from zExceptions import NotFound
-from zope import schema
-from zope.interface import implementer
-from zope.interface import Interface
-from zope.schema.interfaces import IVocabularyFactory
-from zope.schema.vocabulary import SimpleVocabulary
+import zope.deferredimport
-import logging
-logger = logging.getLogger(__name__)
+zope.deferredimport.initialize()
-
-@implementer(IVocabularyFactory)
-class ChangedBaseClasses:
- def __call__(self, context):
- """Return a vocabulary with all changed base classes."""
- terms = []
- for class_name, data in changed_base_classes(context).items():
- title = "{} (➡ {}) - ({} items)".format(
- data["old"], data["new"], data["amount"]
- )
- term = SimpleVocabulary.createTerm(class_name, class_name, title)
- terms.append(term)
- return SimpleVocabulary(terms)
-
-
-class IBaseClassMigratorForm(Interface):
- changed_base_classes = schema.List(
- title="Changed base classes (old class, new class and number of items)",
- description="Select changed base classes you want to migrate. "
- "If the new types are folderish that change is also applied.",
- value_type=schema.Choice(
- vocabulary="plone.app.contenttypes.migration.changed_base_classes",
- ),
- default=[],
- required=True,
- )
-
-
-class BaseClassMigratorForm(form.Form):
- label = _(
- "heading_class_migrator",
- default="Update base-classes for content with changed classes",
- )
-
- fields = field.Fields(IBaseClassMigratorForm)
- fields["changed_base_classes"].widgetFactory = CheckBoxFieldWidget
- ignoreContext = True
- enableCSRFProtection = True
-
- def updateWidgets(self):
- super().updateWidgets()
- changed_base_classes = self.widgets["changed_base_classes"]
- if not changed_base_classes.terms.terms.by_value:
- IStatusMessage(self.request).addStatusMessage(
- "No types with changed classes to migrate!", type="warning"
- )
- return
-
- @button.buttonAndHandler("Update", name="update")
- def handle_migrate(self, action):
- data, errors = self.extractData()
-
- if errors:
- return
-
- changed_base_classes = data.get("changed_base_classes", [])
- messages = IStatusMessage(self.request)
- if not changed_base_classes:
- messages.addStatusMessage("No types were selected", type="warning")
- return
-
- catalog = getToolByName(self.context, "portal_catalog")
- migrated = []
- not_migrated = []
- for brain in catalog():
- try:
- obj = brain.getObject()
- except (KeyError, NotFound):
- continue
- old_class_name = get_old_class_name_string(obj)
- if old_class_name in changed_base_classes:
- if migrate_base_class_to_new_class(obj, migrate_to_folderish=True):
- migrated.append(obj)
- else:
- not_migrated.append(obj)
-
- info_message_template = "{0} objects were migrated."
- warn_message_template = "{0} objects were not migrated."
- if migrated:
- msg = info_message_template.format(len(migrated))
- messages.addStatusMessage(msg, type="info")
- if not_migrated:
- msg = warn_message_template.format(len(not_migrated))
- messages.addStatusMessage(msg, type="warning")
- self.request.response.redirect(self.request["ACTUAL_URL"])
-
-
-BaseClassMigrator = wrap_form(
- BaseClassMigratorForm,
+zope.deferredimport.deprecated(
+ "Please use from plone.app.layout.contenttypes.migration import "
+ "BaseClassMigrator, BaseClassMigratorForm, ChangedBaseClasses, "
+ "IBaseClassMigratorForm instead.",
+ ChangedBaseClasses="plone.app.layout.contenttypes.migration:ChangedBaseClasses",
+ IBaseClassMigratorForm="plone.app.layout.contenttypes.migration:IBaseClassMigratorForm",
+ BaseClassMigratorForm="plone.app.layout.contenttypes.migration:BaseClassMigratorForm",
+ BaseClassMigrator="plone.app.layout.contenttypes.migration:BaseClassMigrator",
)
diff --git a/src/plone/app/contenttypes/browser/templates/document.pt b/src/plone/app/contenttypes/browser/templates/document.pt
deleted file mode 100644
index 5e4da56a3..000000000
--- a/src/plone/app/contenttypes/browser/templates/document.pt
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/plone/app/contenttypes/browser/templates/file.pt b/src/plone/app/contenttypes/browser/templates/file.pt
deleted file mode 100644
index 6da3fc036..000000000
--- a/src/plone/app/contenttypes/browser/templates/file.pt
+++ /dev/null
@@ -1,102 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- image/jpeg
-
-
-
- 1000 kB
-
-
-
-
-
-
-
-
-
-
-
- There is no file uploaded.
-
-
-
-
-
-
-
-
diff --git a/src/plone/app/contenttypes/browser/templates/full_view.pt b/src/plone/app/contenttypes/browser/templates/full_view.pt
deleted file mode 100644
index dee5d8118..000000000
--- a/src/plone/app/contenttypes/browser/templates/full_view.pt
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/plone/app/contenttypes/browser/templates/full_view_item.pt b/src/plone/app/contenttypes/browser/templates/full_view_item.pt
deleted file mode 100644
index e17e57900..000000000
--- a/src/plone/app/contenttypes/browser/templates/full_view_item.pt
+++ /dev/null
@@ -1,90 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
- Description
-
-
-
-
-
-
-
-
-
-
- Read More…
-
-
-
-
-
-
diff --git a/src/plone/app/contenttypes/browser/templates/image.pt b/src/plone/app/contenttypes/browser/templates/image.pt
deleted file mode 100644
index cb77820f0..000000000
--- a/src/plone/app/contenttypes/browser/templates/image.pt
+++ /dev/null
@@ -1,96 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Type
- image/jpeg
-
-
-
- Dimension
- 400x300
-
-
-
- File size
-
- ${python:round(size/1024/1024, 1)}
- MB
-
- ${python:round(size/1024, 1)}
- KB
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/plone/app/contenttypes/browser/templates/image_view_fullscreen.pt b/src/plone/app/contenttypes/browser/templates/image_view_fullscreen.pt
deleted file mode 100644
index 828d0ad92..000000000
--- a/src/plone/app/contenttypes/browser/templates/image_view_fullscreen.pt
+++ /dev/null
@@ -1,85 +0,0 @@
-
-
-
-
-
- Title
-
-
-
-
-
-
-
-
diff --git a/src/plone/app/contenttypes/browser/templates/link.pt b/src/plone/app/contenttypes/browser/templates/link.pt
deleted file mode 100644
index c7689e210..000000000
--- a/src/plone/app/contenttypes/browser/templates/link.pt
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- You see this page because you have permission to edit this link.
- Others will be immediately redirected to the link's target URL.
-
-
-
-
-
-
-
-
-
-
diff --git a/src/plone/app/contenttypes/browser/templates/listing.pt b/src/plone/app/contenttypes/browser/templates/listing.pt
deleted file mode 100644
index 9ad3df226..000000000
--- a/src/plone/app/contenttypes/browser/templates/listing.pt
+++ /dev/null
@@ -1,194 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- —
- Oslo
-
- —
-
-
-
-
-
- by
-
- Bob Dobalina
-
-
-
-
-
- —
- last modified
-
- August 16, 2001 at 23:35:59
-
-
-
-
-
- Place custom listing info for custom types here
-
-
-
-
-
-
-
-
- description
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- There are currently no items in this folder.
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/plone/app/contenttypes/browser/templates/listing_album.pt b/src/plone/app/contenttypes/browser/templates/listing_album.pt
deleted file mode 100644
index 70561c0e6..000000000
--- a/src/plone/app/contenttypes/browser/templates/listing_album.pt
+++ /dev/null
@@ -1,124 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
![]()
-
-
-
Image title
-
Description
-
View
-
-
-
-
-
-
-
-
-
-
![]()
-
-
-
Image title
-
Description
-
View
-
-
-
-
-
-
-
-
-
-
-
- There are currently no items in this folder.
-
-
-
-
-
-
-
-
-
diff --git a/src/plone/app/contenttypes/browser/templates/listing_summary.pt b/src/plone/app/contenttypes/browser/templates/listing_summary.pt
deleted file mode 100644
index fec35e619..000000000
--- a/src/plone/app/contenttypes/browser/templates/listing_summary.pt
+++ /dev/null
@@ -1,91 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- description
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/plone/app/contenttypes/browser/templates/listing_tabular.pt b/src/plone/app/contenttypes/browser/templates/listing_tabular.pt
deleted file mode 100644
index 29b8cdc39..000000000
--- a/src/plone/app/contenttypes/browser/templates/listing_tabular.pt
+++ /dev/null
@@ -1,177 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- There are currently no items in this folder.
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/plone/app/contenttypes/browser/templates/newsitem.pt b/src/plone/app/contenttypes/browser/templates/newsitem.pt
deleted file mode 100644
index 77d7eac23..000000000
--- a/src/plone/app/contenttypes/browser/templates/newsitem.pt
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/plone/app/contenttypes/browser/utils.py b/src/plone/app/contenttypes/browser/utils.py
index 307f5ff0c..cbcdd717d 100644
--- a/src/plone/app/contenttypes/browser/utils.py
+++ b/src/plone/app/contenttypes/browser/utils.py
@@ -1,55 +1,11 @@
-from Acquisition import aq_inner
-from plone.memoize.view import memoize
-from Products.CMFCore.utils import getToolByName
-from Products.Five.browser import BrowserView
-from Products.MimetypesRegistry.MimeTypeItem import guess_icon_path
-from zope.component import getMultiAdapter
-from zope.interface import implementer
-from zope.interface import Interface
+import zope.deferredimport
-PREFIX = "++resource++mimetype.icons/"
+zope.deferredimport.initialize()
-class IUtils(Interface):
- """ """
-
- def getMimeTypeIcon(content_file):
- """ """
-
-
-@implementer(IUtils)
-class Utils(BrowserView):
- def _get_mimes(self, content_file):
- # We use 'yield' so iteration can be cut short
- # if the calling code is happy.
- context = aq_inner(self.context)
- mtr = getToolByName(context, "mimetypes_registry")
- if content_file.contentType:
- # this gives a tuple
- yield from mtr.lookup(content_file.contentType)
- if content_file.filename:
- # this gives a single mime type
- yield mtr.lookupExtension(content_file.filename)
- yield from mtr.lookup("application/octet-stream")
-
- @memoize
- def getMimeTypeIcon(self, content_file):
- # Get possible mime types, and try to find an icon path.
- # Keep the first one, in case there is no good match.
- first = None
- for mime in self._get_mimes(content_file):
- if first is None:
- first = mime
- if hasattr(mime, "icon_path"):
- icon_path = mime.icon_path
- if not icon_path.startswith("++"):
- icon_path = PREFIX + icon_path
- return icon_path
-
- if first is None:
- # Probably does not happen in practice.
- return ""
- context = aq_inner(self.context)
- pstate = getMultiAdapter((context, self.request), name="plone_portal_state")
- portal_url = pstate.portal_url()
- return portal_url + "/" + guess_icon_path(first)
+zope.deferredimport.deprecated(
+ "Please use from plone.app.layout.contenttypes.utils import IUtils, Utils instead.",
+ PREFIX="plone.app.layout.contenttypes.utils:PREFIX",
+ IUtils="plone.app.layout.contenttypes.utils:IUtils",
+ Utils="plone.app.layout.contenttypes.utils:Utils",
+)
diff --git a/src/plone/app/contenttypes/tests/test_folder.py b/src/plone/app/contenttypes/tests/test_folder.py
index 47c048f55..9ddd32f5a 100644
--- a/src/plone/app/contenttypes/tests/test_folder.py
+++ b/src/plone/app/contenttypes/tests/test_folder.py
@@ -1,6 +1,3 @@
-from datetime import datetime
-from datetime import timedelta
-from plone.app.contenttypes.browser.folder import FolderView
from plone.app.contenttypes.interfaces import IFolder
from plone.app.contenttypes.testing import ( # noqa
PLONE_APP_CONTENTTYPES_FUNCTIONAL_TESTING,
@@ -8,7 +5,6 @@
from plone.app.contenttypes.testing import ( # noqa
PLONE_APP_CONTENTTYPES_INTEGRATION_TESTING,
)
-from plone.app.contenttypes.tests.test_image import dummy_image
from plone.app.testing import setRoles
from plone.app.testing import SITE_OWNER_NAME
from plone.app.testing import SITE_OWNER_PASSWORD
@@ -50,74 +46,6 @@ def test_adding(self):
self.assertTrue(IFolder.providedBy(self.portal["doc1"]))
-class FolderViewIntegrationTest(unittest.TestCase):
- layer = PLONE_APP_CONTENTTYPES_INTEGRATION_TESTING
-
- def setUp(self):
- self.portal = self.layer["portal"]
- self.request = self.layer["request"]
- self.request["ACTUAL_URL"] = self.portal.absolute_url()
- setRoles(self.portal, TEST_USER_ID, ["Contributor"])
-
- def test_result_filtering(self):
- """Test, if portal_state's friendly_types and the result method's
- keyword arguments are included in the query.
- """
-
- self.portal.invokeFactory("News Item", "newsitem")
- self.portal.invokeFactory("Document", "document")
- view = FolderView(self.portal, self.request)
-
- # Test, if all results are found.
- view.portal_state.friendly_types = lambda: ["Document", "News Item"]
- res = view.results()
- self.assertEqual(len(res), 2)
-
- # Test, if friendly_types does filter for types.
- view.portal_state.friendly_types = lambda: ["Document"]
- res = view.results()
- self.assertEqual(len(res), 1)
-
- # Test, if friendly_types does filter for types.
- view.portal_state.friendly_types = lambda: ["NotExistingType"]
- res = view.results()
- self.assertEqual(len(res), 0)
-
- # Test, if kwargs filtering is applied.
- view.portal_state.friendly_types = lambda: ["NotExistingType"]
- res = view.results(
- object_provides="plone.app.contenttypes.interfaces.IDocument"
- )
- self.assertEqual(len(res), 1)
-
- def test_result_batching(self):
- for idx in range(5):
- self.portal.invokeFactory("Document", f"document{idx}")
- request = self.request.clone()
- request.form["b_size"] = 5
- view = FolderView(self.portal, request)
-
- batch = view.batch()
- self.assertEqual(batch.length, 5)
- self.assertEqual(len([item for item in batch]), 5)
- self.assertFalse(batch.has_next)
-
- self.portal.invokeFactory("Document", "document5")
-
- batch = view.batch()
- self.assertEqual(batch.length, 6)
- self.assertEqual(len([item for item in batch]), 6)
- self.assertFalse(batch.has_next)
-
- self.portal.invokeFactory("Document", "document6")
-
- batch = view.batch()
- self.assertEqual(batch.length, 5)
- self.assertEqual(len([item for item in batch]), 5)
- self.assertTrue(batch.has_next)
- self.assertEqual(batch.next_item_count, 2)
-
-
class FolderFunctionalTest(unittest.TestCase):
layer = PLONE_APP_CONTENTTYPES_FUNCTIONAL_TESTING
@@ -158,102 +86,3 @@ def test_add_folder_with_shortname(self):
self.browser.getControl(name=widget).value = "my-special-folder"
self.browser.getControl("Save").click()
self.assertTrue(self.browser.url.endswith("my-special-folder/view"))
-
-
-class FolderViewFunctionalTest(unittest.TestCase):
- layer = PLONE_APP_CONTENTTYPES_FUNCTIONAL_TESTING
-
- def setUp(self):
- app = self.layer["app"]
- self.portal = self.layer["portal"]
- self.request = self.layer["request"]
- setRoles(self.portal, TEST_USER_ID, ["Manager"])
- self.portal_url = self.portal.absolute_url()
- self.portal.invokeFactory("Folder", id="folder", title="My Folder")
- self.folder = self.portal.folder
- self.folder_url = self.folder.absolute_url()
- self.folder.invokeFactory("Document", id="doc1", title="Document 1")
- import transaction
-
- transaction.commit()
- self.browser = Browser(app)
- self.browser.handleErrors = False
- self.browser.addHeader(
- "Authorization",
- "Basic {}:{}".format(
- SITE_OWNER_NAME,
- SITE_OWNER_PASSWORD,
- ),
- )
-
- def test_folder_view(self):
- self.browser.open(self.folder_url + "/view")
- self.assertIn("My Folder", self.browser.contents)
- self.assertIn("Document 1", self.browser.contents)
-
- def test_folder_summary_view(self):
- self.browser.open(self.folder_url + "/summary_view")
- self.assertIn("My Folder", self.browser.contents)
- self.assertIn("Document 1", self.browser.contents)
-
- def test_folder_full_view(self):
- self.browser.open(self.folder_url + "/full_view")
- self.assertIn("My Folder", self.browser.contents)
- self.assertIn("Document 1", self.browser.contents)
-
- def test_folder_tabular_view(self):
- self.browser.open(self.folder_url + "/tabular_view")
- self.assertIn("My Folder", self.browser.contents)
- self.assertIn("Document 1", self.browser.contents)
-
- def test_folder_album_view(self):
- self.folder.invokeFactory("Image", id="image1", title="Image 1")
- img1 = self.folder["image1"]
- img1.image = dummy_image()
- import transaction
-
- transaction.commit()
- self.browser.open(self.folder_url + "/album_view")
- self.assertIn("My Folder", self.browser.contents)
- self.assertIn(
- '
-
- def test_list_item_wout_title(self):
- )