Projet

Général

Profil

0001-workflows-allow-to-run-create-document-non-interacti.patch

Frédéric Péters, 01 septembre 2016 15:47

Télécharger (13,4 ko)

Voir les différences:

Subject: [PATCH] workflows: allow to run "create document" non interactively
 (#12988)

 tests/test_form_pages.py  |  53 ++++++++++++++++++
 wcs/qommon/form.py        |   4 ++
 wcs/wf/export_to_model.py | 136 +++++++++++++++++++++++++++++-----------------
 3 files changed, 143 insertions(+), 50 deletions(-)
tests/test_form_pages.py
2340 2340
    assert resp.content_type == 'application/pdf'
2341 2341
    assert resp.body.startswith('%PDF-')
2342 2342

  
2343
def test_formdata_generated_document_non_interactive(pub):
2344
    create_user(pub)
2345
    wf = Workflow(name='status')
2346
    st1 = wf.add_status('Status1', 'st1')
2347
    export_to = ExportToModel()
2348
    export_to.method = 'non-interactive'
2349
    template_filename = os.path.join(os.path.dirname(__file__), 'template.odt')
2350
    template = open(template_filename).read()
2351
    upload = QuixoteUpload('/foo/template.odt', content_type='application/octet-stream')
2352
    upload.fp = StringIO.StringIO()
2353
    upload.fp.write(template)
2354
    upload.fp.seek(0)
2355
    export_to.model_file = UploadedFile(pub.app_dir, None, upload)
2356
    export_to.id = '_export_to'
2357
    export_to.attach_to_history = True
2358
    st1.items.append(export_to)
2359
    export_to.parent = st1
2360

  
2361
    jump = JumpWorkflowStatusItem()
2362
    jump.status = 'st2'
2363
    st1.items.append(jump)
2364
    jump.parent = st1
2365

  
2366
    st2 = wf.add_status('Status2', 'st2')
2367

  
2368
    wf.store()
2369

  
2370
    formdef = create_formdef()
2371
    formdef.workflow_id = wf.id
2372
    formdef.fields = [fields.TextField(id='0', label='comment', type='text', varname='comment')]
2373
    formdef.store()
2374
    formdef.data_class().wipe()
2375

  
2376
    resp = login(get_app(pub), username='foo', password='foo').get('/test/')
2377
    resp.form['f0'] = 'Hello\n\nWorld.'
2378
    resp = resp.forms[0].submit('submit')
2379
    assert 'Check values then click submit.' in resp.body
2380
    resp = resp.forms[0].submit('submit')
2381
    assert resp.status_int == 302
2382
    form_location = resp.location
2383
    resp = resp.follow()
2384
    assert 'The form has been recorded' in resp.body
2385

  
2386
    resp = resp.click('template.odt')
2387
    assert resp.location.endswith('/template.odt')
2388
    resp = resp.follow()
2389
    assert resp.content_type == 'application/octet-stream'
2390
    with open(os.path.join(os.path.dirname(__file__), 'template-out.odt')) as f:
2391
        assert_equal_zip(StringIO.StringIO(resp.body), f)
2392

  
2393
    assert formdef.data_class().count() == 1
2394
    assert formdef.data_class().select()[0].status == 'wf-st2'
2395

  
2343 2396
def test_formdata_form_file_download(pub):
2344 2397
    create_user(pub)
2345 2398
    wf = Workflow(name='status')
wcs/qommon/form.py
1317 1317
    def render(self):
1318 1318
        get_response().add_javascript(['jquery.js', 'widget_list.js'])
1319 1319
        r = TemplateIO(html=True)
1320
        if self.attrs:
1321
            r += htmltag('div', **self.attrs)
1320 1322
        r += self.render_title(self.get_title())
1321 1323
        r += self.render_error(self.get_error())
1322 1324
        add_element_widget = self.get_widget('add_element')
......
1326 1328
            r += widget.render()
1327 1329
        r += add_element_widget.render()
1328 1330
        r += self.render_hint(self.get_hint())
1331
        if self.attrs:
1332
            r += htmltext('</div>')
1329 1333
        return r.getvalue()
1330 1334

  
1331 1335
class WidgetDict(quixote.form.widget.WidgetDict):
wcs/wf/export_to_model.py
15 15
# along with this program; if not, see <http://www.gnu.org/licenses/>.
16 16

  
17 17
import base64
18
import collections
18 19
from StringIO import StringIO
19 20
from xml.etree import ElementTree as ET
20 21
import zipfile
......
29 30
from qommon import ezt, ods
30 31
from qommon.form import (SingleSelectWidget, WidgetList, CheckboxWidget,
31 32
                         StringWidget, UploadWidget, WysiwygTextWidget, Upload,
32
                         UploadedFile, UploadValidationError, VarnameWidget)
33
                         UploadedFile, UploadValidationError, VarnameWidget,
34
                         RadiobuttonsWidget)
