Skip to content

Commit

Permalink
Enable ZMI History tab for OFS.Image.File
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 content
  • Loading branch information
perrinjerome committed Jan 14, 2025
1 parent 1595981 commit c7f9c55
Show file tree
Hide file tree
Showing 4 changed files with 68 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
32 changes: 31 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,31 @@ 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.data),
str(rev2.data)))
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
16 changes: 16 additions & 0 deletions src/OFS/tests/testFileAndImage.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,22 @@ def test_text_representation_is_tag(self):
'<img src="http://nohost/file"'
' alt="" title="" height="16" width="16" />')

def test_history_compare(self):
self.file.manage_edit('a', 'text/plain',
filedata='content of a')
getattr(
self.app,
self.factory)(
'b',
file='content_of_b',
content_type='text/plain')
page = self.file.manage_historyCompare(
self.file,
self.app.b,
self.app.REQUEST)
self.assertIn('content_of_a', page)
self.assertIn('content_of_b', page)


class SVGTests(ImageTests):
content_type = 'image/svg+xml'
Expand Down

0 comments on commit c7f9c55

Please sign in to comment.