workflows: move all actions to their own files (#64722)

This commit is contained in:
Frédéric Péters 2022-05-01 09:32:17 +02:00
parent 483a5e7ffa
commit 9de9af6ad3
29 changed files with 786 additions and 668 deletions

View File

@ -13,7 +13,9 @@ from wcs.formdef import FormDef
from wcs.qommon.form import UploadedFile
from wcs.qommon.http_request import HTTPRequest
from wcs.wf.backoffice_fields import SetBackofficeFieldsWorkflowStatusItem
from wcs.wf.choice import ChoiceWorkflowStatusItem
from wcs.wf.create_formdata import CreateFormdataWorkflowStatusItem, Mapping
from wcs.wf.display_message import DisplayMessageWorkflowStatusItem
from wcs.wf.export_to_model import ExportToModel
from wcs.wf.external_workflow import ExternalWorkflowGlobalAction
from wcs.wf.form import FormWorkflowStatusItem, WorkflowFormFieldsFormDef
@ -23,13 +25,9 @@ from wcs.wf.notification import SendNotificationWorkflowStatusItem
from wcs.wf.profile import UpdateUserProfileStatusItem
from wcs.wf.redirect_to_url import RedirectToUrlWorkflowStatusItem
from wcs.wf.sendmail import SendmailWorkflowStatusItem
from wcs.wf.sms import SendSMSWorkflowStatusItem
from wcs.wf.wscall import WebserviceCallStatusItem
from wcs.workflows import (
ChoiceWorkflowStatusItem,
DisplayMessageWorkflowStatusItem,
SendSMSWorkflowStatusItem,
Workflow,
)
from wcs.workflows import Workflow
from wcs.wscalls import NamedWsCall
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login

View File

@ -23,8 +23,9 @@ from wcs.formdef import FormDef
from wcs.qommon.form import UploadedFile
from wcs.qommon.http_request import HTTPRequest
from wcs.qommon.template import get_current_theme
from wcs.wf.comment import CommentableWorkflowStatusItem
from wcs.wf.export_to_model import ExportToModel
from wcs.workflows import CommentableWorkflowStatusItem, Workflow
from wcs.workflows import Workflow
from wcs.wscalls import NamedWsCall
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login

View File

@ -17,25 +17,25 @@ from wcs.qommon.errors import ConnectionError
from wcs.qommon.form import UploadedFile
from wcs.qommon.http_request import HTTPRequest
from wcs.wf.assign_carddata import AssignCarddataWorkflowStatusItem
from wcs.wf.choice import ChoiceWorkflowStatusItem
from wcs.wf.comment import CommentableWorkflowStatusItem
from wcs.wf.create_carddata import CreateCarddataWorkflowStatusItem
from wcs.wf.create_formdata import CreateFormdataWorkflowStatusItem, Mapping
from wcs.wf.dispatch import DispatchWorkflowStatusItem
from wcs.wf.display_message import DisplayMessageWorkflowStatusItem
from wcs.wf.edit_carddata import EditCarddataWorkflowStatusItem
from wcs.wf.export_to_model import ExportToModel
from wcs.wf.external_workflow import ExternalWorkflowGlobalAction
from wcs.wf.form import FormWorkflowStatusItem, WorkflowFormFieldsFormDef
from wcs.wf.jump import JumpWorkflowStatusItem
from wcs.wf.jump_on_submit import JumpOnSubmitWorkflowStatusItem
from wcs.wf.redirect_to_url import RedirectToUrlWorkflowStatusItem
from wcs.wf.register_comment import RegisterCommenterWorkflowStatusItem
from wcs.wf.remove_tracking_code import RemoveTrackingCodeWorkflowStatusItem
from wcs.wf.roles import AddRoleWorkflowStatusItem, RemoveRoleWorkflowStatusItem
from wcs.wf.sendmail import SendmailWorkflowStatusItem
from wcs.wf.wscall import WebserviceCallStatusItem
from wcs.workflows import (
ChoiceWorkflowStatusItem,
CommentableWorkflowStatusItem,
DisplayMessageWorkflowStatusItem,
JumpOnSubmitWorkflowStatusItem,
SendmailWorkflowStatusItem,
Workflow,
WorkflowBackofficeFieldsFormDef,
WorkflowCriticalityLevel,

View File

@ -13,12 +13,8 @@ from wcs.fields import BlockField, StringField
from wcs.formdef import FormDef
from wcs.mail_templates import MailTemplate
from wcs.wf.form import FormWorkflowStatusItem, WorkflowFormFieldsFormDef
from wcs.workflows import (
SendmailWorkflowStatusItem,
Workflow,
WorkflowBackofficeFieldsFormDef,
WorkflowVariablesFieldsFormDef,
)
from wcs.wf.sendmail import SendmailWorkflowStatusItem
from wcs.workflows import Workflow, WorkflowBackofficeFieldsFormDef, WorkflowVariablesFieldsFormDef
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app
from .utils import sign_uri

View File

@ -23,13 +23,9 @@ from wcs.qommon import ods
from wcs.qommon.http_request import HTTPRequest
from wcs.qommon.ident.password_accounts import PasswordAccount
from wcs.qommon.upload_storage import PicklableUpload
from wcs.wf.editable import EditableWorkflowStatusItem
from wcs.wf.register_comment import RegisterCommenterWorkflowStatusItem
from wcs.workflows import (
AttachmentEvolutionPart,
EditableWorkflowStatusItem,
Workflow,
WorkflowBackofficeFieldsFormDef,
)
from wcs.workflows import AttachmentEvolutionPart, Workflow, WorkflowBackofficeFieldsFormDef
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login
from .utils import sign_uri

View File

@ -22,25 +22,21 @@ from wcs.qommon.ident.password_accounts import PasswordAccount
from wcs.qommon.upload_storage import PicklableUpload
from wcs.roles import logged_users_role
from wcs.wf.backoffice_fields import SetBackofficeFieldsWorkflowStatusItem
from wcs.wf.choice import ChoiceWorkflowStatusItem
from wcs.wf.comment import CommentableWorkflowStatusItem
from wcs.wf.create_carddata import CreateCarddataWorkflowStatusItem
from wcs.wf.create_formdata import CreateFormdataWorkflowStatusItem, Mapping
from wcs.wf.dispatch import DispatchWorkflowStatusItem
from wcs.wf.display_message import DisplayMessageWorkflowStatusItem
from wcs.wf.editable import EditableWorkflowStatusItem
from wcs.wf.form import FormWorkflowStatusItem, WorkflowFormFieldsFormDef
from wcs.wf.jump import JumpWorkflowStatusItem
from wcs.wf.jump_on_submit import JumpOnSubmitWorkflowStatusItem
from wcs.wf.redirect_to_url import RedirectToUrlWorkflowStatusItem
from wcs.wf.register_comment import RegisterCommenterWorkflowStatusItem
from wcs.wf.resubmit import ResubmitWorkflowStatusItem
from wcs.wf.wscall import WebserviceCallStatusItem
from wcs.workflows import (
ChoiceWorkflowStatusItem,
CommentableWorkflowStatusItem,
DisplayMessageWorkflowStatusItem,
EditableWorkflowStatusItem,
JumpOnSubmitWorkflowStatusItem,
Workflow,
WorkflowBackofficeFieldsFormDef,
WorkflowCriticalityLevel,
)
from wcs.workflows import Workflow, WorkflowBackofficeFieldsFormDef, WorkflowCriticalityLevel
from wcs.wscalls import NamedWsCall
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login

View File

@ -11,8 +11,9 @@ from wcs.carddef import CardDef
from wcs.categories import CardDefCategory
from wcs.formdef import FormDef
from wcs.qommon.http_request import HTTPRequest
from wcs.wf.choice import ChoiceWorkflowStatusItem
from wcs.wf.wscall import WebserviceCallStatusItem
from wcs.workflows import ChoiceWorkflowStatusItem, Workflow
from wcs.workflows import Workflow
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login
from .test_all import create_superuser, create_user

View File

@ -30,20 +30,20 @@ from wcs.qommon.template import Template
from wcs.roles import logged_users_role
from wcs.tracking_code import TrackingCode
from wcs.wf.backoffice_fields import SetBackofficeFieldsWorkflowStatusItem
from wcs.wf.choice import ChoiceWorkflowStatusItem
from wcs.wf.comment import CommentableWorkflowStatusItem
from wcs.wf.create_formdata import CreateFormdataWorkflowStatusItem, Mapping
from wcs.wf.display_message import DisplayMessageWorkflowStatusItem
from wcs.wf.editable import EditableWorkflowStatusItem
from wcs.wf.form import FormWorkflowStatusItem, WorkflowFormFieldsFormDef
from wcs.wf.jump import JumpWorkflowStatusItem
from wcs.wf.jump_on_submit import JumpOnSubmitWorkflowStatusItem
from wcs.wf.redirect_to_url import RedirectToUrlWorkflowStatusItem
from wcs.wf.register_comment import RegisterCommenterWorkflowStatusItem
from wcs.wf.resubmit import ResubmitWorkflowStatusItem
from wcs.wf.wscall import JournalWsCallErrorPart
from wcs.workflows import (
AttachmentEvolutionPart,
ChoiceWorkflowStatusItem,
CommentableWorkflowStatusItem,
DisplayMessageWorkflowStatusItem,
EditableWorkflowStatusItem,
JumpOnSubmitWorkflowStatusItem,
Workflow,
WorkflowBackofficeFieldsFormDef,
WorkflowVariablesFieldsFormDef,

View File

@ -11,7 +11,8 @@ from wcs.categories import Category
from wcs.data_sources import NamedDataSource
from wcs.formdef import FormDef
from wcs.wf.form import FormWorkflowStatusItem, WorkflowFormFieldsFormDef
from wcs.workflows import JumpOnSubmitWorkflowStatusItem, Workflow
from wcs.wf.jump_on_submit import JumpOnSubmitWorkflowStatusItem
from wcs.workflows import Workflow
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login
from .test_all import create_user

View File

@ -8,7 +8,8 @@ from wcs import fields
from wcs.carddef import CardDef
from wcs.formdef import FormDef
from wcs.qommon.substitution import CompatibilityNamesDict
from wcs.workflows import EditableWorkflowStatusItem, Workflow
from wcs.wf.editable import EditableWorkflowStatusItem
from wcs.workflows import Workflow
from wcs.wscalls import NamedWsCall
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login

View File

@ -18,16 +18,13 @@ from wcs.formdef import FormDef
from wcs.qommon.form import UploadedFile
from wcs.qommon.misc import ConnectionError
from wcs.wf.attachment import AddAttachmentWorkflowStatusItem
from wcs.wf.choice import ChoiceWorkflowStatusItem
from wcs.wf.display_message import DisplayMessageWorkflowStatusItem
from wcs.wf.export_to_model import ExportToModel, transform_to_pdf
from wcs.wf.form import FormWorkflowStatusItem, WorkflowFormFieldsFormDef
from wcs.wf.jump import JumpWorkflowStatusItem
from wcs.wf.register_comment import RegisterCommenterWorkflowStatusItem
from wcs.workflows import (
ChoiceWorkflowStatusItem,
DisplayMessageWorkflowStatusItem,
Workflow,
WorkflowBackofficeFieldsFormDef,
)
from wcs.workflows import Workflow, WorkflowBackofficeFieldsFormDef
from wcs.wscalls import NamedWsCall
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login

View File

@ -15,7 +15,8 @@ from wcs.qommon.http_request import HTTPRequest
from wcs.qommon.ident.password_accounts import PasswordAccount
from wcs.qommon.misc import indent_xml as indent
from wcs.qommon.upload_storage import PicklableUpload
from wcs.workflows import SendmailWorkflowStatusItem, Workflow
from wcs.wf.sendmail import SendmailWorkflowStatusItem
from wcs.workflows import Workflow
from .utilities import clean_temporary_pub, create_temporary_pub, get_app, login

View File

@ -28,7 +28,8 @@ from wcs.qommon.form import UploadedFile
from wcs.qommon.http_request import HTTPRequest
from wcs.qommon.publisher import Tenant
from wcs.wf.export_to_model import ExportToModel
from wcs.workflows import SendmailWorkflowStatusItem, Workflow
from wcs.wf.sendmail import SendmailWorkflowStatusItem
from wcs.workflows import Workflow
from .utilities import create_temporary_pub

View File

@ -14,9 +14,10 @@ from wcs.blocks import BlockDef
from wcs.formdata import Evolution
from wcs.formdef import FormDef
from wcs.qommon import force_str
from wcs.wf.comment import CommentableWorkflowStatusItem
from wcs.wf.jump import JumpWorkflowStatusItem
from wcs.wf.register_comment import RegisterCommenterWorkflowStatusItem
from wcs.workflows import CommentableWorkflowStatusItem, Workflow, WorkflowCriticalityLevel
from wcs.workflows import Workflow, WorkflowCriticalityLevel
from .utilities import clean_temporary_pub, create_temporary_pub

View File

@ -15,23 +15,23 @@ from wcs.qommon.form import UploadedFile
from wcs.qommon.misc import indent_xml as indent
from wcs.wf.attachment import AddAttachmentWorkflowStatusItem
from wcs.wf.backoffice_fields import SetBackofficeFieldsWorkflowStatusItem
from wcs.wf.choice import ChoiceWorkflowStatusItem
from wcs.wf.comment import CommentableWorkflowStatusItem
from wcs.wf.create_formdata import CreateFormdataWorkflowStatusItem, Mapping
from wcs.wf.dispatch import DispatchWorkflowStatusItem
from wcs.wf.display_message import DisplayMessageWorkflowStatusItem
from wcs.wf.export_to_model import ExportToModel
from wcs.wf.external_workflow import ExternalWorkflowGlobalAction
from wcs.wf.form import FormWorkflowStatusItem, WorkflowFormFieldsFormDef
from wcs.wf.jump import JumpWorkflowStatusItem
from wcs.wf.jump_on_submit import JumpOnSubmitWorkflowStatusItem
from wcs.wf.profile import UpdateUserProfileStatusItem
from wcs.wf.redirect_to_url import RedirectToUrlWorkflowStatusItem
from wcs.wf.register_comment import RegisterCommenterWorkflowStatusItem
from wcs.wf.sendmail import SendmailWorkflowStatusItem
from wcs.wf.sms import SendSMSWorkflowStatusItem
from wcs.wf.wscall import WebserviceCallStatusItem
from wcs.workflows import (
ChoiceWorkflowStatusItem,
CommentableWorkflowStatusItem,
DisplayMessageWorkflowStatusItem,
JumpOnSubmitWorkflowStatusItem,
SendmailWorkflowStatusItem,
SendSMSWorkflowStatusItem,
Workflow,
WorkflowBackofficeFieldsFormDef,
WorkflowCriticalityLevel,

View File

@ -56,10 +56,13 @@ from wcs.wf.aggregation_email import (
)
from wcs.wf.anonymise import AnonymiseWorkflowStatusItem
from wcs.wf.backoffice_fields import SetBackofficeFieldsWorkflowStatusItem
from wcs.wf.choice import ChoiceWorkflowStatusItem
from wcs.wf.comment import CommentableWorkflowStatusItem
from wcs.wf.create_carddata import CreateCarddataWorkflowStatusItem
from wcs.wf.create_formdata import CreateFormdataWorkflowStatusItem, Mapping
from wcs.wf.criticality import MODE_DEC, MODE_INC, MODE_SET, ModifyCriticalityWorkflowStatusItem
from wcs.wf.dispatch import DispatchWorkflowStatusItem
from wcs.wf.display_message import DisplayMessageWorkflowStatusItem
from wcs.wf.export_to_model import ExportToModel, transform_to_pdf
from wcs.wf.external_workflow import ManyExternalCallsPart
from wcs.wf.form import FormWorkflowStatusItem, WorkflowFormFieldsFormDef
@ -71,16 +74,13 @@ from wcs.wf.register_comment import JournalEvolutionPart, RegisterCommenterWorkf
from wcs.wf.remove import RemoveWorkflowStatusItem
from wcs.wf.remove_tracking_code import RemoveTrackingCodeWorkflowStatusItem
from wcs.wf.roles import AddRoleWorkflowStatusItem, RemoveRoleWorkflowStatusItem
from wcs.wf.sendmail import SendmailWorkflowStatusItem
from wcs.wf.sms import SendSMSWorkflowStatusItem
from wcs.wf.timeout_jump import TimeoutWorkflowStatusItem
from wcs.wf.wscall import WebserviceCallStatusItem
from wcs.workflows import (
AbortActionException,
AttachmentEvolutionPart,
ChoiceWorkflowStatusItem,
CommentableWorkflowStatusItem,
DisplayMessageWorkflowStatusItem,
SendmailWorkflowStatusItem,
SendSMSWorkflowStatusItem,
Workflow,
WorkflowBackofficeFieldsFormDef,
WorkflowCriticalityLevel,

View File

@ -14,7 +14,8 @@ from wcs.qommon.substitution import CompatibilityNamesDict
from wcs.qommon.upload_storage import PicklableUpload
from wcs.wf.backoffice_fields import SetBackofficeFieldsWorkflowStatusItem
from wcs.wf.dispatch import DispatchWorkflowStatusItem
from wcs.workflows import SendmailWorkflowStatusItem, Workflow, WorkflowBackofficeFieldsFormDef
from wcs.wf.sendmail import SendmailWorkflowStatusItem
from wcs.workflows import Workflow, WorkflowBackofficeFieldsFormDef
from ..utilities import MockSubstitutionVariables, clean_temporary_pub, create_temporary_pub

View File

@ -7,7 +7,8 @@ from wcs.fields import EmailField, ItemField, StringField
from wcs.formdef import FormDef
from wcs.qommon.http_request import HTTPRequest
from wcs.wf.create_formdata import CreateFormdataWorkflowStatusItem, Mapping
from wcs.workflows import SendmailWorkflowStatusItem, Workflow
from wcs.wf.sendmail import SendmailWorkflowStatusItem
from wcs.workflows import Workflow
from ..utilities import clean_temporary_pub, create_temporary_pub

View File

@ -92,8 +92,10 @@ class CardDef(FormDef):
@classmethod
def get_default_workflow(cls):
from wcs.wf.choice import ChoiceWorkflowStatusItem
from wcs.wf.editable import EditableWorkflowStatusItem
from wcs.wf.remove import RemoveWorkflowStatusItem
from wcs.workflows import ChoiceWorkflowStatusItem, EditableWorkflowStatusItem, Workflow
from wcs.workflows import Workflow
workflow = Workflow(name=force_text(_('Default (cards)')))
workflow.id = '_carddef_default'

View File

@ -194,7 +194,7 @@ class Evolution:
return self._display_parts
def get_plain_text_comment(self):
from .workflows import WorkflowCommentPart
from wcs.wf.comment import WorkflowCommentPart
for part in reversed(self.parts or []):
if isinstance(part, WorkflowCommentPart):

View File

@ -28,7 +28,8 @@ from wcs import data_sources
from wcs.api_utils import get_query_flag, get_user_from_api_query_string, is_url_signed, sign_url_auto_orig
from wcs.blocks import BlockSubWidget, BlockWidget
from wcs.qommon.admin.texts import TextsDirectory
from wcs.workflows import EditableWorkflowStatusItem, RedisplayFormException
from wcs.wf.editable import EditableWorkflowStatusItem
from wcs.workflows import RedisplayFormException
from ..qommon import _, errors, misc, template

View File

@ -52,6 +52,19 @@ class UnpicklerClass(pickle.Unpickler):
module = 'wcs.qommon.form'
elif module in ('formdata', 'formdef', 'roles', 'users', 'workflows'):
module = 'wcs.%s' % module
module_moves = {
('wcs.workflows', 'ChoiceWorkflowStatusItem'): 'wcs.wf.choice',
('wcs.workflows', 'CommentableWorkflowStatusItem'): 'wcs.wf.comment',
('wcs.workflows', 'DisplayMessageWorkflowStatusItem'): 'wcs.wf.display_message',
('wcs.workflows', 'EditableWorkflowStatusItem'): 'wcs.wf.editable',
('wcs.workflows', 'ExportToModel'): 'wcs.wf.export_to_model',
('wcs.workflows', 'JumpOnSubmitWorkflowStatusItem'): 'wcs.wf.jump_on_submit',
('wcs.workflows', 'RedirectToStatusWorkflowStatusItem'): 'wcs.wf.redirect_to_status',
('wcs.workflows', 'SendmailWorkflowStatusItem'): 'wcs.wf.sendmail',
('wcs.workflows', 'SendSMSWorkflowStatusItem'): 'wcs.wf.sms',
('wcs.workflows', 'WorkflowCommentPart'): 'wcs.wf.comment',
}
module = module_moves.get((module, name), module)
__import__(module)
mod = sys.modules[module]
if module == 'wcs.formdef' and name != 'FormDef' and not name.startswith('_wcs_'):

178
wcs/wf/choice.py Normal file
View File

@ -0,0 +1,178 @@
# w.c.s. - web application for online forms
# Copyright (C) 2005-2022 Entr'ouvert
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# 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_response
from wcs.qommon import _
from wcs.qommon.form import (
CheckboxWidget,
ComputedExpressionWidget,
SingleSelectWidget,
VarnameWidget,
WidgetList,
WysiwygTextWidget,
)
from wcs.workflows import WorkflowStatus, WorkflowStatusJumpItem, register_item_class
class ChoiceWorkflowStatusItem(WorkflowStatusJumpItem):
description = _('Manual Jump')
key = 'choice'
endpoint = False
waitpoint = True
ok_in_global_action = False
label = None
identifier = None
by = []
backoffice_info_text = None
require_confirmation = False
ignore_form_errors = False
def get_label(self):
expression = self.get_expression(self.label, allow_python=False, allow_ezt=False)
if expression['type'] == 'text':
return expression['value']
return _('computed label')
def get_line_details(self):
to_status = None
if self.status == '_previous':
to_status = WorkflowStatus(_('previously marked status'))
elif self.status:
try:
to_status = self.parent.parent.get_status(self.status)
except KeyError:
return _('broken, missing destination status')
if self.label and to_status:
more = ''
if self.set_marker_on_status:
more += ' ' + str(_('(and set marker)'))
if self.by:
return _('"%(label)s", to %(to)s, by %(by)s%(more)s') % {
'label': self.get_label(),
'to': to_status.name,
'by': self.render_list_of_roles(self.by),
'more': more,
}
else:
return _('"%(label)s", to %(to)s%(more)s') % {
'label': self.get_label(),
'to': to_status.name,
'more': more,
}
else:
return _('not completed')
def get_computed_strings(self):
yield from super().get_computed_strings()
if self.get_expression(self.label, allow_python=False, allow_ezt=False)['type'] != 'text':
yield self.label
def fill_form(self, form, formdata, user, **kwargs):
label = self.compute(self.label, allow_python=False, allow_ezt=False)
if not label:
return
widget = form.add_submit('button%s' % self.id, label)
if self.identifier:
widget.extra_css_class = 'button-%s' % self.identifier
if self.require_confirmation:
get_response().add_javascript(['jquery.js', '../../i18n.js', 'qommon.js'])
widget.attrs = {'data-ask-for-confirmation': 'true'}
widget.backoffice_info_text = self.backoffice_info_text
widget.ignore_form_errors = self.ignore_form_errors
if self.ignore_form_errors:
widget.attrs['formnovalidate'] = 'formnovalidate'
def submit_form(self, form, formdata, user, evo):
if form.get_submit() == 'button%s' % self.id:
wf_status = self.get_target_status(formdata)
if wf_status:
evo.status = 'wf-%s' % wf_status[0].id
self.handle_markers_stack(formdata)
form.clear_errors()
return True # get out of processing loop
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None, **kwargs):
super().add_parameters_widgets(form, parameters, prefix=prefix, formdef=formdef, **kwargs)
if 'label' in parameters:
form.add(
ComputedExpressionWidget,
'%slabel' % prefix,
title=_('Label'),
value=self.label,
allow_python=False,
)
if 'by' in parameters:
form.add(
WidgetList,
'%sby' % prefix,
title=_('By'),
element_type=SingleSelectWidget,
value=self.by,
add_element_label=self.get_add_role_label(),
element_kwargs={
'render_br': False,
'options': [(None, '---', None)] + self.get_list_of_roles(),
},
)
if 'require_confirmation' in parameters:
form.add(
CheckboxWidget,
'%srequire_confirmation' % prefix,
title=_('Require confirmation'),
value=self.require_confirmation,
)
if 'backoffice_info_text' in parameters:
form.add(
WysiwygTextWidget,
'%sbackoffice_info_text' % prefix,
title=_('Information Text for Backoffice'),
value=self.backoffice_info_text,
)
if 'identifier' in parameters:
form.add(
VarnameWidget,
'%sidentifier' % prefix,
title=_('Identifier'),
value=self.identifier,
advanced=True,
)
if 'ignore_form_errors' in parameters:
form.add(
CheckboxWidget,
'%signore_form_errors' % prefix,
title=_('Ignore form errors'),
value=self.ignore_form_errors,
advanced=True,
)
def get_parameters(self):
return (
'label',
'by',
'status',
'require_confirmation',
'backoffice_info_text',
'ignore_form_errors',
'set_marker_on_status',
'condition',
'identifier',
)
register_item_class(ChoiceWorkflowStatusItem)

194
wcs/wf/comment.py Normal file
View File

@ -0,0 +1,194 @@
# w.c.s. - web application for online forms
# Copyright (C) 2005-2022 Entr'ouvert
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
import html
import xml.etree.ElementTree as ET
from django.utils.html import strip_tags
from quixote.html import htmltext
from wcs.qommon import _
from wcs.qommon.form import (
CheckboxWidget,
MiniRichTextWidget,
SingleSelectWidget,
StringWidget,
VarnameWidget,
WidgetList,
WysiwygTextWidget,
)
from wcs.qommon.misc import xml_node_text
from wcs.workflows import EvolutionPart, WorkflowStatusItem, register_item_class
class WorkflowCommentPart(EvolutionPart):
def __init__(self, comment, varname=None):
self.comment = comment
self.varname = varname
def get_as_plain_text(self):
return html.unescape(strip_tags(self.comment.replace('</p><p>', '\n\n').replace('<br>', '\n')))
def view(self):
return htmltext('<div class="comment">%s</div>' % self.comment)
class CommentableWorkflowStatusItem(WorkflowStatusItem):
description = _('Comment')
key = 'commentable'
category = 'interaction'
endpoint = False
waitpoint = True
ok_in_global_action = False
required = False
varname = None
label = None
button_label = 0 # hack to handle legacy commentable items
hint = None
by = []
backoffice_info_text = None
def get_line_details(self):
if self.by:
return _('by %s') % self.render_list_of_roles(self.by)
else:
return _('not completed')
def fill_form(self, form, formdata, user, **kwargs):
if 'comment' not in [x.name for x in form.widgets]:
if self.label is None:
title = _('Comment')
else:
title = self.label
form.add(
MiniRichTextWidget,
'comment',
title=title,
required=self.required,
hint=self.hint,
cols=40,
rows=7,
class_='comment',
)
if self.button_label == 0:
form.add_submit('button%s' % self.id, _('Add Comment'))
elif self.button_label:
form.add_submit('button%s' % self.id, self.button_label)
if form.get_widget('button%s' % self.id):
form.get_widget('button%s' % self.id).backoffice_info_text = self.backoffice_info_text
def submit_form(self, form, formdata, user, evo):
widget = form.get_widget('comment')
if widget and widget.parse() and not getattr(widget, 'processed', False):
widget.processed = True
comment = widget.parse()
comment_part = WorkflowCommentPart(comment, varname=self.varname)
evo.add_part(comment_part)
if self.varname:
formdata.update_workflow_data({'comment_%s' % self.varname: comment_part.get_as_plain_text()})
def submit_admin_form(self, form):
for f in self.get_parameters():
widget = form.get_widget(f)
setattr(self, f, widget.parse())
def fill_admin_form(self, form):
if self.by and not isinstance(self.by, list):
self.by = None
return super().fill_admin_form(form)
def get_parameters(self):
return (
'label',
'button_label',
'hint',
'by',
'varname',
'backoffice_info_text',
'required',
'condition',
)
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None, **kwargs):
super().add_parameters_widgets(form, parameters, prefix=prefix, formdef=formdef, **kwargs)
if 'label' in parameters:
if self.label is None:
self.label = str(_('Comment'))
form.add(StringWidget, '%slabel' % prefix, size=40, title=_('Label'), value=self.label)
if 'button_label' in parameters:
if self.button_label == 0:
self.button_label = str(_('Add Comment'))
form.add(
StringWidget,
'%sbutton_label' % prefix,
title=_('Button Label'),
hint=_('(empty to disable the button)'),
value=self.button_label,
)
if 'hint' in parameters:
form.add(StringWidget, '%shint' % prefix, size=40, title=_('Hint'), value=self.hint)
if 'by' in parameters:
form.add(
WidgetList,
'%sby' % prefix,
title=_('By'),
element_type=SingleSelectWidget,
value=self.by,
add_element_label=self.get_add_role_label(),
element_kwargs={
'render_br': False,
'options': [(None, '---', None)] + self.get_list_of_roles(),
},
)
if 'varname' in parameters:
form.add(
VarnameWidget,
'%svarname' % prefix,
title=_('Identifier'),
value=self.varname,
hint=_('This will make the comment available in a variable named comment_ + identifier.'),
)
if 'required' in parameters:
form.add(CheckboxWidget, '%srequired' % prefix, title=_('Required'), value=self.required)
if 'backoffice_info_text' in parameters:
form.add(
WysiwygTextWidget,
'%sbackoffice_info_text' % prefix,
title=_('Information Text for Backoffice'),
value=self.backoffice_info_text,
)
def button_label_export_to_xml(self, xml_item, charset, include_id=False):
if self.button_label == 0:
pass
elif self.button_label is None:
# button_label being None is a special case meaning "no button", it
# should be handled differently than the "not filled" case
el = ET.SubElement(xml_item, 'button_label')
else:
el = ET.SubElement(xml_item, 'button_label')
el.text = self.button_label
def button_label_init_with_xml(self, element, charset, include_id=False, snapshot=False):
if element is None:
return
# this can be None if element is self-closing, <button_label />, which
# then maps to None, meaning "no button".
self.button_label = xml_node_text(element)
register_item_class(CommentableWorkflowStatusItem)

137
wcs/wf/display_message.py Normal file
View File

@ -0,0 +1,137 @@
# w.c.s. - web application for online forms
# Copyright (C) 2005-2022 Entr'ouvert
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
import copy
from quixote import get_publisher
from quixote.html import htmltext
from wcs.qommon import _, ezt, misc
from wcs.qommon.form import ComputedExpressionWidget, SingleSelectWidget, TextWidget, WidgetListOfRoles
from wcs.qommon.template import Template
from wcs.workflows import WorkflowStatusItem, register_item_class
class DisplayMessageWorkflowStatusItem(WorkflowStatusItem):
description = _('Alert')
key = 'displaymsg'
category = 'interaction'
support_substitution_variables = True
ok_in_global_action = False
to = None
position = 'top'
level = None
message = None
def get_line_details(self):
parts = []
if self.position == 'top':
parts.append(_('top of page'))
elif self.position == 'bottom':
parts.append(_('bottom of page'))
elif self.position == 'actions':
parts.append(_('with actions'))
if self.to:
parts.append(_('for %s') % self.render_list_of_roles(self.to))
return ', '.join([str(x) for x in parts])
def get_computed_strings(self):
yield from super().get_computed_strings()
yield self.message
def get_message(self, filled, position='top'):
if not (self.message and self.position == position and filled.is_for_current_user(self.to)):
return ''
dict = copy.copy(get_publisher().substitutions.get_context_variables('lazy'))
dict['date'] = misc.localstrftime(filled.receipt_time)
dict['number'] = filled.id
handling_role = filled.get_handling_role()
if handling_role and handling_role.details:
dict['receiver'] = handling_role.details.replace('\n', '<br />')
message = self.message
if self.level:
message = '<div class="%snotice">%s</div>' % (self.level, message)
try:
return Template(message, ezt_format=ezt.FORMAT_HTML).render(dict)
except Exception as e:
get_publisher().record_error(
error_summary=_('Error in template of workflow message (%s)') % e, exception=e, notify=True
)
return '<div class="errornotice">%s</div>' % _('Error rendering message.')
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None, **kwargs):
super().add_parameters_widgets(form, parameters, prefix=prefix, formdef=formdef, **kwargs)
if 'message' in parameters:
form.add(
TextWidget,
'%smessage' % prefix,
title=_('Message'),
value=self.message,
cols=80,
rows=10,
validation_function=ComputedExpressionWidget.validate_template,
)
if 'level' in parameters:
form.add(
SingleSelectWidget,
'%slevel' % prefix,
title=_('Level'),
value=self.level,
options=[
(None, ''),
('success', _('Success')),
('info', _('Information')),
('warning', _('Warning')),
('error', _('Error')),
],
)
if 'position' in parameters:
form.add(
SingleSelectWidget,
'%sposition' % prefix,
title=_('Position'),
value=self.position,
options=[
('top', _('Top of page')),
('bottom', _('Bottom of page')),
# ('actions', _('With actions')) "too complicated"
],
)
if 'to' in parameters:
form.add(
WidgetListOfRoles,
'%sto' % prefix,
title=_('To'),
value=self.to or [],
add_element_label=self.get_add_role_label(),
first_element_empty_label=_('Everybody'),
roles=self.get_list_of_roles(include_logged_in_users=False),
)
def get_parameters(self):
return ('message', 'level', 'position', 'to', 'condition')
def get_message_parameter_view_value(self):
if self.message.startswith('<'):
return htmltext(self.message)
return htmltext('<pre>%s</pre>') % self.message
register_item_class(DisplayMessageWorkflowStatusItem)

94
wcs/wf/editable.py Normal file
View File

@ -0,0 +1,94 @@
# w.c.s. - web application for online forms
# Copyright (C) 2005-2022 Entr'ouvert
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# 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_request
from wcs.qommon import _
from wcs.qommon.form import SingleSelectWidget, StringWidget, WidgetList, WysiwygTextWidget
from wcs.workflows import WorkflowStatusItem, register_item_class
class EditableWorkflowStatusItem(WorkflowStatusItem):
description = _('Edition')
key = 'editable'
category = 'formdata-action'
endpoint = False
waitpoint = True
ok_in_global_action = False
by = []
status = None
label = None
backoffice_info_text = None
def get_line_details(self):
if self.by:
return _('by %s') % self.render_list_of_roles(self.by)
else:
return _('not completed')
def fill_form(self, form, formdata, user, **kwargs):
label = self.label
if not label:
label = _('Edit Form')
widget = form.add_submit('button%s' % self.id, label)
widget.backoffice_info_text = self.backoffice_info_text
widget.ignore_form_errors = True
widget.attrs['formnovalidate'] = 'formnovalidate'
def submit_form(self, form, formdata, user, evo):
if form.get_submit() == 'button%s' % self.id:
return formdata.get_url(backoffice=get_request().is_in_backoffice()) + 'wfedit-%s' % self.id
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None, **kwargs):
super().add_parameters_widgets(form, parameters, prefix=prefix, formdef=formdef, **kwargs)
if 'by' in parameters:
form.add(
WidgetList,
'%sby' % prefix,
title=_('By'),
element_type=SingleSelectWidget,
value=self.by,
add_element_label=self.get_add_role_label(),
element_kwargs={
'render_br': False,
'options': [(None, '---', None)] + self.get_list_of_roles(),
},
)
if 'status' in parameters:
form.add(
SingleSelectWidget,
'%sstatus' % prefix,
title=_('Status After Edit'),
value=self.status,
hint=_("Don't select any if you don't want status change processing"),
options=[(None, '---')] + [(x.id, x.name) for x in self.parent.parent.possible_status],
)
if 'label' in parameters:
form.add(StringWidget, '%slabel' % prefix, title=_('Button Label'), value=self.label)
if 'backoffice_info_text' in parameters:
form.add(
WysiwygTextWidget,
'%sbackoffice_info_text' % prefix,
title=_('Information Text for Backoffice'),
value=self.backoffice_info_text,
)
def get_parameters(self):
return ('by', 'status', 'label', 'backoffice_info_text', 'condition')
register_item_class(EditableWorkflowStatusItem)

46
wcs/wf/jump_on_submit.py Normal file
View File

@ -0,0 +1,46 @@
# w.c.s. - web application for online forms
# Copyright (C) 2005-2022 Entr'ouvert
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# 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 wcs.qommon import _
from wcs.workflows import WorkflowStatusJumpItem, register_item_class
class JumpOnSubmitWorkflowStatusItem(WorkflowStatusJumpItem):
description = _('On Submit Jump')
key = 'jumponsubmit'
ok_in_global_action = False
def get_line_details(self):
if self.status:
if self.get_target_status():
return _('to %s') % self.get_target_status()[0].name
else:
return _('broken')
else:
return _('not completed')
def submit_form(self, form, formdata, user, evo):
if form.is_submitted() and not form.has_errors():
wf_status = self.get_target_status(formdata)
if wf_status:
evo.status = 'wf-%s' % wf_status[0].id
self.handle_markers_stack(formdata)
def get_parameters(self):
return ('status', 'set_marker_on_status', 'condition')
register_item_class(JumpOnSubmitWorkflowStatusItem)

View File

@ -0,0 +1,46 @@
# w.c.s. - web application for online forms
# Copyright (C) 2005-2022 Entr'ouvert
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# 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 wcs.qommon import _
from wcs.qommon.form import CheckboxWidget
from wcs.workflows import WorkflowStatusItem
# RedirectToStatusWorkflowStatusItem is not registered as the class kept for
# backward compatibility only and should not be exposed to the user. (#3031)
class RedirectToStatusWorkflowStatusItem(WorkflowStatusItem):
description = _('Status Page Redirection')
key = 'redirectstatus'
ok_in_global_action = False
backoffice = False
def perform(self, formdata):
return formdata.get_url(self.backoffice)
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None, **kwargs):
super().add_parameters_widgets(form, parameters, prefix=prefix, formdef=formdef, **kwargs)
if 'backoffice' in parameters:
form.add(
CheckboxWidget,
'%sbackoffice' % prefix,
title=_('Redirect to backoffice page'),
value=self.backoffice,
)
def get_parameters(self):
return ('backoffice',)