33 35
from qommon.errors import PublishError
34 36
import qommon
35 37

  
......
180 182
    varname = None
181 183
    convert_to_pdf = False
182 184
    push_to_portfolio = False
185
    method = 'interactive'
183 186

  
184 187
    def render_as_line(self):
185
        if self.label:
186
            if self.model_file:
187
                model = _('with model named %(file_name)s of %(size)s bytes') % {
188
                    'file_name': self.model_file.base_filename,
189
                    'size': self.model_file.size}
190
            else:
191
                model = _('no model set')
192
            return _('Create document, labeled %(label)s, %(model)s') % {
193
                'label': self.label,
194
                'model': model}
188
        if self.model_file:
189
            model = _('with model named %(file_name)s of %(size)s bytes') % {
190
                'file_name': self.model_file.base_filename,
191
                'size': self.model_file.size}
195 192
        else:
196
            return _('Create document (not completed)')
193
            model = _('no model set')
194
        return _('Create document, %(model)s') %  {'model': model}
197 195

  
198 196
    def fill_form(self, form, formdata, user):
197
        if not self.method == 'interactive':
198
            return
199 199
        label = self.label
200 200
        if not label:
201 201
            label = _('Create Document')
......
204 204
        widget.backoffice_info_text = self.backoffice_info_text
205 205

  
206 206
    def submit_form(self, form, formdata, user, evo):
207
        if not self.method == 'interactive':
208
            return
207 209
        if not self.model_file:
208 210
            return
209 211
        if form.get_submit() == 'button%s' % self.id:
210 212
            if not evo.comment:
211 213
                evo.comment = _('Form exported in a model')
214
            self.perform_real(formdata, evo)
212 215
            in_backoffice = get_request() and get_request().is_in_backoffice()
213
            outstream = self.apply_template_to_formdata(formdata)
214
            filename = self.model_file.base_filename
215
            content_type = self.model_file.content_type
216
            if self.convert_to_pdf:
217
                filename = filename.rsplit('.', 1)[0] + '.pdf'
218
                content_type = 'application/pdf'
219
            if self.push_to_portfolio:
220
                push_document(formdata.get_user(), filename, outstream)
221 216
            if self.attach_to_history:
222
                evo.add_part(AttachmentEvolutionPart(
223
                    filename,
224
                    outstream,
225
                    content_type=content_type,
226
                    varname=self.varname))
227 217
                return formdata.get_url(backoffice=in_backoffice)
228 218
            base_url = formdata.get_url(backoffice=in_backoffice)
229 219
            return base_url + self.get_directory_name()
......
257 247

  
258 248
    def add_parameters_widgets(self, form, parameters, prefix='',
259 249
                               formdef=None):
260
        if 'by' in parameters:
261
            options = [(None, '---', None)] + self.get_list_of_roles()
262
            form.add(WidgetList, '%sby' % prefix, title=_('By'),
263
                     element_type=SingleSelectWidget,
264
                     value=self.by,
265
                     add_element_label=_('Add Role'),
266
                     element_kwargs={
267
                         'render_br': False,
268
                         'options': options})
269
        if 'attach_to_history' in parameters:
270
            form.add(CheckboxWidget, '%sattach_to_history' % prefix,
271
                     title=_('Attach generated file to the form history'),
272
                     value=self.attach_to_history)
273
        if 'label' in parameters:
274
            form.add(StringWidget, '%slabel' % prefix,
275
                     title=_('Button Label'),
276
                     value=self.label)
250
        methods = collections.OrderedDict(
251
                [('interactive', _('Interactive (button)')),
252
                 ('non-interactive', _('Non interactive'))])
277 253
        if 'model_file' in parameters:
278 254
            ids = (self.parent.parent.id, self.parent.id, self.id)
279 255
            if formdef:
......
304 280
            form.add(UploadWidget, widget_name, directory='models',
305 281
                     filename=filename, title=_('Model'), hint=hint,
306 282
                     validation=self.model_file_validation, value=value)
