WIP: workflows: add rich text support to history comments (#27992) #1077

Draft
fpeters wants to merge 2 commits from wip/27992-history-comment-rich into main
7 changed files with 58 additions and 10 deletions

View File

@ -1,3 +1,5 @@
import os
import pytest
from quixote import cleanup
@ -62,3 +64,17 @@ def test_display_message_rich_text(pub):
workflow.store()
resp = app.get(display_message.get_admin_url())
assert resp.pyquery('textarea[data-config]') # ckeditor
pub.site_options.set('options', 'disabled-godo-usages', 'wf-displaymsg')
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
pub.site_options.write(fd)
display_message.message = '<p>hello world</p>'
workflow.store()
resp = app.get(display_message.get_admin_url())
assert resp.pyquery('textarea[data-config]') # ckeditor
pub.site_options.set('options', 'disabled-godo-usages', 'something, else')
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
pub.site_options.write(fd)
resp = app.get(display_message.get_admin_url())
assert resp.pyquery('textarea[data-godo-schema]') # godo

View File

@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
from quixote import get_publisher, get_response, redirect
from quixote import get_publisher, get_response, get_session, redirect
from quixote.directory import Directory
from quixote.html import TemplateIO, htmltext
@ -35,7 +35,7 @@ from wcs.qommon.form import (
StringWidget,
TextWidget,
WidgetList,
get_session,
get_rich_text_widget_class,
)
@ -255,7 +255,7 @@ class CommentTemplatePage(Directory):
value=self.comment_template.description,
)
form.add(
TextWidget,
get_rich_text_widget_class(self.comment_template.comment, usage='wf-history-comment-template'),
'comment',
title=_('Comment'),
value=self.comment_template.comment,

View File

@ -17,6 +17,7 @@
from collections import defaultdict
from quixote import get_publisher
from quixote.html import htmltext
from wcs.categories import CommentTemplateCategory
from wcs.qommon import _, get_logger
@ -52,6 +53,20 @@ class CommentTemplate(XmlStorableObject):
XmlStorableObject.__init__(self)
self.name = name
def migrate(self):
changed = False
if self.comment and not self.comment.startswith('<'): # 2024-01-28
# convert to HTML
self.comment = str(
htmltext('<p>')
+ htmltext('\n').join([(x or htmltext('</p><p>')) for x in self.comment.splitlines()])
+ htmltext('</p>')
)
changed = True
if changed:
self.store(comment=_('Automatic update'), snapshot_store_user=False)
@property
def category(self):
return CommentTemplateCategory.get(self.category_id, ignore_errors=True)
@ -67,14 +82,16 @@ class CommentTemplate(XmlStorableObject):
base_url = get_publisher().get_backoffice_url()
return '%s/workflows/comment-templates/%s/' % (base_url, self.id)
def store(self, comment=None, application=None, *args, **kwargs):
def store(self, comment=None, snapshot_store_user=True, application=None, *args, **kwargs):
assert not self.is_readonly()
if self.slug is None:
# set slug if it's not yet there
self.slug = self.get_new_slug()
super().store(*args, **kwargs)
if get_publisher().snapshot_class:
get_publisher().snapshot_class.snap(instance=self, comment=comment, application=application)
get_publisher().snapshot_class.snap(
instance=self, comment=comment, store_user=snapshot_store_user, application=application
)
def get_places_of_use(self):
from wcs.workflows import Workflow

View File

@ -3972,8 +3972,14 @@ class DjangoConditionWidget(StringWidget):
self.set_error(str(e))
def get_rich_text_widget_class(content):
# use godo.js if all tags in existing content are supported
def get_rich_text_widget_class(content, usage=None):
# use godo.js if all tags in existing content are supported and it's not been disabled
# in site options for this particular usage.
disabled_godo_usage = [
x.strip() for x in get_publisher().get_site_option('disabled-godo-usages').split(',')
]
if usage in disabled_godo_usage:
return WysiwygTextWidget
tags = set(re.findall(r'<([a-z]+)[\s>]', content or ''))
if tags.issubset(set(RichTextWidget.ALL_TAGS)):
return RichTextWidget

View File

@ -446,6 +446,7 @@ class QommonPublisher(Publisher):
'relatable-hosts': '',
'sync-map-and-address-fields': 'true',
'unused-files-behaviour': 'remove',
'disabled-godo-usages': '',
},
}
if self.site_options is None:

View File

@ -112,7 +112,7 @@ class DisplayMessageWorkflowStatusItem(WorkflowStatusItem):
in_global_action = isinstance(self.parent, WorkflowGlobalAction)
if 'message' in parameters:
form.add(
get_rich_text_widget_class(self.message),
get_rich_text_widget_class(self.message, usage='wf-displaymsg'),
'%smessage' % prefix,
title=_('Message'),
value=self.message,

View File

@ -29,7 +29,7 @@ from wcs.workflows import (
)
from ..qommon import _, ezt
from ..qommon.form import SingleSelectWidget, TextWidget, WidgetListOfRoles
from ..qommon.form import SingleSelectWidget, WidgetListOfRoles, get_rich_text_widget_class
from ..qommon.template import TemplateError
@ -122,7 +122,7 @@ class RegisterCommenterWorkflowStatusItem(WorkflowStatusItem):
}
if 'comment' in parameters:
form.add(
TextWidget,
get_rich_text_widget_class(self.comment, usage='wf-history-comment-template'),
'%scomment' % prefix,
title=_('Message'),
value=self.comment,
@ -194,6 +194,14 @@ class RegisterCommenterWorkflowStatusItem(WorkflowStatusItem):
if match:
self.level, self.comment = match.groups(0)
changed = True
if self.comment and not self.comment.startswith('<'): # 2024-01-28
# convert to HTML
self.comment = str(
htmltext('<p>')
+ htmltext('\n').join([(x or htmltext('</p><p>')) for x in self.comment.splitlines()])
+ htmltext('</p>')
)
changed = True
return changed
def perform(self, formdata):