Projet

Général

Profil

0001-do-not-add-an-evolution-on-static-jump-22236.patch

Thomas Noël, 01 mai 2018 18:45

Télécharger (15,8 ko)

Voir les différences:

Subject: [PATCH] do not add an evolution on static jump (#22236)

 tests/test_form_pages.py     | 38 ++++++++++++++++++++++++++++----
 tests/test_sql.py            |  2 ++
 wcs/admin/forms.py           |  4 +---
 wcs/backoffice/management.py |  2 +-
 wcs/formdata.py              | 24 ++++++++++++++++-----
 wcs/sql.py                   | 42 ++++++++++++++++++++++++++++--------
 wcs/wf/jump.py               |  5 +----
 wcs/workflows.py             |  4 ++--
 8 files changed, 93 insertions(+), 28 deletions(-)
tests/test_form_pages.py
1 1
# -*- coding: utf-8 -*-
2 2

  
3
import datetime
3 4
import json
4 5
import pytest
5 6
import hashlib
......
3766 3767
    user.roles = [role.id]
3767 3768
    user.store()
3768 3769

  
3770
    assert len(formdef.data_class().get(formdata.id).evolution) == 1
3771
    assert formdef.data_class().get(formdata.id).evolution[0].last_jump_time is None
3772

  
3769 3773
    login(app, username='foo', password='foo')
3770 3774
    resp = app.post(formdata.get_url() + 'jump/trigger/XXX', status=302)
3775
    formdata = formdef.data_class().get(formdata.id)
3776
    # status is not changed: no new evolution, only a new last_jump_time
3777
    assert len(formdata.evolution) == 1
3778
    assert formdata.status == 'wf-st1'
3779
    assert formdata.evolution[0].last_jump_time is not None
3780

  
3781
    # add a comment to last evolution, forcing create a new one
3782
    formdata.evolution[-1].comment = 'new-evolution-1'
3783
    formdata.store()
3771 3784
    resp = app.post(formdata.get_url() + 'jump/trigger/XXX', status=302)
3785
    formdata = formdef.data_class().get(formdata.id)
3786
    assert len(formdata.evolution) == 2
3787
    assert formdata.status == 'wf-st1'
3788

  
3789
    # again
3790
    formdata.evolution[-1].comment = 'new-evolution-2'
3791
    formdata.store()
3772 3792
    resp = app.post(formdata.get_url() + 'jump/trigger/XXX', status=302)
3773 3793

  
3774
    assert len(formdef.data_class().get(formdata.id).evolution) == 4
3775
    assert formdef.data_class().get(formdata.id).status == 'wf-st1'
3794
    # last evolution is empty, this last trigger does not create a new one
3795
    resp = app.post(formdata.get_url() + 'jump/trigger/XXX', status=302)
3796

  
3797
    # finally, 3 evolutions: new-evolution-1, new-evolution-2, empty
3798
    formdata = formdef.data_class().get(formdata.id)
3799
    assert len(formdata.evolution) == 3
3800
    assert formdata.status == 'wf-st1'
3801
    assert formdata.evolution[0].comment == 'new-evolution-1'
3802
    assert formdata.evolution[1].comment == 'new-evolution-2'
3803
    assert formdata.evolution[2].comment is None
3776 3804

  
3777 3805
    resp = app.get(formdata.get_url())
3778
    assert resp.body.count('Status1') == 2 # once in summary and once in journal
3779
    assert resp.body.count('CSS-STATUS1') == 1
3806
    assert resp.body.count('Status1') == 3 # once in summary and two in journal
3807
    assert resp.body.count('CSS-STATUS1') == 2
3808
    assert resp.body.count('new-evolution-1') == 1
3809
    assert resp.body.count('new-evolution-2') == 1
3780 3810

  
3781 3811
def test_display_message(pub):
3782 3812
    user = create_user(pub)
tests/test_sql.py
1456 1456
    formdata1 = data_class()
1457 1457
    formdata1.status = 'wf-st1'
1458 1458
    formdata1.just_created()
1459
    formdata1.evolution[0].comment = 'comment'
1459 1460
    formdata1.jump_status('st1') # will add another evolution entry
1460 1461
    formdata1.evolution[0].time = datetime.datetime(2015, 1, 1, 0, 0, 0).timetuple()
1461 1462
    formdata1.evolution[1].time = datetime.datetime(2015, 1, 2, 0, 0, 0).timetuple()
......
1464 1465
    formdata2 = data_class()
1465 1466
    formdata2.status = 'wf-st1'
1466 1467
    formdata2.just_created()
1468
    formdata2.evolution[0].comment = 'comment'
1467 1469
    formdata2.jump_status('st1') # will add another evolution entry
1468 1470
    formdata2.evolution[0].time = datetime.datetime(2015, 1, 3, 0, 0, 0).timetuple()
1469 1471
    formdata2.evolution[1].time = datetime.datetime(2015, 1, 4, 0, 0, 0).timetuple()
wcs/admin/forms.py
1156 1156
                if form.get_widget('date').parse():
1157 1157
                    date = form.get_widget('date').parse()
1158 1158
                    date = time.strptime(date, misc.date_format())
1159
                    all_forms = [x for x in all_forms if (
1160
                        x.evolution and x.evolution[-1].time < date) or (
1161
                        x.receipt_time < date)]
1159
                    all_forms = [x for x in all_forms if x.get_last_update_time() < date]
1162 1160

  
1163 1161
                self.fd = StringIO()
1164 1162
                t = tarfile.open('wcs.tar.gz', 'w:gz', fileobj=self.fd)
wcs/backoffice/management.py
1878 1878

  
1879 1879
        for status, status_id in possible_status:
1880 1880
            res_time_forms = [
1881
                    (time.mktime(x.evolution[-1].time) - time.mktime(x.receipt_time)) \
1881
                    (time.mktime(x.get_last_update_time()) - time.mktime(x.receipt_time)) \
1882 1882
                    for x in values if x.status == status and x.evolution]
1883 1883
            if not res_time_forms:
1884 1884
                continue
wcs/formdata.py
131 131
    who = None
132 132
    status = None
133 133
    time = None
134
    last_jump_time = None
134 135
    comment = None
135 136
    parts = None
136 137

  
......
179 180
    def get_json_export_dict(self, user, anonymise=False):
180 181
        data = {
181 182
            'time': self.time,
183
            'last_jump_time': self.last_jump_time,
182 184
        }
183 185
        if self.status:
184 186
            data['status'] = self.status[3:]
......
536 538
            previous_status = self.pop_previous_marked_status()
537 539
            assert previous_status, 'failed to compute previous status'
538 540
            status_id = previous_status.id
539
        evo = Evolution(self)
540
        evo.time = time.localtime()
541
        evo.status = 'wf-%s' % status_id
541
        status = 'wf-%s' % status_id
542 542
        if not self.evolution:
543 543
            self.evolution = []
544
        elif (self.status == status
545
              and self.evolution[-1].status == status
546
              and not self.evolution[-1].comment
547
              and not self.evolution[-1].display_parts()):
548
            # if status do not change and last evolution is empty,
549
            # just update last jump time on last evolution, do not add one
550
            self.evolution[-1].last_jump_time = time.localtime()
551
            self.store()
552
            return
553
        evo = Evolution(self)
554
        evo.time = time.localtime()
555
        evo.status = status
544 556
        self.evolution.append(evo)
545
        self.status = evo.status
557
        self.status = status
546 558
        self.store()
547 559

  
548 560
    def get_url(self, backoffice = False):
......
830 842
    def get_last_update_time(self):
831 843
        if hasattr(self, '_last_update_time'):
832 844
            return self._last_update_time
833
        if self.evolution and self.evolution[-1].time:
845
        if self.evolution and self.evolution[-1].last_jump_time:
846
            return self.evolution[-1].last_jump_time
847
        elif self.evolution and self.evolution[-1].time:
834 848
            return self.evolution[-1].time
835 849
        else:
836 850
            return self.receipt_time
wcs/sql.py
371 371
                                    who varchar,
372 372
                                    status varchar,
373 373
                                    time timestamp,
374
                                    last_jump_time timestamp,
374 375
                                    comment text,
375 376
                                    parts bytea,
376 377
                                    formdata_id integer REFERENCES %s (id) ON DELETE CASCADE)''' % (
......
463 464
    for field in (existing_fields - needed_fields):
464 465
        cur.execute('''ALTER TABLE %s DROP COLUMN %s CASCADE''' % (table_name, field))
465 466

  
467
    # migrations on _evolutions table
468
    cur.execute('''SELECT column_name FROM information_schema.columns
