Remove legacy "workflow" code (#1175)

This commit is contained in:
Frédéric Péters 2012-06-20 13:02:28 +02:00
parent 633196d8e4
commit ff156169a1
8 changed files with 156 additions and 350 deletions

View File

@ -149,8 +149,6 @@ class FormDefUI:
value = formdef.always_advertise)
form.add(CheckboxWidget, 'confirmation', title = _('Include confirmation page'),
value = formdef.confirmation)
form.add(CheckboxWidget, 'discussion', title = _('Allow discussion'),
value = formdef.discussion)
form.add(SingleSelectWidget, 'signing', title = _('Signature'),
options = [
(None, _('None')),
@ -204,7 +202,7 @@ class FormDefUI:
form.get_widget('name').set_error(_('This name is already used'))
raise ValueError()
for f in ('name', 'confirmation', 'signing', 'discussion', 'acl_read',
for f in ('name', 'confirmation', 'signing', 'acl_read',
'only_allow_one', 'receiver_id', 'category_id', 'disabled',
'allow_drafts', 'workflow_id', 'private_status_and_history',
'disabled_redirection', 'always_advertise',
@ -304,9 +302,10 @@ class FormDefPage(Directory):
if self.formdef.workflow:
'<li>%s ' % _('Workflow:')
'%s' % self.formdef.workflow.name
pristine_workflow = Workflow.get(self.formdef.workflow_id)
if pristine_workflow.has_options():
' (<a href="workflow">%s</a>)' % _('options')
if self.formdef.workflow_id:
pristine_workflow = Workflow.get(self.formdef.workflow_id)
if pristine_workflow.has_options():
' (<a href="workflow">%s</a>)' % _('options')
'</li>'
if self.formdef.receiver:
'<li>%s ' % _('Recipient Role:')
@ -340,8 +339,6 @@ class FormDefPage(Directory):
'<ul>'
if self.formdef.confirmation:
'<li>%s</li>' % _('Include confirmation page')
if not self.formdef.workflow_id and self.formdef.discussion:
'<li>%s</li>' % _('Allow discussion')
if self.formdef.signing == 'optional':
'<li>%s</li>' % _('Optional Signing')
if self.formdef.signing == 'compulsory':
@ -512,11 +509,8 @@ class FormDefPage(Directory):
all_forms = self.formdef.data_class().select()
if form.get_widget('not-done').parse() is False:
if self.formdef.workflow:
not_endpoint_status = self.formdef.workflow.get_not_endpoint_status()
not_endpoint_status_ids = ['wf-%s' % x.id for x in not_endpoint_status]
else:
not_endpoint_status_ids = ('new', 'accepted')
not_endpoint_status = self.formdef.workflow.get_not_endpoint_status()
not_endpoint_status_ids = ['wf-%s' % x.id for x in not_endpoint_status]
all_forms = [x for x in all_forms if x.status not in not_endpoint_status_ids]
if form.get_widget('date').parse():

View File

@ -33,7 +33,6 @@ from wcs.forms.common import FormStatusPage
from wcs.categories import Category
from wcs.formdef import FormDef
from wcs.forms.root import status_labels
from wcs.forms.backoffice import FormDefUI
try:
@ -144,11 +143,8 @@ class RootDirectory(BackofficeRootDirectory):
if not user.is_admin and not formdef.receiver_id in (user.roles or []):
continue
if formdef.workflow:
not_endpoint_status = [('wf-%s' % x.id, x.name) for x in \
not_endpoint_status = [('wf-%s' % x.id, x.name) for x in \
formdef.workflow.get_not_endpoint_status()]
else:
not_endpoint_status = [('new', _('New')), ('accepted', _('Accepted'))]
forms = []
for status_id, status_name in not_endpoint_status:
@ -267,11 +263,8 @@ class FormPage(Directory):
html_top('forms', '%s - %s' % (_('Pending Forms'), self.formdef.name))
'<h2>%s - %s</h2>' % (self.formdef.name, _('Pending Forms'))
if self.formdef.workflow:
not_endpoint_status = [('wf-%s' % x.id, x.name) for x in \
not_endpoint_status = [('wf-%s' % x.id, x.name) for x in \
self.formdef.workflow.get_not_endpoint_status()]
else:
not_endpoint_status = [('new', _('New')), ('accepted', _('Accepted'))]
nb_status = len(not_endpoint_status)
column2 = nb_status/2
@ -381,14 +374,9 @@ class FormPage(Directory):
if not self.formdef.workflow or len(self.formdef.workflow.possible_status) > 1:
'<ul>'
if self.formdef.workflow:
for status in self.formdef.workflow.possible_status:
'<li>%s: %d</li>' % (status.name,
len([x for x in values if x.status == 'wf-%s' % status.id]))
else:
for status in ('new', 'accepted', 'finished', 'rejected'):
'<li>%s: %d</li>' % (_(status_labels[status]),
len([x for x in values if x.status == status]))
for status in self.formdef.workflow.possible_status:
'<li>%s: %d</li>' % (status.name,
len([x for x in values if x.status == 'wf-%s' % status.id]))
'</ul>'
self.stats_fields(values)
@ -429,12 +417,8 @@ class FormPage(Directory):
'</div>'
def stats_resolution_time [html] (self, values):
if self.formdef.workflow:
possible_status_id = [x.id for x in self.formdef.workflow.possible_status]
possible_status = ['wf-%s' % x.id for x in self.formdef.workflow.possible_status]
else:
possible_status_id = ('finished', 'rejected')
possible_status = ('finished', 'rejected')
possible_status_id = [x.id for x in self.formdef.workflow.possible_status]
possible_status = ['wf-%s' % x.id for x in self.formdef.workflow.possible_status]
if len(possible_status) < 2:
return
@ -450,10 +434,7 @@ class FormPage(Directory):
res_time_forms.sort()
sum_times = sum(res_time_forms)
len_times = len(res_time_forms)
if status in status_labels:
'<h3>%s</h3>' % (_('To Status "%s"') % _(status_labels[status]))
else:
'<h3>%s</h3>' % (_('To Status "%s"') % self.formdef.workflow.get_status(status_id).name)
'<h3>%s</h3>' % (_('To Status "%s"') % self.formdef.workflow.get_status(status_id).name)
'<ul>'
' <li>%s %s</li>' % (_('Minimum Time:'), format_time(min(res_time_forms)))
' <li>%s %s</li>' % (_('Maximum Time:'), format_time(max(res_time_forms)))

View File

@ -106,6 +106,14 @@ class FormData(StorableObject):
def __init__(self, id=None):
self.id = id
def migrate(self):
changed = False
if self.status and not self.status.startswith('wf-'):
self.status = 'wf-%s' % self.status
changed = True
if changed:
self.store()
def get_user(self):
if self.user_id and self.user_id != 'ultra-user':
return get_publisher().user_class.get(self.user_id, ignore_errors=True)
@ -132,10 +140,7 @@ class FormData(StorableObject):
def just_created(self):
self.receipt_time = time.localtime()
if self.formdef.workflow:
self.status = 'wf-%s' % self.formdef.workflow.possible_status[0].id
else:
self.status = 'new'
self.status = 'wf-%s' % self.formdef.workflow.possible_status[0].id
# we add the initial status to the history, this makes it more readable
# afterwards (also this gets the (previous_status) code to work in all
# cases)
@ -148,20 +153,15 @@ class FormData(StorableObject):
def perform_workflow(self):
url = None
get_publisher().substitutions.feed(self)
if self.status.startswith('wf-'):
wf_status = self.get_workflow_status()
url = wf_status.perform_items(self)
elif self.status == 'new':
self.formdef.notify_new_receiver(self)
self.formdef.notify_new_user(self)
wf_status = self.get_workflow_status()
url = wf_status.perform_items(self)
return url
def display_workflow_message(self):
if self.status.startswith('wf-'):
wf_status = self.get_workflow_status()
for status in wf_status.items:
if hasattr(status, 'get_message'):
return status.get_message(self)
wf_status = self.get_workflow_status()
for status in wf_status.items:
if hasattr(status, 'get_message'):
return status.get_message(self)
return ''
def get_status_label(self, status = None):
@ -169,20 +169,12 @@ class FormData(StorableObject):
status = self.status
if not self.formdef:
return _('Unknown')
if self.formdef.workflow:
try:
status_id = status.split('-')[1]
wf_status = [x for x in self.formdef.workflow.possible_status if x.id == status_id][0]
except IndexError:
return _('Unknown')
return wf_status.name
else:
# COMPAT (behaviour when no workflow)
from formdef import status_labels
try:
return _(status_labels[status])
except KeyError:
return _('Unknown')
try:
status_id = status.split('-')[1]
wf_status = [x for x in self.formdef.workflow.possible_status if x.id == status_id][0]
except IndexError:
return _('Unknown')
return wf_status.name
def get_workflow_form(self, user):
wf_status = self.get_workflow_status()
@ -204,10 +196,11 @@ class FormData(StorableObject):
return '%s/%s/%s/' % (base_url, self.formdef.url_name, self.id)
def get_workflow_status(self):
if not self.status.startswith('wf-'):
raise 'Error, this codepath is only for workflows (current status: %s)' % self.status
status_id = self.status.split('-')[1]
wf_status = [x for x in self.formdef.workflow.possible_status if x.id == status_id][0]
try:
status_id = self.status.split('-')[1]
wf_status = [x for x in self.formdef.workflow.possible_status if x.id == status_id][0]
except IndexError:
return None
return wf_status
def get_field_value(self, field):

View File

@ -45,17 +45,10 @@ from qommon.substitution import Substitutions
from formdata import FormData
from roles import Role, logged_users_role
from categories import Category
from wcs.workflows import Workflow
from wcs.workflows import Workflow, CommentableWorkflowStatusItem, \
SendmailWorkflowStatusItem, ChoiceWorkflowStatusItem
import fields
status_labels = {
None: N_('Unknown'),
'new': N_('New'),
'rejected': N_('Rejected'),
'accepted': N_('Accepted'),
'finished': N_('Finished')
}
class FormField:
### only used to unpickle form fields from older (<200603) versions
def __setstate__(self, dict):
@ -206,7 +199,84 @@ class FormDef(StorableObject):
return None
return self.get_workflow_with_options(workflow)
else:
return None
return self.get_default_workflow()
def get_default_workflow(self):
workflow = Workflow(name=_('Default'))
workflow.id = '_default'
new_status = workflow.add_status(_('New'), 'new')
rejected_status = workflow.add_status(_('Rejected'), 'rejected')
accepted_status = workflow.add_status(_('Accepted'), 'accepted')
finished_status = workflow.add_status(_('Finished'), 'finished')
commentable = CommentableWorkflowStatusItem()
commentable.id = '_commentable'
commentable.by = ('_submitted', '_receiver')
notify_new_receiver_email = SendmailWorkflowStatusItem()
notify_new_receiver_email.id = '_notify_new_receiver_email'
notify_new_receiver_email.to = ('_receiver',)
notify_new_receiver_email.subject = EmailsDirectory.get_subject('new_receiver')
notify_new_receiver_email.body = EmailsDirectory.get_body('new_receiver')
notify_new_user_email = SendmailWorkflowStatusItem()
notify_new_user_email.id = '_notify_new_user_email'
notify_new_user_email.to = ('_submitter',)
notify_new_user_email.subject = EmailsDirectory.get_subject('new_user')
notify_new_user_email.body = EmailsDirectory.get_body('new_user')
notify_change_receiver_email = SendmailWorkflowStatusItem()
notify_change_receiver_email.id = '_notify_change_receiver_email'
notify_change_receiver_email.to = ('_receiver',)
notify_change_receiver_email.subject = EmailsDirectory.get_subject('change_receiver')
notify_change_receiver_email.body = EmailsDirectory.get_body('change_receiver')
notify_change_user_email = SendmailWorkflowStatusItem()
notify_change_user_email.id = '_notify_change_user_email'
notify_change_user_email.to = ('_submitter',)
notify_change_user_email.subject = EmailsDirectory.get_subject('change_user')
notify_change_user_email.body = EmailsDirectory.get_body('change_user')
new_status.items.append(notify_new_receiver_email)
new_status.items.append(notify_new_user_email)
accepted_status.items.append(notify_change_receiver_email)
accepted_status.items.append(notify_change_user_email)
rejected_status.items.append(notify_change_receiver_email)
rejected_status.items.append(notify_change_user_email)
finished_status.items.append(notify_change_receiver_email)
finished_status.items.append(notify_change_user_email)
accept = ChoiceWorkflowStatusItem()
accept.id = '_accept'
accept.label = _('Accept')
accept.by = ('_receiver',)
accept.status = accepted_status.id
accept.parent = new_status
new_status.items.append(accept)
new_status.items.append(commentable)
accepted_status.items.append(commentable)
reject = ChoiceWorkflowStatusItem()
reject.id = '_reject'
reject.label = _('Reject')
reject.by = ('_receiver',)
reject.status = rejected_status.id
reject.parent = new_status
new_status.items.append(reject)
finish = ChoiceWorkflowStatusItem()
finish.id = '_finish'
finish.label = _('Finish')
finish.by = ('_receiver',)
finish.status = finished_status.id
finish.parent = accepted_status
accepted_status.items.append(finish)
return workflow
def get_workflow_with_options(self, workflow):
# this needs to be kept in sync with admin/forms.ptl,
@ -486,99 +556,6 @@ class FormDef(StorableObject):
d.update(self.category.get_substitution_variables())
return d
def notify_new_user(self, formdata):
submitter_email = self.get_submitter_email(formdata)
if not submitter_email:
return
if self.receiver.emails:
from_email = self.receiver.emails[0]
else:
from_email = None
url = formdata.get_url()
data = get_publisher().substitutions.get_context_variables()
data.update({
'url': url,
'details': self.get_detailed_email_form(formdata, url),
'name': self.name,
'user': formdata.user,
})
emails.custom_ezt_email('new_user',
data, submitter_email,
replyto = from_email,
exclude_current_user = False,
fire_and_forget = True)
def notify_new_receiver(self, formdata):
receiver_emails = self.receiver.get_emails()
if not receiver_emails:
return
if self.receiver.emails:
from_email = self.receiver.emails[0]
else:
from_email = None
mail_body = _("""Hello,
A new form has been submitted on the website, you can consult it with this
link: [url]
[if-any details]
[details]
[end]
""")
url = formdata.get_url(backoffice = True)
data = get_publisher().substitutions.get_context_variables()
data.update({
'url': url,
'details': self.get_detailed_email_form(formdata, url),
'name': self.name
})
emails.custom_ezt_email('new_receiver',
data, email_rcpt=None,
bcc = receiver_emails,
exclude_current_user = True,
fire_and_forget = True)
def notify_change_user(self, formdata, old_status):
submitter_email = self.get_submitter_email(formdata)
if not submitter_email:
return
if self.receiver.emails:
from_email = self.receiver.emails[0]
else:
from_email = None
url = formdata.get_url()
if old_status != formdata.status:
email_key = 'change_user'
else:
email_key = 'comment_user'
evolution = self.get_detailed_evolution(formdata)
data = get_publisher().substitutions.get_context_variables()
data.update({
'name': self.name,
'url': url,
'evolution': evolution,
'before': _(status_labels[old_status]),
'after': _(status_labels[formdata.status]),
'user': formdata.user,
})
emails.custom_ezt_email(email_key, data, submitter_email,
replyto = from_email,
exclude_current_user = True,
fire_and_forget = True)
def get_detailed_evolution(self, formdata):
if not formdata.evolution:
@ -591,42 +568,11 @@ link: [url]
details.append(' %s' % get_publisher().user_class.get(evo.who).name)
if evo.status:
details.append(_('Status'))
details.append(' %s' % _(status_labels[evo.status]))
details.append(' %s' % formdata.get_status_label())
if evo.comment:
details.append('\n%s\n' % evo.comment)
return '\n\n----\n\n' + '\n'.join(details)
def notify_change_receiver(self, formdata, old_status):
receiver_emails = self.receiver.get_emails()
if not receiver_emails:
return
emails_cfg = get_cfg('emails', {})
url = formdata.get_url(backoffice = True)
if old_status != formdata.status:
email_key = 'change_receiver'
else:
email_key = 'comment_receiver'
evolution = self.get_detailed_evolution(formdata)
data = get_publisher().substitutions.get_context_variables()
data.update({
'name': self.name,
'url': url,
'evolution': evolution,
'before': _(status_labels[old_status]),
'after': _(status_labels[formdata.status])
})
emails.custom_ezt_email(email_key, data,
email_rcpt=None, bcc=receiver_emails,
exclude_current_user = True,
fire_and_forget = True)
def is_user_allowed_read(self, user, formdata=None):
if self.acl_read == 'all':
return True

View File

@ -21,8 +21,6 @@ from quixote import get_request, get_publisher
from qommon import misc
from qommon.form import *
from root import status_labels
class FormDefUI:
def __init__(self, formdef):
self.formdef = formdef
@ -100,12 +98,8 @@ class FormDefUI:
if include_status_column:
'<td><select name="status" onchange="updateListing()"'
'<option value="">%s</option>' % _('All')
if self.formdef.workflow:
for status in self.formdef.workflow.possible_status:
'<option value="wf-%s">%s</option>' % (status.id, status.name)
else: # COMPAT (behaviour when no workflow)
for label in ('new', 'accepted', 'finished', 'rejected'):
'<option value="%s">%s</option>' % (label, _(status_labels[label]))
for status in self.formdef.workflow.possible_status:
'<option value="wf-%s">%s</option>' % (status.id, status.name)
'</select></td>'
'</tr>'
'</thead>'

View File

@ -21,7 +21,6 @@ from quixote import get_publisher, get_request, get_response, get_session, redir
from quixote.directory import Directory, AccessControlled
from wcs import formdata
from wcs.formdef import status_labels
from wcs.fields import WidgetField
@ -115,21 +114,11 @@ class FormStatusPage(Directory):
form = None
if self.formdef.workflow:
session = get_session()
user = get_request().user
form = self.filled.get_workflow_form(user)
if form:
form.add_captcha()
else:
# COMPAT (when no workflow)
if self.formdef.discussion and self.filled.status in ('new', 'accepted'):
form = Form(enctype="multipart/form-data")
form.add_captcha()
form.add(TextWidget, 'comment', title = _('Comment'), required = False,
cols = 40, rows = 10)
form.get_widget('comment').attrs[str('class')] = str('comment')
form.add_submit('add-comment', _('Add Comment'))
session = get_session()
user = get_request().user
form = self.filled.get_workflow_form(user)
if form:
form.add_captcha()
if form and form.is_submitted():
if not form.has_errors():
@ -310,30 +299,12 @@ class FormStatusPage(Directory):
user = self.check_receiver()
form = None
if self.formdef.workflow:
try:
form = self.filled.get_workflow_form(user)
except:
# XXX: probably because there are mixed forms, with and without
# workflows
form = Form()
else:
# COMPAT (when no workflow)
if self.filled.status == 'new':
form = Form(enctype="multipart/form-data")
form.add(TextWidget, 'comment', title = _('Comment'), required = False,
cols = 40, rows = 10)
form.get_widget('comment').attrs[str('class')] = str('comment')
form.add_submit('accept', _('Accept'))
form.add_submit('add-comment', _('Add Comment'))
form.add_submit('reject', _('Reject'))
if self.filled.status == 'accepted':
form = Form(enctype="multipart/form-data")
form.add(TextWidget, 'comment', title = _('Comment'), required = False,
cols = 40, rows = 10)
form.get_widget('comment').attrs[str('class')] = str('comment')
form.add_submit('add-comment', _('Add Comment'))
form.add_submit('finish', _('Finish'))
try:
form = self.filled.get_workflow_form(user)
except:
# XXX: probably because there are mixed forms, with and without
# workflows
form = Form()
if form and form.is_submitted():
url = self.submit(form)
@ -372,62 +343,16 @@ class FormStatusPage(Directory):
def submit(self, form, comment_only = False):
status = None
if self.formdef.workflow:
current_status = self.filled.status
user = get_request().user
next_url = self.filled.handle_workflow_form(user, form)
if next_url:
return next_url
if form.has_errors():
return
if current_status != self.filled.status:
# XXX: log
pass
else:
# COMPAT (when no workflow)
comment = form.get_widget('comment').parse()
old_status = self.filled.status
if self.filled.status == 'new' and not comment_only:
if form.get_widget('accept').parse():
status = 'accepted'
if form.get_widget('reject').parse():
status = 'rejected'
if self.filled.status == 'accepted' and not comment_only:
if form.get_widget('finish').parse():
status = 'finished'
if comment_only:
status = None
if status:
get_logger().info('form %s - id: %s - status -> %s' % (
self.formdef.name, self.filled.id, status))
else:
get_logger().info('form %s - id: %s - new comment' % (
self.formdef.name, self.filled.id))
who = None
session = get_session()
if session.user and not str(session.user).startswith('anonymous-'):
who = session.user
evo = formdata.Evolution()
evo.status = status
evo.time = time.localtime()
evo.who = who
evo.comment = comment
if not self.filled.evolution:
self.filled.evolution = []
self.filled.evolution.append(evo)
if status:
self.filled.status = status
self.filled.store()
if comment_only:
self.formdef.notify_change_receiver(self.filled, old_status)
else:
self.formdef.notify_change_user(self.filled, old_status)
current_status = self.filled.status
user = get_request().user
next_url = self.filled.handle_workflow_form(user, form)
if next_url:
return next_url
if form.has_errors():
return
if current_status != self.filled.status:
get_logger().info('form %s - id: %s - status -> %s' % (
self.formdef.name, self.filled.id, self.filled.status))
def download(self):
if not self.filled.formdef.is_user_allowed_read(get_request().user, self.filled):

View File

@ -35,7 +35,7 @@ from qommon import ezt
from wcs.anonylink import AnonymityLink
from wcs.categories import Category
from wcs.formdef import FormField, FormDef, status_labels
from wcs.formdef import FormField, FormDef
from wcs.formdata import FormData
from wcs.users import User
from wcs.roles import logged_users_role
@ -1126,19 +1126,6 @@ class RootDirectory(AccessControlled, Directory):
'</p>'
def formdata_list_item [html] (self, f):
if f.formdef.private_status_and_history:
'<li><a href="%s/%s/">%s</a>, %s</li>' % (
f.formdef.url_name, f.id, f.formdef.name,
misc.localstrftime(f.receipt_time))
else:
'<li><a href="%s/%s/">%s</a>, %s, %s: %s</li>' % (
f.formdef.url_name, f.id, f.formdef.name,
misc.localstrftime(f.receipt_time),
_('status'),
_(status_labels[f.status]) )
def user_forms [html] (self, user_forms):
draft = [x for x in user_forms if x.status == 'draft']
if draft:
@ -1149,31 +1136,13 @@ class RootDirectory(AccessControlled, Directory):
f.formdef.url_name, f.id, f.formdef.name)
'</ul>'
# (COMPAT) without workflows
current = [x for x in user_forms if x.status in ('new', 'accepted') or \
x.formdef.private_status_and_history]
if current:
'<h2 id="submitted">%s</h2>' % _('Your Current Forms')
'<ul>'
for f in current:
self.formdata_list_item(f)
'</ul>'
done = [x for x in user_forms if x.status in ('rejected', 'finished') and \
not x.formdef.private_status_and_history]
if done:
'<h2 id="done">%s</h2>' % _('Your Old Forms')
'<ul>'
for f in done:
self.formdata_list_item(f)
'</ul>'
# with workflows
workflows = Workflow.select(order_by = 'name')
workflows = [FormDef().get_default_workflow()] + Workflow.select(order_by = 'name')
for workflow in workflows:
# XXX: seperate endpoints from non-endpoints
for status in workflow.possible_status:
fms = [x for x in user_forms if x.status == 'wf-%s' % status.id and \
x.formdef.workflow_id == workflow.id and \
x.formdef.workflow.id == workflow.id and \
not x.formdef.private_status_and_history]
if not fms:
continue

View File

@ -87,15 +87,19 @@ class Workflow(StorableObject):
self.name = name
self.possible_status = []
def add_status(self, name):
def add_status(self, name, id=None):
if [x for x in self.possible_status if x.name == name]:
raise DuplicateStatusNameError()
status = WorkflowStatus(name)
status.parent = self
if self.possible_status:
status.id = str(max([lax_int(x.id) for x in self.possible_status]) + 1)
if id is None:
if self.possible_status:
status.id = str(max([lax_int(x.id) for x in self.possible_status]) + 1)
else:
status.id = '1'
else:
status.id = '1'
status.id = id
self.possible_status.append(status)
return status