Skip to content

Commit

Permalink
Enable ZMI History tab for OFS.Image.File (#1245)
Browse files Browse the repository at this point in the history
Modernize a bit the condition to display online text editor: support
editing json inline and tolerate larger file content.
  • Loading branch information
perrinjerome authored Jan 15, 2025
1 parent 1595981 commit fbd6ce9
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 21 deletions.
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ https://github.com/zopefoundation/Zope/blob/4.x/CHANGES.rst
5.11.2 (unreleased)
-------------------

- Enable ZMI History tab for ``OFS.Image.File``.
(`#396 <https://github.com/zopefoundation/Zope/pull/396>`_)

- Fix error messages from spam/pen test requests.

- Fix a ``ResourceWarning`` emitted when uploading large files.
Expand Down
31 changes: 30 additions & 1 deletion src/OFS/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
from App.special_dtml import DTMLFile
from DateTime.DateTime import DateTime
from OFS.Cache import Cacheable
from OFS.History import Historical
from OFS.History import html_diff
from OFS.interfaces import IWriteLock
from OFS.PropertyManager import PropertyManager
from OFS.role import RoleManager
Expand Down Expand Up @@ -167,6 +169,7 @@ class File(
PropertyManager,
RoleManager,
Item_w__name__,
Historical,
Cacheable
):
"""A File object is a content object for arbitrary files."""
Expand Down Expand Up @@ -201,7 +204,9 @@ class File(
+ PropertyManager.manage_options
+ RoleManager.manage_options
+ Item_w__name__.manage_options
+ Cacheable.manage_options)
+ Cacheable.manage_options
+ Historical.manage_options
)

_properties = (
{'id': 'title', 'type': 'string'},
Expand Down Expand Up @@ -657,6 +662,30 @@ def manage_upload(self, file='', REQUEST=None):
return self.manage_main(
self, REQUEST, manage_tabs_message=msg)

@security.protected(change_images_and_files)
def manage_is_editable_inline(self):
return (
self.content_type
and (
self.content_type.startswith('text')
or self.content_type.endswith('javascript')
or self.content_type == 'application/json'
)
and self.get_size() < 2**17
)

def manage_historyCompare(self, rev1, rev2, REQUEST,
historyComparisonResults=''):
if self.manage_is_editable_inline():
return File.inheritedAttribute('manage_historyCompare')(
self, rev1, rev2, REQUEST,
historyComparisonResults=html_diff(
str(rev1), str(rev2)))
return File.inheritedAttribute('manage_historyCompare')(
self, rev1, rev2, REQUEST,
historyComparisonResults=historyComparisonResults
)

def _get_content_type(self, file, body, id, content_type=None):
headers = getattr(file, 'headers', None)
if headers and 'content-type' in headers:
Expand Down
38 changes: 18 additions & 20 deletions src/OFS/dtml/fileEdit.dtml
Original file line number Diff line number Diff line change
Expand Up @@ -38,28 +38,26 @@
</div>
</div>

<dtml-let ct=getContentType>
<dtml-if "(ct.startswith('text') or ct.endswith('javascript')) and this().get_size() < 65536">
<div class="form-group">
<dtml-try>
<textarea id="content" <dtml-if content_type>data-contenttype="&dtml-content_type;"</dtml-if>
class="form-control zmi-file zmi-code col-sm-12"
name="filedata:text" wrap="off" rows="20"><dtml-var __str__ html_quote></textarea>
<dtml-except UnicodeDecodeError>
<div class="alert alert-warning" role="alert">
The file could not be decoded with '<dtml-var "error_value.encoding">'.
</div>
</dtml-try>
</div>
<dtml-else>
<div class="form-group row">
<label for="size" class="form-label col-sm-3 col-md-2">File Size</label>
<div class="form-text col-sm-9 col-md-10">
<dtml-var size thousands_commas> bytes
<dtml-if manage_is_editable_inline>
<div class="form-group">
<dtml-try>
<textarea id="content" <dtml-if content_type>data-contenttype="&dtml-content_type;"</dtml-if>
class="form-control zmi-file zmi-code col-sm-12"
name="filedata:text" wrap="off" rows="20"><dtml-var __str__ html_quote></textarea>
<dtml-except UnicodeDecodeError>
<div class="alert alert-warning" role="alert">
The file could not be decoded with '<dtml-var "error_value.encoding">'.
</div>
</dtml-try>
</div>
<dtml-else>
<div class="form-group row">
<label for="size" class="form-label col-sm-3 col-md-2">File Size</label>
<div class="form-text col-sm-9 col-md-10">
<dtml-var size thousands_commas> bytes
</div>
</dtml-if>
</dtml-let>
</div>
</dtml-if>

<div class="zmi-controls">
<dtml-if wl_isLocked>
Expand Down
13 changes: 13 additions & 0 deletions src/OFS/tests/testFileAndImage.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,3 +517,16 @@ def test_Image__manage_edit__1(self):
self.assertIn('Saved changes', self.browser.contents)
text_2 = self.browser.getControl(name='filedata:text').value
self.assertEqual(text_2, 'hällo')

def test_File__manage_history(self):
self.app.file.update_data('beföre'.encode())
transaction.commit()
self.app.file.update_data('àftér'.encode())
transaction.commit()
self.browser.open('http://localhost/file/manage_main')
self.browser.getLink('History').click()
keys = self.browser.getControl(name='keys:list')
keys.value = [keys.options[0], keys.options[1]]
self.browser.getControl('Compare').click()
self.assertIn('beföre', self.browser.contents)
self.assertIn('àftér', self.browser.contents)

0 comments on commit fbd6ce9

Please sign in to comment.