469
                    WHERE table_schema = 'public'
470
                      AND table_name = '%s_evolutions'
471
                ''' % table_name)
472
    evo_existing_fields = set([x[0] for x in cur.fetchall()])
473
    if 'last_jump_time' not in evo_existing_fields:
474
        cur.execute('''ALTER TABLE %s_evolutions ADD COLUMN last_jump_time timestamp''' % table_name)
475

  
466 476
    if rebuild_views or len(existing_fields - needed_fields):
467 477
        # views may have been dropped when dropping columns, so we recreate
468 478
        # them even if not asked to.
......
1192 1202
            self._evolution = []
1193 1203
            return self._evolution
1194 1204
        conn, cur = get_connection_and_cursor()
1195
        sql_statement = '''SELECT id, who, status, time, comment, parts FROM %s_evolutions
1205
        sql_statement = '''SELECT id, who, status, time, last_jump_time,
1206
                                  comment, parts FROM %s_evolutions
1196 1207
                            WHERE formdata_id = %%(id)s
1197 1208
                         ORDER BY id''' % self._table_name
1198 1209
        cur.execute(sql_statement, {'id': self.id})
......
1209 1220
    @classmethod
1210 1221
    def _row2evo(cls, row, formdata):
1211 1222
        o = wcs.formdata.Evolution(formdata)
