This commit is contained in:
parent
e56c295643
commit
5e922bcfc8
|
@ -208,7 +208,6 @@ def test_studio_home_recent_changes(pub):
|
|||
pub.cfg['admin-permissions'].update({'settings': ['x']})
|
||||
pub.write_cfg()
|
||||
|
||||
app = login(get_app(pub))
|
||||
resp = app.get('/backoffice/studio/')
|
||||
# no access to settings
|
||||
for i in range(6):
|
||||
|
@ -246,7 +245,6 @@ def test_studio_home_recent_changes(pub):
|
|||
pub.cfg['admin-permissions'].update({'settings': ['x'], 'forms': ['x']})
|
||||
pub.write_cfg()
|
||||
|
||||
app = login(get_app(pub))
|
||||
resp = app.get('/backoffice/studio/')
|
||||
# no access to settings or forms
|
||||
for i in range(6):
|
||||
|
@ -282,7 +280,6 @@ def test_studio_home_recent_changes(pub):
|
|||
pub.cfg['admin-permissions'].update({'settings': ['x'], 'forms': ['x'], 'workflows': ['x']})
|
||||
pub.write_cfg()
|
||||
|
||||
app = login(get_app(pub))
|
||||
resp = app.get('/backoffice/studio/')
|
||||
# no access to settings, forms or workflows
|
||||
for i in range(6):
|
||||
|
@ -307,7 +304,6 @@ def test_studio_home_recent_changes(pub):
|
|||
assert 'backoffice/cards/%s/' % objects[CardDef.xml_root_node][i].id in resp
|
||||
|
||||
objects[CardDef.xml_root_node][5].remove_self()
|
||||
app = login(get_app(pub))
|
||||
resp = app.get('/backoffice/studio/')
|
||||
# too old
|
||||
assert 'backoffice/cards/%s/' % objects[CardDef.xml_root_node][0].id not in resp
|
||||
|
@ -317,6 +313,27 @@ def test_studio_home_recent_changes(pub):
|
|||
# deleted
|
||||
assert 'backoffice/cards/%s/' % objects[CardDef.xml_root_node][5].id not in resp
|
||||
|
||||
# all changes page: admin user can see all changes (depending on permissions)
|
||||
resp = resp.click(href='all-changes/')
|
||||
assert '(1-6/6)' in resp
|
||||
# he can also see changes from other users
|
||||
for snapshot in pub.snapshot_class.select():
|
||||
snapshot.user_id = other_user.id
|
||||
snapshot.store()
|
||||
|
||||
pub.cfg['admin-permissions'] = {}
|
||||
pub.write_cfg()
|
||||
resp = app.get('/backoffice/studio/all-changes/')
|
||||
assert '(1-20/42)' in resp
|
||||
resp = resp.click('<!--Next Page-->')
|
||||
assert '21-40/42' in resp.text
|
||||
resp = resp.click('<!--Next Page-->')
|
||||
assert '41-42/42' in resp.text
|
||||
|
||||
user.is_admin = False
|
||||
user.store()
|
||||
app.get('/backoffice/studio/all-changes/', status=403)
|
||||
|
||||
|
||||
def test_studio_workflows(pub):
|
||||
create_superuser(pub)
|
||||
|
|
|
@ -24,17 +24,65 @@ from wcs.carddef import CardDef
|
|||
from wcs.data_sources import NamedDataSource
|
||||
from wcs.formdef import FormDef
|
||||
from wcs.mail_templates import MailTemplate
|
||||
from wcs.qommon import _, pgettext, template
|
||||
from wcs.qommon import _, misc, pgettext, template
|
||||
from wcs.qommon.backoffice.listing import pagination_links
|
||||
from wcs.qommon.backoffice.menu import html_top
|
||||
from wcs.qommon.form import get_response
|
||||
from wcs.workflows import Workflow
|
||||
from wcs.wscalls import NamedWsCall
|
||||
|
||||
|
||||
class ChangesDirectory(Directory):
|
||||
_q_exports = ['']
|
||||
|
||||
def _q_index(self):
|
||||
get_response().breadcrumb.append(('all-changes/', pgettext('studio', 'All changes')))
|
||||
html_top(pgettext('studio', 'All Changes'))
|
||||
limit = misc.get_int_or_400(
|
||||
get_request().form.get('limit', get_publisher().get_site_option('default-page-size')) or 20
|
||||
)
|
||||
offset = misc.get_int_or_400(get_request().form.get('offset', 0))
|
||||
|
||||
backoffice_root = get_publisher().get_backoffice_root()
|
||||
object_types = []
|
||||
if backoffice_root.is_accessible('workflows'):
|
||||
object_types += [Workflow, MailTemplate]
|
||||
if backoffice_root.is_accessible('forms'):
|
||||
object_types += [NamedDataSource, BlockDef, FormDef]
|
||||
if backoffice_root.is_accessible('workflows'):
|
||||
object_types += [NamedDataSource]
|
||||
if backoffice_root.is_accessible('settings'):
|
||||
object_types += [NamedDataSource, NamedWsCall]
|
||||
if backoffice_root.is_accessible('cards'):
|
||||
object_types += [CardDef]
|
||||
object_types = [ot.xml_root_node for ot in object_types]
|
||||
|
||||
objects = []
|
||||
links = ''
|
||||
if get_publisher().snapshot_class:
|
||||
objects = get_publisher().snapshot_class.get_recent_changes(
|
||||
object_types=object_types, limit=limit, offset=offset
|
||||
)
|
||||
total_count = get_publisher().snapshot_class.count_recent_changes(object_types=object_types)
|
||||
links = pagination_links(offset, limit, total_count, load_js=False)
|
||||
|
||||
return template.QommonTemplateResponse(
|
||||
templates=['wcs/backoffice/changes.html'],
|
||||
context={
|
||||
'objects': objects,
|
||||
'pagination_links': links,
|
||||
},
|
||||
)
|
||||
|
||||
def is_accessible(self, user):
|
||||
return user.is_admin
|
||||
|
||||
|
||||
class StudioDirectory(Directory):
|
||||
_q_exports = ['', 'deprecations', ('logged-errors', 'logged_errors_dir')]
|
||||
_q_exports = ['', 'deprecations', ('logged-errors', 'logged_errors_dir'), ('all-changes', 'changes_dir')]
|
||||
|
||||
deprecations = DeprecationsDirectory()
|
||||
changes_dir = ChangesDirectory()
|
||||
|
||||
def __init__(self):
|
||||
self.logged_errors_dir = LoggedErrorsDirectory(parent_dir=self)
|
||||
|
@ -71,10 +119,12 @@ class StudioDirectory(Directory):
|
|||
if backoffice_root.is_accessible('cards'):
|
||||
object_types += [CardDef]
|
||||
|
||||
user = get_request().user
|
||||
context = {
|
||||
'has_sidebar': False,
|
||||
'extra_links': extra_links,
|
||||
'recent_errors': LoggedErrorsDirectory.get_errors(offset=0, limit=5)[0],
|
||||
'show_all_changes': get_publisher().snapshot_class and user and user.is_admin,
|
||||
}
|
||||
if get_publisher().snapshot_class:
|
||||
context['recent_objects'] = get_publisher().snapshot_class.get_recent_changes(
|
||||
|
|
|
@ -184,8 +184,8 @@ class Snapshot:
|
|||
obj.store()
|
||||
|
||||
@classmethod
|
||||
def get_recent_changes(cls, object_types, user):
|
||||
elements = cls._get_recent_changes(object_types, user)
|
||||
def get_recent_changes(cls, object_types=None, user=None, limit=5, offset=0):
|
||||
elements = cls._get_recent_changes(object_types=object_types, user=user, limit=limit, offset=offset)
|
||||
instances = []
|
||||
for object_type, object_id, snapshot_timestamp in elements:
|
||||
klass = cls.get_class(object_type)
|
||||
|
|
42
wcs/sql.py
42
wcs/sql.py
|
@ -3793,22 +3793,46 @@ class Snapshot(SqlMixin, wcs.snapshots.Snapshot):
|
|||
return cls.get(row[0])
|
||||
|
||||
@classmethod
|
||||
def _get_recent_changes(cls, object_types, user):
|
||||
def _get_recent_changes(cls, object_types, user=None, limit=5, offset=0):
|
||||
conn, cur = get_connection_and_cursor()
|
||||
sql_statement = '''SELECT object_type, object_id, MAX(timestamp) AS m
|
||||
FROM snapshots
|
||||
WHERE object_type IN %(object_types)s
|
||||
AND user_id = %(user_id)s
|
||||
GROUP BY object_type, object_id
|
||||
ORDER BY m DESC
|
||||
LIMIT 5'''
|
||||
parameters = {'object_types': tuple(object_types), 'user_id': str(user.id)}
|
||||
clause = [Contains('object_type', object_types)]
|
||||
if user is not None:
|
||||
clause.append(Equal('user_id', str(user.id)))
|
||||
where_clauses, parameters, dummy = parse_clause(clause)
|
||||
|
||||
sql_statement = 'SELECT object_type, object_id, MAX(timestamp) AS m FROM snapshots'
|
||||
sql_statement += ' WHERE ' + ' AND '.join(where_clauses)
|
||||
sql_statement += ' GROUP BY object_type, object_id ORDER BY m DESC'
|
||||
|
||||
if limit:
|
||||
sql_statement += ' LIMIT %(limit)s'
|
||||
parameters['limit'] = limit
|
||||
if offset:
|
||||
sql_statement += ' OFFSET %(offset)s'
|
||||
parameters['offset'] = offset
|
||||
|
||||
cur.execute(sql_statement, parameters)
|
||||
result = cur.fetchall()
|
||||
conn.commit()
|
||||
cur.close()
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def count_recent_changes(cls, object_types):
|
||||
conn, cur = get_connection_and_cursor()
|
||||
|
||||
clause = [Contains('object_type', object_types)]
|
||||
where_clauses, parameters, dummy = parse_clause(clause)
|
||||
sql_statement = 'SELECT COUNT(*) FROM (SELECT object_type, object_id FROM snapshots'
|
||||
sql_statement += ' WHERE ' + ' AND '.join(where_clauses)
|
||||
sql_statement += ' GROUP BY object_type, object_id) AS s'
|
||||
|
||||
cur.execute(sql_statement, parameters)
|
||||
count = cur.fetchone()[0]
|
||||
conn.commit()
|
||||
cur.close()
|
||||
return count
|
||||
|
||||
|
||||
class LoggedError(SqlMixin, wcs.logged_errors.LoggedError):
|
||||
_table_name = 'loggederrors'
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
{% extends "wcs/backoffice/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block appbar-title %}{% trans "All changes" context 'studio' %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<ul class="objects-list single-links">
|
||||
{% for obj in objects %}
|
||||
<li>
|
||||
<a href="{{ obj.get_admin_url }}">
|
||||
{{ obj.name }}
|
||||
<span class="extra-info">{{ obj.snapshot_timestamp }}</span>
|
||||
<span class="badge">{{ obj.verbose_name }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{{ pagination_links|safe }}
|
||||
{% endblock %}
|
|
@ -40,6 +40,9 @@
|
|||
<span class="timestamp">{{ obj.snapshot_timestamp }}</span></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% if show_all_changes %}
|
||||
<p><a class="all-changes pk-button" href="all-changes/">{% trans "See all changes" %}</a></p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="errors-and-deprecations">
|
||||
|
|
Loading…
Reference in New Issue