307
        if 'backoffice_info_text' in parameters:
308
            form.add(WysiwygTextWidget, '%sbackoffice_info_text' % prefix,
309
                     title=_('Information Text for Backoffice'),
310
                     value=self.backoffice_info_text)
311
        if 'varname' in parameters:
312
            form.add(VarnameWidget, '%svarname' % prefix,
313
                     title=_('Variable Name'), value=self.varname)
283
        if 'attach_to_history' in parameters:
284
            form.add(CheckboxWidget, '%sattach_to_history' % prefix,
285
                     title=_('Attach generated file to the form history'),
286
                     value=self.attach_to_history)
314 287
        if 'convert_to_pdf' in parameters:
315 288
            form.add(CheckboxWidget, '%sconvert_to_pdf' % prefix,
316 289
                     title=_('Convert generated file to PDF'),
......
319 292
            form.add(CheckboxWidget, '%spush_to_portfolio' % prefix,
320 293
                     title=_('Push generated file to portfolio'),
321 294
                     value=self.push_to_portfolio)
295
        if 'varname' in parameters:
296
            form.add(VarnameWidget, '%svarname' % prefix,
297
                     title=_('Variable Name'), value=self.varname)
298

  
299
        if 'method' in parameters:
300
            form.add(RadiobuttonsWidget, '%smethod' % prefix,
301
                    title=_('Method'),
302
                    options=methods.items(),
303
                    value=self.method,
304
                    attrs={'data-dynamic-display-parent': 'true'})
305

  
306
        if 'by' in parameters:
307
            options = [(None, '---', None)] + self.get_list_of_roles()
308
            form.add(WidgetList, '%sby' % prefix, title=_('By'),
309
                     element_type=SingleSelectWidget,
310
                     value=self.by,
311
                     add_element_label=_('Add Role'),
312
                     attrs={
313
                         'data-dynamic-display-child-of': '%smethod' % prefix,
314
                         'data-dynamic-display-value': methods.get('interactive'),
315
                     },
316
                     element_kwargs={
317
                         'render_br': False,
318
                         'options': options})
319

  
320
        if 'label' in parameters:
321
            form.add(StringWidget, '%slabel' % prefix,
322
                     title=_('Button Label'),
323
                     value=self.label,
324
                     attrs={
325
                         'data-dynamic-display-child-of': '%smethod' % prefix,
326
                         'data-dynamic-display-value': methods.get('interactive'),
327
                     })
328

  
329
        if 'backoffice_info_text' in parameters:
330
            form.add(WysiwygTextWidget, '%sbackoffice_info_text' % prefix,
331
                     title=_('Information Text for Backoffice'),
332
                     value=self.backoffice_info_text,
333
                     attrs={
334
                         'data-dynamic-display-child-of': '%smethod' % prefix,
335
                         'data-dynamic-display-value': methods.get('interactive'),
336
                     })
322 337

  
323 338
    def get_directory_name(self):
324 339
        return qommon.misc.simplify(self.label or 'export_to_model', space='_')
......
399 414
        return outstream
400 415

  
401 416
    def get_parameters(self):
402
        parameters = ('by', 'label', 'model_file', 'attach_to_history',
417
        parameters = ('method', 'by', 'label', 'model_file', 'attach_to_history',
403 418
                'backoffice_info_text', 'varname')
404 419
        if transform_to_pdf is not None:
405 420
            parameters += ('convert_to_pdf',)
......
435 450
        upload.fp.seek(0)
436 451
        self.model_file = UploadedFile('models', filename, upload)
437 452

  
453
    def perform(self, formdata):
454
        if self.method == 'interactive':
455
            return
456
        self.perform_real(formdata, formdata.evolution[-1])
457

  
458
    def perform_real(self, formdata, evo):
459
        outstream = self.apply_template_to_formdata(formdata)
460
        filename = self.model_file.base_filename
461
        content_type = self.model_file.content_type
462
        if self.convert_to_pdf:
463
            filename = filename.rsplit('.', 1)[0] + '.pdf'
464
            content_type = 'application/pdf'
465
        if self.push_to_portfolio:
466
            push_document(formdata.get_user(), filename, outstream)
467
        if self.attach_to_history:
468
            evo.add_part(AttachmentEvolutionPart(
469
                filename,
470
                outstream,
471
                content_type=content_type,
472
                varname=self.varname))
473

  
438 474
register_item_class(ExportToModel)
439
-