snapshots: remove last_modification time & user from instances (#48255)

This commit is contained in:
Lauréline Guérin 2020-11-10 13:48:10 +01:00
parent 20159ae39b
commit 6899480328
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
10 changed files with 44 additions and 109 deletions

View File

@ -61,7 +61,7 @@ def test_forms(pub):
def test_forms_new(pub):
user = create_superuser(pub)
create_superuser(pub)
app = login(get_app(pub))
create_role()
@ -81,12 +81,11 @@ def test_forms_new(pub):
assert formdef.url_name == 'form-title'
assert formdef.fields == []
assert formdef.disabled == True
assert formdef.last_modification_user_id == str(user.id)
def test_forms_new_popup(pub):
FormDef.wipe()
user = create_superuser(pub)
create_superuser(pub)
app = login(get_app(pub))
create_role()
@ -107,7 +106,6 @@ def test_forms_new_popup(pub):
assert formdef.url_name == 'form-title'
assert formdef.fields == []
assert formdef.disabled == True
assert formdef.last_modification_user_id == str(user.id)
def assert_option_display(resp, label, value):

View File

@ -602,8 +602,7 @@ def test_formdef_schema(pub):
# check schema
assert resp.json == resp2.json
assert set(resp.json.keys()) >= set(['enable_tracking_codes', 'url_name', 'description',
'workflow', 'expiration_date', 'discussion',
'last_modification_time', 'has_captcha',
'workflow', 'expiration_date', 'discussion', 'has_captcha',
'always_advertise', 'name', 'disabled', 'only_allow_one',
'fields', 'keywords',
'publication_date', 'detailed_emails',

View File

@ -189,15 +189,6 @@ def test_include_id():
assert f2.fields[4].id == formdef.fields[4].id
def test_modification_time():
formdef = FormDef()
formdef.name = 'empty'
formdef.last_modification_time = time.localtime()
assert_xml_import_export_works(formdef)
f2 = assert_json_import_export_works(formdef)
assert tuple(f2.last_modification_time)[:6] == tuple(formdef.last_modification_time)[:6]
def test_workflow_options():
formdef = FormDef()
formdef.name = 'workflow options'

View File

@ -76,12 +76,6 @@ def test_snapshot_basics(pub):
data_source.store()
assert pub.snapshot_class.count() == 5
# check calling .store() without changes doesn't create snapshots
# (this cannot be done on formdefs/carddefs as they embed a modification
# time)
data_source.store()
assert pub.snapshot_class.count() == 5
# check we got correct data in the serializations
snapshot = pub.snapshot_class.get_latest('formdef', formdef.id)
assert '>testform2<' in snapshot.serialization
@ -232,6 +226,10 @@ def test_block_snapshot_browse(pub, blocks_feature):
blockdef.name = 'testblock'
blockdef.fields = []
blockdef.store()
assert pub.snapshot_class.count() == 1
# check calling .store() without changes doesn't create snapshots
blockdef.store()
assert pub.snapshot_class.count() == 1
app = login(get_app(pub))
@ -250,6 +248,10 @@ def test_card_snapshot_browse(pub):
carddef.name = 'testcard'
carddef.fields = []
carddef.store()
assert pub.snapshot_class.count() == 1
# check calling .store() without changes doesn't create snapshots
carddef.store()
assert pub.snapshot_class.count() == 1
pub.custom_view_class.wipe()
custom_view = pub.custom_view_class()
@ -287,6 +289,10 @@ def test_datasource_snapshot_browse(pub):
datasource.data_source = {'type': 'formula',
'value': repr([('1', 'un'), ('2', 'deux')])}
datasource.store()
assert pub.snapshot_class.count() == 1
# check calling .store() without changes doesn't create snapshots
datasource.store()
assert pub.snapshot_class.count() == 1
app = login(get_app(pub))
@ -316,6 +322,10 @@ def test_form_snapshot_browse(pub, formdef_with_history):
formdef_with_history.name = 'testform 5'
formdef_with_history.description = 'this is a description (5)'
formdef_with_history.store()
assert pub.snapshot_class.count() == 7
# check calling .store() without changes doesn't create snapshots
formdef_with_history.store()
assert pub.snapshot_class.count() == 7
# delete custom views
pub.custom_view_class.wipe()
@ -337,6 +347,10 @@ def test_workflow_snapshot_browse(pub):
Workflow.wipe()
workflow = Workflow(name='test')
workflow.store()
assert pub.snapshot_class.count() == 1
# check calling .store() without changes doesn't create snapshots
workflow.store()
assert pub.snapshot_class.count() == 1
app = login(get_app(pub))
@ -394,6 +408,10 @@ def test_wscall_snapshot_browse(pub):
NamedWsCall.wipe()
wscall = NamedWsCall(name='test')
wscall.store()
assert pub.snapshot_class.count() == 1
# check calling .store() without changes doesn't create snapshots
wscall.store()
assert pub.snapshot_class.count() == 1
app = login(get_app(pub))

View File

@ -26,20 +26,21 @@ from qommon import _, misc
def last_modification_block(obj):
r = TemplateIO(html=True)
if obj.last_modification_time:
timestamp, user_id = obj.get_last_modification_info()
if timestamp:
warning_class = ''
if (time.time() - time.mktime(obj.last_modification_time)) < 600:
if get_request().user and str(get_request().user.id) != obj.last_modification_user_id:
if (time.time() - timestamp.timestamp()) < 600:
if get_request().user and str(get_request().user.id) != user_id:
warning_class = 'recent'
r += htmltext('<p class="last-modification %s">') % warning_class
r += _('Last Modification:')
r += ' '
r += misc.localstrftime(obj.last_modification_time)
r += misc.localstrftime(timestamp)
r += ' '
if obj.last_modification_user_id:
if user_id:
try:
r += _('by %s') % get_publisher().user_class.get(
obj.last_modification_user_id).display_name
r += _('by %s') % get_publisher().user_class.get(user_id).display_name
except KeyError:
pass
r += htmltext('</p>')

View File

@ -15,7 +15,6 @@
# along with this program; if not, see <http://www.gnu.org/licenses/>.
import uuid
import time
import xml.etree.ElementTree as ET
from quixote import get_request, get_publisher
@ -46,9 +45,6 @@ class BlockDef(StorableObject):
fields = None
digest_template = None
last_modification_time = None
last_modification_user_id = None
# declarations for serialization
TEXT_ATTRIBUTES = ['name', 'slug', 'digest_template']
@ -63,12 +59,6 @@ class BlockDef(StorableObject):
# set slug if it's not yet there
self.slug = self.get_new_slug()
self.last_modification_time = time.localtime()
if get_request() and get_request().user:
self.last_modification_user_id = str(get_request().user.id)
else:
self.last_modification_user_id = None
super().store()
if get_publisher().snapshot_class:
get_publisher().snapshot_class.snap(instance=self, comment=comment)
@ -114,12 +104,6 @@ class BlockDef(StorableObject):
continue
ET.SubElement(root, text_attribute).text = getattr(self, text_attribute)
if self.last_modification_time:
elem = ET.SubElement(root, 'last_modification')
elem.text = time.strftime('%Y-%m-%d %H:%M:%S', self.last_modification_time)
if include_id:
elem.attrib['user_id'] = str(self.last_modification_user_id)
fields = ET.SubElement(root, 'fields')
for field in self.fields or []:
fields.append(field.export_to_xml(charset='utf-8', include_id=True))
@ -189,12 +173,6 @@ class BlockDef(StorableObject):
field_o.init_with_xml(field, charset, include_id=True)
blockdef.fields.append(field_o)
if tree.find('last_modification') is not None:
node = tree.find('last_modification')
blockdef.last_modification_time = time.strptime(node.text, '%Y-%m-%d %H:%M:%S')
if include_id and node.attrib.get('user_id'):
blockdef.last_modification_user_id = node.attrib.get('user_id')
return blockdef
def get_usage_formdefs(self):

View File

@ -122,9 +122,6 @@ class FormDef(StorableObject):
geolocations = None
last_modification_time = None
last_modification_user_id = None
max_field_id = None
# store fields in a separate pickle chunk
@ -233,10 +230,6 @@ class FormDef(StorableObject):
changed = True
break
if type(self.last_modification_user_id) is int:
self.last_modification_user_id = str(self.last_modification_user_id)
changed = True
if self.workflow_roles:
workflow_roles_list = self.workflow_roles.items()
for role_key, role_id in self.workflow_roles.items():
@ -384,11 +377,6 @@ class FormDef(StorableObject):
# or if there are not yet any submitted forms
if self.id is None or self.data_class().count() == 0:
self.internal_identifier = new_internal_identifier
self.last_modification_time = time.localtime()
if get_request() and get_request().user:
self.last_modification_user_id = str(get_request().user.id)
else:
self.last_modification_user_id = None
t = StorableObject.store(self)
if get_publisher().snapshot_class:
get_publisher().snapshot_class.snap(instance=self, comment=comment)
@ -775,10 +763,6 @@ class FormDef(StorableObject):
more_attributes = []
if self.max_field_id:
more_attributes.append('max_field_id')
if self.last_modification_time:
more_attributes.append('last_modification_time')
if include_id:
more_attributes.append('last_modification_user_id')
for attribute in self.TEXT_ATTRIBUTES + self.BOOLEAN_ATTRIBUTES + more_attributes:
if not hasattr(self, attribute):
@ -858,17 +842,11 @@ class FormDef(StorableObject):
formdef.workflow_id = w.id
break
more_attributes = ['max_field_id', 'last_modification_time',
'last_modification_user_id']
more_attributes = ['max_field_id']
for attribute in cls.TEXT_ATTRIBUTES + cls.BOOLEAN_ATTRIBUTES + more_attributes:
if attribute in value:
setattr(formdef, attribute, value.get(attribute))
# fixup last_modification_time to the proper type
if formdef.last_modification_time:
formdef.last_modification_time = time.strptime(
formdef.last_modification_time, '%Y-%m-%dT%H:%M:%S')
formdef.fields = []
for i, field in enumerate(value.get('fields', [])):
try:
@ -942,12 +920,6 @@ class FormDef(StorableObject):
if self.max_field_id:
ET.SubElement(root, 'max_field_id').text = str(self.max_field_id)
if self.last_modification_time:
elem = ET.SubElement(root, 'last_modification')
elem.text = time.strftime('%Y-%m-%d %H:%M:%S', self.last_modification_time)
if include_id:
elem.attrib['user_id'] = str(self.last_modification_user_id)
fields = ET.SubElement(root, 'fields')
for field in self.fields or []:
fields.append(field.export_to_xml(charset=charset, include_id=include_id))
@ -1140,12 +1112,6 @@ class FormDef(StorableObject):
view_o.init_with_xml(view, charset)
formdef._custom_views.append(view_o)
if tree.find('last_modification') is not None:
node = tree.find('last_modification')
formdef.last_modification_time = time.strptime(node.text, '%Y-%m-%d %H:%M:%S')
if include_id and node.attrib.get('user_id'):
formdef.last_modification_user_id = node.attrib.get('user_id')
if tree.find('category') is not None:
category_node = tree.find('category')
if include_id and category_node.attrib.get('category_id'):

View File

@ -1271,7 +1271,6 @@ class FormPage(Directory, FormTemplateMixin):
def submitted(self, form, existing_formdata = None):
if existing_formdata: # modifying
filled = existing_formdata
filled.last_modification_time = time.localtime()
# XXX: what about status?
else:
filled = self.get_current_draft() or self.formdef.data_class()()

View File

@ -844,6 +844,14 @@ class StorableObject(object):
assert not self.is_readonly()
self.remove_object(self.id)
def get_last_modification_info(self):
if not get_publisher().snapshot_class:
return None, None
snapshots = get_publisher().snapshot_class.select_object_history(self)
if not snapshots:
return None, None
return snapshots[0].timestamp, snapshots[0].user_id
@classmethod
def wipe(cls):
tmpdir = tempfile.mkdtemp(prefix='wiping', dir=os.path.join(get_publisher().app_dir))

View File

@ -343,9 +343,6 @@ class Workflow(StorableObject):
global_actions = None
criticality_levels = None
last_modification_time = None
last_modification_user_id = None
def __init__(self, name = None):
StorableObject.__init__(self)
self.name = name
@ -399,11 +396,6 @@ class Workflow(StorableObject):
elif self.backoffice_fields_formdef:
must_update = True
self.last_modification_time = time.localtime()
if get_request() and get_request().user:
self.last_modification_user_id = str(get_request().user.id)
else:
self.last_modification_user_id = None
StorableObject.store(self)
if get_publisher().snapshot_class:
get_publisher().snapshot_class.snap(instance=self, comment=comment)
@ -584,12 +576,6 @@ class Workflow(StorableObject):
role_node.attrib['id'] = role_id
role_node.text = force_text(role_label, charset)
if self.last_modification_time:
elem = ET.SubElement(root, 'last_modification')
elem.text = time.strftime('%Y-%m-%d %H:%M:%S', self.last_modification_time)
if include_id:
elem.attrib['user_id'] = str(self.last_modification_user_id)
possible_status = ET.SubElement(root, 'possible_status')
for status in self.possible_status:
possible_status.append(status.export_to_xml(charset=charset,
@ -657,12 +643,6 @@ class Workflow(StorableObject):
for role_node in tree.findall('roles/role'):
workflow.roles[role_node.attrib['id']] = xml_node_text(role_node)
if tree.find('last_modification') is not None:
node = tree.find('last_modification')
workflow.last_modification_time = time.strptime(node.text, '%Y-%m-%d %H:%M:%S')
if include_id and node.attrib.get('user_id'):
workflow.last_modification_user_id = node.attrib.get('user_id')
workflow.possible_status = []
for status in tree.find('possible_status'):
status_o = WorkflowStatus()
@ -742,9 +722,6 @@ class Workflow(StorableObject):
root['name'] = force_text(self.name, charset)
if include_id and self.id:
root['id'] = str(self.id)
if self.last_modification_time:
root['last_modification_time'] = time.strftime('%Y-%m-%dT%H:%M:%S',
self.last_modification_time)
roles = root['functions'] = {}
for role, label in self.roles.items():
roles[role] = force_text(label, charset)