1212
        o._sql_id, o.who, o.status, o.time, o.comment = [str_encode(x) for x in tuple(row[:5])]
1223
        o._sql_id, o.who, o.status, o.time, o.last_jump_time, o.comment = [
1224
                str_encode(x) for x in tuple(row[:6])]
1213 1225
        if o.time:
1214 1226
            o.time = o.time.timetuple()
1215
        if row[5]:
1216
            o.parts = cPickle.loads(str(row[5]))
1227
        if o.last_jump_time:
1228
            o.last_jump_time = o.last_jump_time.timetuple()
1229
        if row[6]:
1230
            o.parts = cPickle.loads(str(row[6]))
1217 1231
        return o
1218 1232

  
1219 1233
    def set_evolution(self, value):
......
1234 1248
        if not object_dict:
1235 1249
            return
1236 1250
        conn, cur = get_connection_and_cursor()
1237
        sql_statement = '''SELECT id, who, status, time, comment, parts, formdata_id
1251
        sql_statement = '''SELECT id, who, status, time, last_jump_time,
1252
                                  comment, parts, formdata_id
1238 1253
                             FROM %s_evolutions''' % cls._table_name
1239 1254
        sql_statement += ''' WHERE formdata_id IN %(object_ids)s ORDER BY id'''
1240 1255
        cur.execute(sql_statement, {'object_ids': tuple(object_dict.keys())})
......
1246 1261
            row = cur.fetchone()
1247 1262
            if row is None:
1248 1263
                break
1249
            _sql_id, who, status, time, comment, parts, formdata_id = tuple(row[:7])
1264
            _sql_id, who, status, time, last_jump_time, comment, parts, formdata_id = tuple(row[:8])
1250 1265
            formdata = object_dict.get(formdata_id)
1251 1266
            if not formdata:
1252 1267
                continue
......
1340 1355
                    sql_dict.update({'id': evo._sql_id})
1341 1356
                    sql_statement = '''UPDATE %s_evolutions SET
