plone / plone.namedfile

Handle File and Image fields targeting, but not depending on, Plone Dexterity content
https://pypi.org/project/plone.namedfile/
9 stars 18 forks source link

Edge case with content with id "image" #156

Open frapell opened 6 months ago

frapell commented 6 months ago

There is a very specific edge case, where an item with id "image" will throw an exception. Steps to reproduce:

  1. Create a folder with any name (e.g. Test Folder), this results in /Plone/test-folder
  2. Inside this new folder, add another folder with any name (e.g. Images) this results in /Plone/test-folder/images
  3. Inside this subfolder, create another item, can be a page or another folder, and name it pecifically "Image" so its id ends up being "image". this results in /Plone/test-folder/images/image
  4. Go back to the folder created in step 1 (/Plone/test-folder)

The following traceback is observed:

Traceback (innermost last):
  Module ZPublisher.WSGIPublisher, line 181, in transaction_pubevents
  Module ZPublisher.WSGIPublisher, line 391, in publish_module
  Module ZPublisher.WSGIPublisher, line 285, in publish
  Module ZPublisher.mapply, line 98, in mapply
  Module ZPublisher.WSGIPublisher, line 68, in call_object
  Module zope.browserpage.simpleviewclass, line 44, in __call__
  Module Products.Five.browser.pagetemplatefile, line 126, in __call__
  Module Products.Five.browser.pagetemplatefile, line 58, in __call__
  Module zope.pagetemplate.pagetemplate, line 134, in pt_render
  Module Products.PageTemplates.engine, line 365, in __call__
  Module z3c.pt.pagetemplate, line 174, in render
  Module chameleon.zpt.template, line 331, in render
  Module chameleon.template, line 217, in render
  Module chameleon.utils, line 20, in raise_with_traceback
  Module chameleon.template, line 193, in render
  Module 3cb10457e85649fa285944d63a54ffc6, line 1869, in render
  Module 45cb177dc1ec34106adbaf082ff1c6b3, line 930, in render_master
  Module 45cb177dc1ec34106adbaf082ff1c6b3, line 1553, in render_content
  Module 3cb10457e85649fa285944d63a54ffc6, line 1854, in __fill_content_core
  Module 3cb10457e85649fa285944d63a54ffc6, line 121, in render_content_core
  Module 3cb10457e85649fa285944d63a54ffc6, line 492, in render_listing
  Module 3cb10457e85649fa285944d63a54ffc6, line 959, in render_entries
  Module zope.tales.pythonexpr, line 73, in __call__
   - __traceback_info__: (image_scale.tag(item, 'image', scale=thumb_scale_list, css_class=img_class, loading='lazy'))
  Module <string>, line 1, in <module>
  Module plone.memoize.volatile, line 73, in replacement
  Module plone.namedfile.scaling, line 774, in tag
  Module plone.namedfile.scaling, line 685, in tag
  Module plone.namedfile.scaling, line 610, in scale
  Module plone.scale.storage, line 219, in pre_scale
  Module plone.scale.storage, line 204, in hash_key
  Module plone.scale.storage, line 163, in modified_time
  Module plone.namedfile.scaling, line 567, in modified
  Module DateTime.DateTime, line 446, in __init__
DateTime.interfaces.SyntaxError: DateTime.interfaces.SyntaxError: Unable to parse (<bound method DexterityContent.modified of <Document at image>>,), {}

 - Expression: "python:image_scale.tag(item, 'image', scale=thumb_scale_list, css_class=img_class, loading='lazy')"
 - Filename:   ... .egg/plone/app/contenttypes/browser/templates/listing.pt
 - Location:   (line 164: col 56)
 - Source:     ... python:image_scale.tag(item, 'image', scale=thumb_scale_list, css_class=img_class, loading='lazy') ...
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 - Expression: "provider:plone.abovecontentbody"
 - Filename:   ... one/Products/CMFPlone/browser/templates/main_template.pt
 - Location:   (line 107: col 74)
 - Source:     ... ontent="structure provider:plone.abovecontentbody" />
                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 - Expression: "context/@@main_template/macros/master"
 - Filename:   ... .egg/plone/app/contenttypes/browser/templates/listing.pt
 - Location:   (line 6: col 23)
 - Source:     ... tal:use-macro="context/@@main_template/macros/master"
                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 - Arguments:  template: <Products.Five.browser.pagetemplatefile.ViewPageTemplateFile object at 0x7f542fcc2380>
               options: {}
               args: ()
               nothing: None
               modules: <Products.PageTemplates.ZRPythonExpr._SecureModuleImporter object at 0x7f5433d71cc0>
               request: <WSGIRequest, URL=http://localhost:8080/Plone/test-folder/listing_view>
               view: <Products.Five.browser.metaconfigure.SimpleViewClass from /trabajo/plone/buildout.coredev/eggs/plone.app.contenttypes-3.0.5-py3.10.egg/plone/app/contenttypes/browser/templates/listing.pt object at 0x7f542c0b34f0>
               context: <Folder at /Plone/test-folder>
               views: <Products.Five.browser.pagetemplatefile.ViewMapper object at 0x7f542c0b0580>
               here: <Folder at /Plone/test-folder>
               container: <Folder at /Plone/test-folder>
               root: <Application at >
               traverse_subpath: []
               user: <PropertiedUser 'admin'>
               default: <DEFAULT>
               repeat: <Products.PageTemplates.engine.RepeatDictWrapper object at 0x7f54266c0d00>
               loop: {'item': <Products.PageTemplates.engine.RepeatItem object at 0x7f5426b8f730>}
               target_language: None
               translate: <function BaseTemplate.render.<locals>.translate at 0x7f54266aac20>
               macroname: 'master'
               attrs: {}

The issue happens here https://github.com/plone/plone.namedfile/blob/e8a44b8688e596a123b10a4a2e6ae48c82cdf140/plone/namedfile/scaling.py#L564-L567 where getattr(context, fieldname, None) returns the content item with id image instead of the expected field

I am not sure what the proper fix would be here... maybe ImageScaling should adapt some more specific interface than ITraversable ?

Suggestions?

davisagli commented 6 months ago

In general, things don't work out well when a contained content item has the same id as a field. Unfortunately, fixing this probably requires deep changes in Zope, to only traverse to sub-items via item access (__getitem__) and not attribute access. That would be a pretty fundamental change. It looks like Hanno tried to clean this up in 2010 but ran into some trouble because traversal prefers acquired attributes over __getitem__: https://github.com/zopefoundation/Products.BTreeFolder2/blob/master/src/Products/BTreeFolder2/BTreeFolder2.py#L233