general: update file types in all kind of formdefs on change (#47180) #688

Merged
fpeters merged 1 commits from wip/47180-update-filetype-in-all-formdefs into main 2023-09-18 11:48:48 +02:00
3 changed files with 128 additions and 28 deletions

View File

@ -34,6 +34,7 @@ from wcs.mail_templates import MailTemplate
from wcs.qommon.form import UploadedFile
from wcs.qommon.http_request import HTTPRequest
from wcs.wf.export_to_model import ExportToModel
from wcs.wf.form import WorkflowFormFieldsFormDef
from wcs.workflows import Workflow
from wcs.wscalls import NamedWsCall
@ -729,8 +730,10 @@ def test_settings_filetypes(pub):
assert resp.forms[0]['mimetypes'].value == 'application/vnd.oasis.opendocument.text'
resp.forms[0]['mimetypes'] = 'application/vnd.oasis.opendocument.text, .doc, .docx, .pdf'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/settings/filetypes/'
assert resp.location.startswith('http://example.net/backoffice/processing?job=')
resp = resp.follow()
assert 'completed' in resp.text
resp = resp.click('Back to settings')
assert 'application/msword (.' in resp.text
assert 'application/pdf' in pub.cfg['filetypes'][1]['mimetypes']
@ -787,6 +790,28 @@ def test_settings_filetypes_update(pub):
'label': 'Text files',
}
CardDef.wipe()
carddef = CardDef()
carddef.name = 'card title'
carddef.fields = formdef.fields
carddef.store()
BlockDef.wipe()
blockdef = BlockDef()
blockdef.name = 'block title'
blockdef.fields = formdef.fields
blockdef.store()
Outdated
Review

Puisqu'on passe par get_formdefs_of_all_kinds pour mettre à jour les formdef, peut-être ajouter un bloc de champ avec un champ fichier, et une action de formulaire-de-workflow avec un champ fichier... (je sais, c'est un peu relou)

Puisqu'on passe par get_formdefs_of_all_kinds pour mettre à jour les formdef, peut-être ajouter un bloc de champ avec un champ fichier, et une action de formulaire-de-workflow avec un champ fichier... (je sais, c'est un peu relou)

Voilà avec bloc et formulaire de workflow. (et bien d'avoir ajouté ce test, ça a permis de voir que la modif aux workflows pouvait ne pas avoir lieu s'il y avait à la fois formulaire de workflow et action de fichier attaché).

Voilà avec bloc et formulaire de workflow. (et bien d'avoir ajouté ce test, ça a permis de voir que la modif aux workflows pouvait ne pas avoir lieu s'il y avait à la fois formulaire de workflow et action de fichier attaché).
wf = Workflow(name='status')
st1 = wf.add_status('Status1', 'st1')
attach = st1.add_action('addattachment', id='_attach')
attach.document_type = formdef.fields[0].document_type
attach.by = ['_submitter']
display_form = st1.add_action('form')
display_form.formdef = WorkflowFormFieldsFormDef(item=display_form)
display_form.formdef.fields = formdef.fields
wf.store()
resp = resp.click('Text files')
resp.forms[0]['mimetypes'] = 'application/vnd.oasis.opendocument.text, .doc, .docx, .pdf'
resp = resp.forms[0].submit('submit')
@ -801,6 +826,46 @@ def test_settings_filetypes_update(pub):
],
'label': 'Text files',
}
assert CardDef.get(carddef.id).fields[0].document_type == {
'id': 1,
'mimetypes': [
'application/vnd.oasis.opendocument.text',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/pdf',
],
'label': 'Text files',
}
assert BlockDef.get(blockdef.id).fields[0].document_type == {
'id': 1,
'mimetypes': [
'application/vnd.oasis.opendocument.text',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/pdf',
],
'label': 'Text files',
}
assert Workflow.get(wf.id).possible_status[0].items[0].document_type == {
'id': 1,
'mimetypes': [
'application/vnd.oasis.opendocument.text',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/pdf',
],
'label': 'Text files',
}
assert Workflow.get(wf.id).possible_status[0].items[1].formdef.fields[0].document_type == {
'id': 1,
'mimetypes': [
'application/vnd.oasis.opendocument.text',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/pdf',
],
'label': 'Text files',
}
resp = app.get('/backoffice/settings/filetypes/')
resp = resp.click('Text files')