1342 1357
                                        time = %%(time)s,
1358
                                        last_jump_time = %%(last_jump_time)s,
1343 1359
                                        status = %%(status)s,
1344 1360
                                        comment = %%(comment)s,
1345 1361
                                        parts = %%(parts)s
......
1348 1364
                else:
1349 1365
                    sql_statement = '''INSERT INTO %s_evolutions (
1350 1366
                                               id, who, status,
1351
                                               time, comment, parts,
1367
                                               time, last_jump_time,
1368
                                               comment, parts,
1352 1369
                                               formdata_id)
1353 1370
                                        VALUES (DEFAULT, %%(who)s, %%(status)s,
1354
                                                %%(time)s, %%(comment)s,
1371
                                                %%(time)s, %%(last_jump_time)s,
1372
                                                %%(comment)s,
1355 1373
                                                %%(parts)s, %%(formdata_id)s)
1356 1374
                                     RETURNING id''' % self._table_name
1375
                if evo.last_jump_time:
1376
                    last_jump_time = datetime.datetime.fromtimestamp(time.mktime(evo.last_jump_time))
1377
                else:
1378
                    last_jump_time = None
1357 1379
                sql_dict.update({
1358 1380
                        'who': evo.who,
1359 1381
                        'status': evo.status,
1360 1382
                        'time': datetime.datetime.fromtimestamp(time.mktime(evo.time)),
1383
                        'last_jump_time': last_jump_time,
1361 1384
                        'comment': evo.comment,
1362 1385
                        'formdata_id': self.id,
1363 1386
                })
......
2105 2128
    return result
2106 2129

  
2107 2130

  
2108
SQL_LEVEL = 25
2131
SQL_LEVEL = 26
2109 2132

  
2110 2133
def migrate_global_views(conn, cur):
2111 2134
    cur.execute('''SELECT COUNT(*) FROM information_schema.tables
......
2179 2202
        # 19: add geolocation to views
2180 2203
        # 20: remove user hash stuff
2181 2204
        # 22: rebuild views
2205
        # 26: add last_jump_time in evolutions tables
2182 2206
        migrate_views(conn, cur)
2183 2207
    if sql_level < 21:
2184 2208
        # 3: introduction of _structured for user fields
wcs/wf/jump.py
235 235

  
236 236
        if self.timeout:
237 237
            timeout = int(self.compute(self.timeout))
238
            if formdata.evolution:
239
                last = formdata.evolution[-1].time
240
            else:
241
                last = formdata.receipt_time
238
            last = formdata.get_last_update_time()
242 239
            if last:
243 240
                diff = time.time() - time.mktime(last)
244 241
                must_jump = (diff > timeout) and must_jump
wcs/workflows.py
1033 1033
            anchor_status = self.anchor_status_first or formdata.status
1034 1034
            for evolution in formdata.evolution:
1035 1035
                if evolution.status == anchor_status:
1036
                    anchor_date = evolution.time
1036
                    anchor_date = evolution.last_jump_time or evolution.time
1037 1037
                    break
1038 1038
        elif self.anchor == 'latest-arrival':
1039 1039
            anchor_status = self.anchor_status_latest or formdata.status
1040 1040
            for evolution in reversed(formdata.evolution):
1041 1041
                if evolution.status == anchor_status:
1042
                    anchor_date = evolution.time
1042
                    anchor_date = evolution.last_jump_time or evolution.time
1043 1043
                    break
1044 1044
        elif self.anchor == 'python':
1045 1045
            variables = get_publisher().substitutions.get_context_variables()
1046
-