0001-do-not-add-an-evolution-on-static-jump-22236.patch
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 |
- |