View File

@ -37,7 +37,7 @@ from wcs.blocks import BlockDef, BlockdefImportError
from wcs.carddef import CardDef
from wcs.data_sources import NamedDataSource
from wcs.fields import MapOptionsMixin
from wcs.formdef import FormDef, FormdefImportError
from wcs.formdef import FormDef, FormdefImportError, get_formdefs_of_all_kinds
from wcs.qommon import _, errors, get_cfg, ident, misc, template
from wcs.qommon.admin.cfg import cfg_submit
from wcs.qommon.admin.emails import EmailsDirectory
@ -441,9 +441,21 @@ class FileTypesDirectory(Directory):
old_filetype = filetype.copy()
filetype['label'] = form.get_widget('label').parse()
filetype['mimetypes'] = self.parse_mimetypes(form.get_widget('mimetypes').parse())
FormDef.update_filetype(filetype_id, old_filetype, filetype)
get_publisher().write_cfg()
return redirect('.')
if filetype == old_filetype:
return redirect('./')
job = get_response().add_after_job(
FileTypeUpdateAfterJob(

Au-delà de ce que je notais dans le ticket, je transforme ici en afterjob.

Au-delà de ce que je notais dans le ticket, je transforme ici en afterjob.
label=_('Updating fields'),
return_url='/backoffice/settings/filetypes/',
filetype_id=filetype_id,
new_filetype=filetype,
)
)
job.store()
return redirect(job.get_processing_url())
if form.get_submit() == 'delete':
del filetypes_cfg[filetype_id]
@ -1309,3 +1321,50 @@ $('#form_default-zoom-level').on('change', function() {
('error_email', 'debug_mode', 'mail_redirection'),
)
return redirect('.')
class FileTypeUpdateAfterJob(AfterJob):
def done_action_url(self):
return self.kwargs['return_url']
def done_button_attributes(self):
return {'data-redirect-auto': 'true'}
def done_action_label(self):
return _('Back to settings')
def execute(self):
self.report_lines = []
formdefs = get_formdefs_of_all_kinds()
self.total_count = len(formdefs) + Workflow.count()
self.store()
filetype_id = self.kwargs['filetype_id']
new_filetype = self.kwargs['new_filetype']
def update_document_type(obj):
if getattr(obj, 'document_type', None) and obj.document_type['id'] == filetype_id:

ce que ne demandait pas non plus le ticket : passer sur tous les types de formdef.

ce que ne demandait pas non plus le ticket : passer sur tous les types de formdef.
old_filetype = obj.document_type.copy()
del old_filetype['id']
if old_filetype != new_filetype:
obj.document_type = new_filetype.copy()
obj.document_type['id'] = filetype_id
return True
return False
for formdef in get_formdefs_of_all_kinds():
# look for file fields to update them with the new mimetypes.
changed = False
for field in formdef.fields or []:
changed |= update_document_type(field)
if changed:
formdef.store(comment=_('Automatic update of file types'))
self.increment_count()
for workflow in Workflow.select(ignore_errors=True, ignore_migration=True):
changed = False
for item in workflow.get_all_items():
if item.key == 'addattachment':
changed |= update_document_type(item)

Enfin ce que demandait le ticket : passer sur l'action "attacher un fichier".

Enfin ce que demandait le ticket : passer sur l'action "attacher un fichier".
if changed:
workflow.store(comment=_('Automatic update of file types'))
self.increment_count()

View File

@ -1783,30 +1783,6 @@ class FormDef(StorableObject):
return True
return False
@classmethod
def update_filetype(cls, filetype_id, previous_filetype, new_filetype):
# look for file fields in all formdefs, to update them with the
# new mimetypes.
if previous_filetype == new_filetype:
return
for formdef in cls.select():
changed = False
for field in formdef.fields:
if not hasattr(field, 'document_type'):
continue
if not field.document_type:
continue
if field.document_type['id'] == filetype_id:
previous_filetype = field.document_type.copy()
del previous_filetype['id']
if previous_filetype == new_filetype:
continue
field.document_type = new_filetype.copy()
field.document_type['id'] = filetype_id
changed = True
if changed:
formdef.store()
class _EmptyClass: # helper for instance creation without calling __init__
pass