View File

@ -18,16 +18,16 @@ import base64
import collections
import copy
import datetime
import html
import glob
import itertools
import os
import random
import time
import uuid
import xml.etree.ElementTree as ET
from importlib import import_module
from django.utils.encoding import force_text
from django.utils.html import strip_tags
from quixote import get_publisher, get_request, get_response
from quixote.html import TemplateIO, htmltext
@ -46,19 +46,13 @@ from .mail_templates import MailTemplate
from .qommon import _, ezt, force_str, get_cfg, misc
from .qommon.form import (
CheckboxWidget,
ComputedExpressionWidget,
ConditionWidget,
Form,
MiniRichTextWidget,
SingleSelectWidget,
SingleSelectWidgetWithOther,
StringWidget,
TextWidget,
ValidatedStringWidget,
VarnameWidget,
WidgetList,
WidgetListOfRoles,
WysiwygTextWidget,
)
from .qommon.humantime import seconds2humanduration
from .qommon.misc import C_, file_digest, get_as_datetime, xml_node_text
@ -1022,6 +1016,10 @@ class Workflow(StorableObject):
@classmethod
def get_default_workflow(cls):
from .qommon.admin.emails import EmailsDirectory
from .wf.choice import ChoiceWorkflowStatusItem
from .wf.comment import CommentableWorkflowStatusItem
from .wf.jump import JumpWorkflowStatusItem
from .wf.sendmail import SendmailWorkflowStatusItem
# force_text() is used on lazy gettext calls as the default workflow is used
# in tests as the basis for other ones and lazy gettext would fail pickling.
@ -1043,8 +1041,6 @@ class Workflow(StorableObject):
commentable.id = '_commentable'
commentable.by = ['_submitter', '_receiver']
from wcs.wf.jump import JumpWorkflowStatusItem
jump_to_new = JumpWorkflowStatusItem()
jump_to_new.id = '_jump_to_new'
jump_to_new.status = new_status.id
@ -2070,6 +2066,8 @@ class WorkflowStatus:
actions = []
status_id = self.id
from .wf.choice import ChoiceWorkflowStatusItem
class StatusAction:
def __init__(self, action):
self.id = 'st-%s' % action.identifier
@ -2813,344 +2811,6 @@ def register_item_class(klass):
klass.init()
class WorkflowCommentPart(EvolutionPart):
def __init__(self, comment, varname=None):
self.comment = comment
self.varname = varname
def get_as_plain_text(self):
return html.unescape(strip_tags(self.comment.replace('</p><p>', '\n\n').replace('<br>', '\n')))
def view(self):
return htmltext('<div class="comment">%s</div>' % self.comment)
class CommentableWorkflowStatusItem(WorkflowStatusItem):
description = _('Comment')
key = 'commentable'
category = 'interaction'
endpoint = False
waitpoint = True
ok_in_global_action = False
required = False
varname = None
label = None
button_label = 0 # hack to handle legacy commentable items
hint = None
by = []
backoffice_info_text = None
def get_line_details(self):
if self.by:
return _('by %s') % self.render_list_of_roles(self.by)
else:
return _('not completed')
def fill_form(self, form, formdata, user, **kwargs):
if 'comment' not in [x.name for x in form.widgets]:
if self.label is None:
title = _('Comment')
else:
title = self.label
form.add(
MiniRichTextWidget,
'comment',
title=title,
required=self.required,
hint=self.hint,
cols=40,
rows=7,
class_='comment',
)
if self.button_label == 0:
form.add_submit('button%s' % self.id, _('Add Comment'))
elif self.button_label:
form.add_submit('button%s' % self.id, self.button_label)
if form.get_widget('button%s' % self.id):
form.get_widget('button%s' % self.id).backoffice_info_text = self.backoffice_info_text
def submit_form(self, form, formdata, user, evo):
widget = form.get_widget('comment')
if widget and widget.parse() and not getattr(widget, 'processed', False):
widget.processed = True
comment = widget.parse()
comment_part = WorkflowCommentPart(comment, varname=self.varname)
evo.add_part(comment_part)
if self.varname:
formdata.update_workflow_data({'comment_%s' % self.varname: comment_part.get_as_plain_text()})
def submit_admin_form(self, form):
for f in self.get_parameters():
widget = form.get_widget(f)
setattr(self, f, widget.parse())
def fill_admin_form(self, form):
if self.by and not isinstance(self.by, list):
self.by = None
return super().fill_admin_form(form)
def get_parameters(self):
return (
'label',
'button_label',
'hint',
'by',
'varname',
'backoffice_info_text',
'required',
'condition',
)
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None, **kwargs):
super().add_parameters_widgets(form, parameters, prefix=prefix, formdef=formdef, **kwargs)
if 'label' in parameters:
if self.label is None:
self.label = str(_('Comment'))
form.add(StringWidget, '%slabel' % prefix, size=40, title=_('Label'), value=self.label)
if 'button_label' in parameters:
if self.button_label == 0:
self.button_label = str(_('Add Comment'))
form.add(
StringWidget,
'%sbutton_label' % prefix,
title=_('Button Label'),
hint=_('(empty to disable the button)'),
value=self.button_label,
)
if 'hint' in parameters:
form.add(StringWidget, '%shint' % prefix, size=40, title=_('Hint'), value=self.hint)
if 'by' in parameters:
form.add(
WidgetList,
'%sby' % prefix,
title=_('By'),
element_type=SingleSelectWidget,
value=self.by,
add_element_label=self.get_add_role_label(),
element_kwargs={
'render_br': False,
'options': [(None, '---', None)] + self.get_list_of_roles(),
},
)
if 'varname' in parameters:
form.add(
VarnameWidget,
'%svarname' % prefix,
title=_('Identifier'),
value=self.varname,
hint=_('This will make the comment available in a variable named comment_ + identifier.'),
)
if 'required' in parameters:
form.add(CheckboxWidget, '%srequired' % prefix, title=_('Required'), value=self.required)
if 'backoffice_info_text' in parameters:
form.add(
WysiwygTextWidget,
'%sbackoffice_info_text' % prefix,
title=_('Information Text for Backoffice'),
value=self.backoffice_info_text,
)
def button_label_export_to_xml(self, xml_item, charset, include_id=False):
if self.button_label == 0:
pass
elif self.button_label is None:
# button_label being None is a special case meaning "no button", it
# should be handled differently than the "not filled" case
el = ET.SubElement(xml_item, 'button_label')
else:
el = ET.SubElement(xml_item, 'button_label')
el.text = self.button_label
def button_label_init_with_xml(self, element, charset, include_id=False, snapshot=False):
if element is None:
return
# this can be None if element is self-closing, <button_label />, which
# then maps to None, meaning "no button".
self.button_label = xml_node_text(element)
register_item_class(CommentableWorkflowStatusItem)
class ChoiceWorkflowStatusItem(WorkflowStatusJumpItem):
description = _('Manual Jump')
key = 'choice'
endpoint = False
waitpoint = True
ok_in_global_action = False
label = None
identifier = None
by = []
backoffice_info_text = None
require_confirmation = False
ignore_form_errors = False
def get_label(self):
expression = self.get_expression(self.label, allow_python=False, allow_ezt=False)
if expression['type'] == 'text':
return expression['value']
return _('computed label')
def get_line_details(self):
to_status = None
if self.status == '_previous':
to_status = WorkflowStatus(_('previously marked status'))
elif self.status:
try:
to_status = self.parent.parent.get_status(self.status)
except KeyError:
return _('broken, missing destination status')
if self.label and to_status:
more = ''
if self.set_marker_on_status:
more += ' ' + str(_('(and set marker)'))
if self.by:
return _('"%(label)s", to %(to)s, by %(by)s%(more)s') % {
'label': self.get_label(),
'to': to_status.name,
'by': self.render_list_of_roles(self.by),
'more': more,
}
else:
return _('"%(label)s", to %(to)s%(more)s') % {
'label': self.get_label(),
'to': to_status.name,
'more': more,
}
else:
return _('not completed')
def get_computed_strings(self):
yield from super().get_computed_strings()
if self.get_expression(self.label, allow_python=False, allow_ezt=False)['type'] != 'text':
yield self.label
def fill_form(self, form, formdata, user, **kwargs):
label = self.compute(self.label, allow_python=False, allow_ezt=False)
if not label:
return
widget = form.add_submit('button%s' % self.id, label)
if self.identifier:
widget.extra_css_class = 'button-%s' % self.identifier
if self.require_confirmation:
get_response().add_javascript(['jquery.js', '../../i18n.js', 'qommon.js'])
widget.attrs = {'data-ask-for-confirmation': 'true'}
widget.backoffice_info_text = self.backoffice_info_text
widget.ignore_form_errors = self.ignore_form_errors
if self.ignore_form_errors:
widget.attrs['formnovalidate'] = 'formnovalidate'
def submit_form(self, form, formdata, user, evo):
if form.get_submit() == 'button%s' % self.id:
wf_status = self.get_target_status(formdata)
if wf_status:
evo.status = 'wf-%s' % wf_status[0].id
self.handle_markers_stack(formdata)
form.clear_errors()
return True # get out of processing loop
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None, **kwargs):
super().add_parameters_widgets(form, parameters, prefix=prefix, formdef=formdef, **kwargs)
if 'label' in parameters:
form.add(
ComputedExpressionWidget,
'%slabel' % prefix,
title=_('Label'),
value=self.label,
allow_python=False,
)
if 'by' in parameters:
form.add(
WidgetList,
'%sby' % prefix,
title=_('By'),
element_type=SingleSelectWidget,
value=self.by,
add_element_label=self.get_add_role_label(),
element_kwargs={
'render_br': False,
'options': [(None, '---', None)] + self.get_list_of_roles(),
},
)
if 'require_confirmation' in parameters:
form.add(
CheckboxWidget,
'%srequire_confirmation' % prefix,
title=_('Require confirmation'),
value=self.require_confirmation,
)
if 'backoffice_info_text' in parameters:
form.add(
WysiwygTextWidget,
'%sbackoffice_info_text' % prefix,
title=_('Information Text for Backoffice'),
value=self.backoffice_info_text,
)
if 'identifier' in parameters:
form.add(
VarnameWidget,
'%sidentifier' % prefix,
title=_('Identifier'),
value=self.identifier,
advanced=True,
)
if 'ignore_form_errors' in parameters:
form.add(
CheckboxWidget,
'%signore_form_errors' % prefix,
title=_('Ignore form errors'),
value=self.ignore_form_errors,
advanced=True,
)
def get_parameters(self):
return (
'label',
'by',
'status',
'require_confirmation',
'backoffice_info_text',
'ignore_form_errors',
'set_marker_on_status',
'condition',
'identifier',
)
register_item_class(ChoiceWorkflowStatusItem)
class JumpOnSubmitWorkflowStatusItem(WorkflowStatusJumpItem):
description = _('On Submit Jump')
key = 'jumponsubmit'
ok_in_global_action = False
def get_line_details(self):
if self.status:
if self.get_target_status():
return _('to %s') % self.get_target_status()[0].name
else:
return _('broken')
else:
return _('not completed')
def submit_form(self, form, formdata, user, evo):
if form.is_submitted() and not form.has_errors():
wf_status = self.get_target_status(formdata)
if wf_status:
evo.status = 'wf-%s' % wf_status[0].id
self.handle_markers_stack(formdata)
def get_parameters(self):
return ('status', 'set_marker_on_status', 'condition')
register_item_class(JumpOnSubmitWorkflowStatusItem)
def get_formdata_template_context(formdata=None):
ctx = get_publisher().substitutions.get_context_variables('lazy')
if formdata:
@ -3193,258 +2853,13 @@ def template_on_context(context=None, template=None, **kwargs):
return Template(template, **kwargs).render(context)
class DisplayMessageWorkflowStatusItem(WorkflowStatusItem):
description = _('Alert')
key = 'displaymsg'
category = 'interaction'
support_substitution_variables = True
ok_in_global_action = False
to = None
position = 'top'
level = None
message = None
def get_line_details(self):
parts = []
if self.position == 'top':
parts.append(_('top of page'))
elif self.position == 'bottom':
parts.append(_('bottom of page'))
elif self.position == 'actions':
parts.append(_('with actions'))
if self.to:
parts.append(_('for %s') % self.render_list_of_roles(self.to))
return ', '.join([str(x) for x in parts])
def get_computed_strings(self):
yield from super().get_computed_strings()
yield self.message
def get_message(self, filled, position='top'):
if not (self.message and self.position == position and filled.is_for_current_user(self.to)):
return ''
dict = copy.copy(get_publisher().substitutions.get_context_variables('lazy'))
dict['date'] = misc.localstrftime(filled.receipt_time)
dict['number'] = filled.id
handling_role = filled.get_handling_role()
if handling_role and handling_role.details:
dict['receiver'] = handling_role.details.replace('\n', '<br />')
message = self.message
if self.level:
message = '<div class="%snotice">%s</div>' % (self.level, message)
try:
return Template(message, ezt_format=ezt.FORMAT_HTML).render(dict)
except Exception as e:
get_publisher().record_error(
error_summary=_('Error in template of workflow message (%s)') % e, exception=e, notify=True
)
return '<div class="errornotice">%s</div>' % _('Error rendering message.')
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None, **kwargs):
super().add_parameters_widgets(form, parameters, prefix=prefix, formdef=formdef, **kwargs)
if 'message' in parameters:
form.add(
TextWidget,
'%smessage' % prefix,
title=_('Message'),
value=self.message,
cols=80,
rows=10,
validation_function=ComputedExpressionWidget.validate_template,
)
if 'level' in parameters:
form.add(
SingleSelectWidget,
'%slevel' % prefix,
title=_('Level'),
value=self.level,
options=[
(None, ''),
('success', _('Success')),
('info', _('Information')),
('warning', _('Warning')),
('error', _('Error')),
],
)
if 'position' in parameters:
form.add(
SingleSelectWidget,
'%sposition' % prefix,
title=_('Position'),
value=self.position,
options=[
('top', _('Top of page')),
('bottom', _('Bottom of page')),
# ('actions', _('With actions')) "too complicated"
],
)
if 'to' in parameters:
form.add(
WidgetListOfRoles,
'%sto' % prefix,
title=_('To'),
value=self.to or [],
add_element_label=self.get_add_role_label(),
first_element_empty_label=_('Everybody'),
roles=self.get_list_of_roles(include_logged_in_users=False),
)
def get_parameters(self):
return ('message', 'level', 'position', 'to', 'condition')
def get_message_parameter_view_value(self):
if self.message.startswith('<'):
return htmltext(self.message)
return htmltext('<pre>%s</pre>') % self.message
register_item_class(DisplayMessageWorkflowStatusItem)
class RedirectToStatusWorkflowStatusItem(WorkflowStatusItem):
description = _('Status Page Redirection')
key = 'redirectstatus'
ok_in_global_action = False
backoffice = False
def perform(self, formdata):
return formdata.get_url(self.backoffice)
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None, **kwargs):
super().add_parameters_widgets(form, parameters, prefix=prefix, formdef=formdef, **kwargs)
if 'backoffice' in parameters:
form.add(
CheckboxWidget,
'%sbackoffice' % prefix,
title=_('Redirect to backoffice page'),
value=self.backoffice,
)
def get_parameters(self):
return ('backoffice',)
# RedirectToStatusWorkflowStatusItem is not registered as the class kept for
# backward compatibility only and should not be exposed to the user. (#3031)
class EditableWorkflowStatusItem(WorkflowStatusItem):
description = _('Edition')
key = 'editable'
category = 'formdata-action'
endpoint = False
waitpoint = True
ok_in_global_action = False
by = []
status = None
label = None
backoffice_info_text = None
def get_line_details(self):
if self.by:
return _('by %s') % self.render_list_of_roles(self.by)
else:
return _('not completed')
def fill_form(self, form, formdata, user, **kwargs):
label = self.label
if not label:
label = _('Edit Form')
widget = form.add_submit('button%s' % self.id, label)
widget.backoffice_info_text = self.backoffice_info_text
widget.ignore_form_errors = True
widget.attrs['formnovalidate'] = 'formnovalidate'
def submit_form(self, form, formdata, user, evo):
if form.get_submit() == 'button%s' % self.id:
return formdata.get_url(backoffice=get_request().is_in_backoffice()) + 'wfedit-%s' % self.id
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None, **kwargs):
super().add_parameters_widgets(form, parameters, prefix=prefix, formdef=formdef, **kwargs)
if 'by' in parameters:
form.add(
WidgetList,
'%sby' % prefix,
title=_('By'),
element_type=SingleSelectWidget,
value=self.by,
add_element_label=self.get_add_role_label(),
element_kwargs={
'render_br': False,
'options': [(None, '---', None)] + self.get_list_of_roles(),
},
)
if 'status' in parameters:
form.add(
SingleSelectWidget,
'%sstatus' % prefix,
title=_('Status After Edit'),
value=self.status,
hint=_("Don't select any if you don't want status change processing"),
options=[(None, '---')] + [(x.id, x.name) for x in self.parent.parent.possible_status],
)
if 'label' in parameters:
form.add(StringWidget, '%slabel' % prefix, title=_('Button Label'), value=self.label)
if 'backoffice_info_text' in parameters:
form.add(
WysiwygTextWidget,
'%sbackoffice_info_text' % prefix,
title=_('Information Text for Backoffice'),
value=self.backoffice_info_text,
)
def get_parameters(self):
return ('by', 'status', 'label', 'backoffice_info_text', 'condition')
register_item_class(EditableWorkflowStatusItem)
def load_extra():
from .wf import aggregation_email # noqa pylint: disable=unused-import
from .wf import anonymise # noqa pylint: disable=unused-import
from .wf import assign_carddata # noqa pylint: disable=unused-import
from .wf import attachment # noqa pylint: disable=unused-import
from .wf import backoffice_fields # noqa pylint: disable=unused-import
from .wf import create_carddata # noqa pylint: disable=unused-import
from .wf import create_formdata # noqa pylint: disable=unused-import
from .wf import criticality # noqa pylint: disable=unused-import
from .wf import dispatch # noqa pylint: disable=unused-import
from .wf import edit_carddata # noqa pylint: disable=unused-import
from .wf import export_to_model # noqa pylint: disable=unused-import
from .wf import external_workflow # noqa pylint: disable=unused-import
from .wf import form # noqa pylint: disable=unused-import
from .wf import geolocate # noqa pylint: disable=unused-import
from .wf import jump # noqa pylint: disable=unused-import
from .wf import notification # noqa pylint: disable=unused-import
from .wf import profile # noqa pylint: disable=unused-import
from .wf import redirect_to_url # noqa pylint: disable=unused-import
from .wf import register_comment # noqa pylint: disable=unused-import
from .wf import remove # noqa pylint: disable=unused-import
from .wf import remove_tracking_code # noqa pylint: disable=unused-import
from .wf import resubmit # noqa pylint: disable=unused-import
from .wf import roles # noqa pylint: disable=unused-import
from .wf import sendmail # noqa pylint: disable=unused-import
from .wf import timeout_jump # noqa pylint: disable=unused-import
from .wf import wscall # noqa pylint: disable=unused-import
from . import wf
aggregation_email.register_cronjob()
jump.register_cronjob()
# additional imports to get symbols referenced in past pickle files
# noqa pylint: disable=unused-import,wrong-import-position
from .wf.export_to_model import ExportToModel
# noqa pylint: disable=unused-import,wrong-import-position
from .wf.sendmail import SendmailWorkflowStatusItem
# noqa pylint: disable=unused-import,wrong-import-position
from .wf.sms import SendSMSWorkflowStatusItem
for filename in glob.glob(os.path.join(wf.__path__[0], '*.py')):
module_name = os.path.splitext(os.path.basename(filename))[0]
if module_name == '__init__':
continue
module = import_module('wcs.wf.%s' % module_name)
if hasattr(module, 'register_cronjob'):
module.register_cronjob()