Add history revisions

issue3678
review3551002
This commit is contained in:
Cédric Krier
2014-03-18 19:54:32 +01:00
parent 7c151984e0
commit 335b0b6851
5 changed files with 94 additions and 2 deletions
+1
View File
@@ -1,3 +1,4 @@
* Add history revisions
* Add the multi selection widget
* Add index to one2many's on_change
* Remove auto-refresh on Action Window
+5
View File
@@ -401,6 +401,11 @@ Class methods:
Could be overrided to use a custom SQL query instead of a table of the
database. It should return a SQL FromItem.
.. classmethod:: ModelSQL.history_revisions(ids)
Return a sorted list of all revisions for ids. The list is composed of
the date, id and username of the revision.
.. classmethod:: ModelStorage.search(domain[, offset[, limit[, order[, count[, query]]]]])
Return a list of records that match the :ref:`domain <topics-domain>` or
+7
View File
@@ -68,6 +68,7 @@ class Model(ModelSQL, ModelView):
cls._order.insert(0, ('model', 'ASC'))
cls.__rpc__.update({
'list_models': RPC(),
'list_history': RPC(),
'global_search': RPC(),
})
@@ -129,6 +130,12 @@ class Model(ModelSQL, ModelView):
])
return [m.model for m in models]
@classmethod
def list_history(cls):
'Return a list of all models with history'
return [name for name, model in Pool().iterobject()
if getattr(model, '_history', False)]
@classmethod
def create(cls, vlist):
pool = Pool()
+42 -2
View File
@@ -1,8 +1,9 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
import re
import datetime
from functools import reduce
from itertools import islice, izip
from itertools import islice, izip, chain
from sql import Table, Column, Literal, Desc, Asc, Expression, Flavor
from sql.functions import Now, Extract
@@ -10,7 +11,7 @@ from sql.conditionals import Coalesce
from sql.operators import Or, And, Operator
from sql.aggregate import Count, Max
from trytond.model import ModelStorage
from trytond.model import ModelStorage, ModelView
from trytond.model import fields
from trytond import backend
from trytond.tools import reduce_ids
@@ -19,6 +20,7 @@ from trytond.transaction import Transaction
from trytond.pool import Pool
from trytond.cache import LRUDict
from trytond.exceptions import ConcurrencyException
from trytond.rpc import RPC
_RE_UNIQUE = re.compile('UNIQUE\s*\((.*)\)', re.I)
_RE_CHECK = re.compile('CHECK\s*\((.*)\)', re.I)
@@ -38,6 +40,10 @@ class ModelSQL(ModelStorage):
cls._sql_constraints = []
cls._order = [('id', 'ASC')]
cls._sql_error_messages = {}
if issubclass(cls, ModelView):
cls.__rpc__.update({
'history_revisions': RPC(),
})
if not cls._table:
cls._table = cls.__name__.replace('.', '_')
@@ -228,6 +234,40 @@ class ModelSQL(ModelStorage):
if name in exception[0]:
cls.raise_user_error(error)
@classmethod
def history_revisions(cls, ids):
pool = Pool()
ModelAccess = pool.get('ir.model.access')
User = pool.get('res.user')
cursor = Transaction().cursor
ModelAccess.check(cls.__name__, 'read')
table = cls.__table_history__()
user = User.__table__()
revisions = []
in_max = cursor.IN_MAX
for i in range(0, len(ids), in_max):
sub_ids = ids[i:i + in_max]
where = reduce_ids(table.id, sub_ids)
cursor.execute(*table.join(user, 'LEFT',
Coalesce(table.write_uid, table.create_uid) == user.id)
.select(
Coalesce(table.write_date, table.create_date),
table.id,
user.name,
where=where))
revisions.append(cursor.fetchall())
revisions = list(chain(*revisions))
revisions.sort(reverse=True)
# SQLite uses char for COALESCE
if revisions and isinstance(revisions[0][0], basestring):
strptime = datetime.datetime.strptime
format_ = '%Y-%m-%d %H:%M:%S.%f'
revisions = [(strptime(timestamp, format_), id_, name)
for timestamp, id_, name in revisions]
return revisions
@classmethod
def __insert_history(cls, ids, deleted=False):
transaction = Transaction()
+39
View File
@@ -104,6 +104,45 @@ class HistoryTestCase(unittest.TestCase):
history = History(history_id)
self.assertEqual(history.value, value)
def test0030history_revisions(self):
'Test history revisions'
History = POOL.get('test.history')
with Transaction().start(DB_NAME, USER,
context=CONTEXT) as transaction:
history = History(value=1)
history.save()
history_id = history.id
first = history.create_date
transaction.cursor.commit()
with Transaction().start(DB_NAME, USER,
context=CONTEXT) as transaction:
history = History(history_id)
history.value = 2
history.save()
second = history.write_date
transaction.cursor.commit()
with Transaction().start(DB_NAME, USER,
context=CONTEXT) as transaction:
history = History(history_id)
history.value = 3
history.save()
third = history.write_date
transaction.cursor.commit()
with Transaction().start(DB_NAME, USER, context=CONTEXT):
revisions = History.history_revisions([history_id])
self.assertEqual(revisions, [
(third, history_id, u'Administrator'),
(second, history_id, u'Administrator'),
(first, history_id, u'Administrator'),
])
def suite():
return unittest.TestLoader().loadTestsFromTestCase(HistoryTestCase)