Compare commits
7 Commits
e2a8829156
...
539d7e9d58
Author | SHA1 | Date |
---|---|---|
Ales (Shagi) Zabala Alava | 539d7e9d58 | |
Ales (Shagi) Zabala Alava | 04fc4b4a15 | |
Ales (Shagi) Zabala Alava | 05bb3371a7 | |
Ales (Shagi) Zabala Alava | 8683f411bb | |
Ales (Shagi) Zabala Alava | 78ce1e4e65 | |
Ales (Shagi) Zabala Alava | faeef79053 | |
Ales (Shagi) Zabala Alava | 2a03ed8b9a |
Binary file not shown.
|
@ -0,0 +1,182 @@
|
||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2020-12-22 16:24+0000\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"Language: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
|
#: apps.py:8
|
||||||
|
msgid "GAS"
|
||||||
|
msgstr "GAS"
|
||||||
|
|
||||||
|
#: forms.py:25
|
||||||
|
msgid "roles"
|
||||||
|
msgstr "roles"
|
||||||
|
|
||||||
|
#: gas/config.py:6
|
||||||
|
msgid "Users with access to gas control panel."
|
||||||
|
msgstr "Usuarios con acceso al panel de control."
|
||||||
|
|
||||||
|
#: gas/config.py:7
|
||||||
|
msgid "Users with access to everithing inside control panel."
|
||||||
|
msgstr "Usuarios con acceso a todo el panel de control."
|
||||||
|
|
||||||
|
#: gas/config.py:14 gas/users/views.py:31 gas/users/views.py:38
|
||||||
|
#: gas/users/views.py:48 gas/users/views.py:59 gas/users/views.py:95
|
||||||
|
#: gas/users/views.py:107
|
||||||
|
msgid "Users"
|
||||||
|
msgstr "Usuarios"
|
||||||
|
|
||||||
|
#: gas/users/forms.py:9 templates/gas/users/user_list.html:10
|
||||||
|
msgid "Username"
|
||||||
|
msgstr "Usuario"
|
||||||
|
|
||||||
|
#: gas/users/forms.py:10 templates/gas/users/user_list.html:11
|
||||||
|
msgid "Active"
|
||||||
|
msgstr "Activo"
|
||||||
|
|
||||||
|
#: gas/users/forms.py:12 templates/gas/users/user_list.html:12
|
||||||
|
msgid "Roles"
|
||||||
|
msgstr "Roles"
|
||||||
|
|
||||||
|
#: gas/users/views.py:33
|
||||||
|
msgid "New user"
|
||||||
|
msgstr "Nuevo usuario"
|
||||||
|
|
||||||
|
#: gas/users/views.py:43
|
||||||
|
msgid "Create user"
|
||||||
|
msgstr "Crear usuario"
|
||||||
|
|
||||||
|
#: gas/users/views.py:44
|
||||||
|
msgid "User created"
|
||||||
|
msgstr "Usuario creado"
|
||||||
|
|
||||||
|
#: gas/users/views.py:49
|
||||||
|
msgid "Create"
|
||||||
|
msgstr "Crear"
|
||||||
|
|
||||||
|
#: gas/users/views.py:54
|
||||||
|
msgid "Update user"
|
||||||
|
msgstr "Actulizar usuario"
|
||||||
|
|
||||||
|
#: gas/users/views.py:55
|
||||||
|
msgid "User updated"
|
||||||
|
msgstr "Usuario actualizado"
|
||||||
|
|
||||||
|
#: gas/users/views.py:61
|
||||||
|
msgid "Update"
|
||||||
|
msgstr "Actualizar"
|
||||||
|
|
||||||
|
#: gas/users/views.py:68
|
||||||
|
msgid "User password updated"
|
||||||
|
msgstr "Contraseña de usuario actualizada"
|
||||||
|
|
||||||
|
#: gas/users/views.py:75
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Change {username} user password"
|
||||||
|
msgstr "Cambiar la contraseña del usuario {username}"
|
||||||
|
|
||||||
|
#: gas/users/views.py:97 templates/gas/base.html:23
|
||||||
|
#: templates/gas/users/user_list.html:29
|
||||||
|
msgid "Change password"
|
||||||
|
msgstr "Cambiar contraseña"
|
||||||
|
|
||||||
|
#: gas/users/views.py:102
|
||||||
|
msgid "Delete user"
|
||||||
|
msgstr "Borrar usuario"
|
||||||
|
|
||||||
|
#: gas/users/views.py:103
|
||||||
|
msgid "User deleted"
|
||||||
|
msgstr "Usuario borrado"
|
||||||
|
|
||||||
|
#: gas/users/views.py:109 templates/gas/delete_confirmation.html:20
|
||||||
|
#: templates/gas/users/user_list.html:30
|
||||||
|
msgid "Delete"
|
||||||
|
msgstr "Borrar"
|
||||||
|
|
||||||
|
#: models.py:8
|
||||||
|
msgid "role"
|
||||||
|
msgstr "rol"
|
||||||
|
|
||||||
|
#: models.py:10
|
||||||
|
msgid "user"
|
||||||
|
msgstr "usuario"
|
||||||
|
|
||||||
|
#: models.py:14
|
||||||
|
msgid "user role"
|
||||||
|
msgstr "rol de usuario"
|
||||||
|
|
||||||
|
#: models.py:15
|
||||||
|
msgid "user roles"
|
||||||
|
msgstr "roles de usuario"
|
||||||
|
|
||||||
|
#: templates/gas/base.html:24
|
||||||
|
msgid "Logout"
|
||||||
|
msgstr "Salir"
|
||||||
|
|
||||||
|
#: templates/gas/base.html:44
|
||||||
|
msgid "Home"
|
||||||
|
msgstr "Inicio"
|
||||||
|
|
||||||
|
#: templates/gas/base_form.html:20 templates/gas/delete_confirmation.html:21
|
||||||
|
msgid "Cancel"
|
||||||
|
msgstr "Cancelar"
|
||||||
|
|
||||||
|
#: templates/gas/base_form.html:23
|
||||||
|
msgid "Save"
|
||||||
|
msgstr "Guardar"
|
||||||
|
|
||||||
|
#: templates/gas/base_form.html:26
|
||||||
|
msgid "Save and continue"
|
||||||
|
msgstr "Guardar y continuar"
|
||||||
|
|
||||||
|
#: templates/gas/base_list.html:24
|
||||||
|
msgid "Filter"
|
||||||
|
msgstr "Filtrar"
|
||||||
|
|
||||||
|
#: templates/gas/delete_confirmation.html:5
|
||||||
|
msgid "Delete confirmation"
|
||||||
|
msgstr "Confirmación de borrado"
|
||||||
|
|
||||||
|
#: templates/gas/delete_confirmation.html:10
|
||||||
|
msgid "Summary"
|
||||||
|
msgstr "Resumen"
|
||||||
|
|
||||||
|
#: templates/gas/delete_confirmation.html:16
|
||||||
|
msgid "Objects"
|
||||||
|
msgstr "Objetos"
|
||||||
|
|
||||||
|
#: templates/gas/login.html:7 templates/gas/login.html:15
|
||||||
|
msgid "Login"
|
||||||
|
msgstr "Login"
|
||||||
|
|
||||||
|
#: templates/gas/users/user_list.html:28
|
||||||
|
msgid "Edit"
|
||||||
|
msgstr "Editar"
|
||||||
|
|
||||||
|
#: views.py:44
|
||||||
|
msgid "Operation successful."
|
||||||
|
msgstr "Operación realizada."
|
||||||
|
|
||||||
|
#: views.py:170
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Are your sure you want to delete {object}?"
|
||||||
|
msgstr "¿Seguro que quieres borrar {object}?"
|
||||||
|
|
||||||
|
#: views.py:171
|
||||||
|
#, python-format
|
||||||
|
msgid "%(obj)s deleted."
|
||||||
|
msgstr ""
|
|
@ -22,8 +22,8 @@ class Migration(migrations.Migration):
|
||||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_roles', to=settings.AUTH_USER_MODEL, verbose_name='user')),
|
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_roles', to=settings.AUTH_USER_MODEL, verbose_name='user')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'role',
|
'verbose_name': 'user role',
|
||||||
'verbose_name_plural': 'roles',
|
'verbose_name_plural': 'user roles',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
14
gas/sites.py
14
gas/sites.py
|
@ -7,14 +7,20 @@ from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class Entry:
|
class Entry:
|
||||||
def __init__(self, name, label, icon=None, url=None, roles=None, parent=None, children=None):
|
def __init__(self, name, label, icon=None, url=None, roles=None, parent=None, order=None):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.label = label
|
self.label = label
|
||||||
self.icon = icon
|
self.icon = icon
|
||||||
self.url = url
|
self.url = url
|
||||||
self.roles = roles
|
self.roles = roles
|
||||||
self.children = children or dict()
|
self.children = dict()
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
self.order = order if order is not None else float("inf")
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
if isinstance(other, Entry):
|
||||||
|
return (self.parent, self.order, self.label) < (other.parent, other.order, other.label)
|
||||||
|
return super().__lt__(other)
|
||||||
|
|
||||||
|
|
||||||
class GASSite(object):
|
class GASSite(object):
|
||||||
|
@ -42,7 +48,7 @@ class GASSite(object):
|
||||||
raise ImproperlyConfigured("Prefix {0} already in use".format(prefix))
|
raise ImproperlyConfigured("Prefix {0} already in use".format(prefix))
|
||||||
self._registry['urls'][prefix] = urls
|
self._registry['urls'][prefix] = urls
|
||||||
|
|
||||||
def register_menu(self, name, label, url=None, icon=None, roles=None, parent=None):
|
def register_menu(self, name, label, url=None, icon=None, roles=None, parent=None, order=None):
|
||||||
if name in self._registry['menu']:
|
if name in self._registry['menu']:
|
||||||
raise ImproperlyConfigured("Menu entry '{0}' already registered.".format(name))
|
raise ImproperlyConfigured("Menu entry '{0}' already registered.".format(name))
|
||||||
|
|
||||||
|
@ -53,7 +59,7 @@ class GASSite(object):
|
||||||
|
|
||||||
roles.add(self.base_role)
|
roles.add(self.base_role)
|
||||||
|
|
||||||
entry = Entry(name, label, icon, url, roles, parent=parent)
|
entry = Entry(name, label, icon, url, roles, parent=parent, order=order)
|
||||||
|
|
||||||
if parent:
|
if parent:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -194,3 +194,17 @@ label {
|
||||||
.required label {
|
.required label {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#login {
|
||||||
|
background: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#login form {
|
||||||
|
border: 1px solid gray;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
background: #fff;
|
||||||
|
margin: 2em auto;
|
||||||
|
width: 20em;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
<ul class="actions">
|
<ul class="actions">
|
||||||
|
{% block actions %}
|
||||||
{% if not is_popup %}
|
{% if not is_popup %}
|
||||||
<li><a href="{{ view.get_success_url }}">{% trans "Cancel" %}</a></li>
|
<li><a href="{{ view.get_success_url }}">{% trans "Cancel" %}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -26,6 +27,11 @@
|
||||||
<li><button name="save_and_continue" type="submit">{% trans "Save and continue" %}</button>
|
<li><button name="save_and_continue" type="submit">{% trans "Save and continue" %}</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% block extra_actions %}{% endblock %}
|
{% block extra_actions %}{% endblock %}
|
||||||
|
{% endblock actions %}
|
||||||
</ul>
|
</ul>
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_js %}
|
||||||
|
{{ form.media }}
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -18,6 +18,6 @@
|
||||||
|
|
||||||
<form method="post" action=".">{% csrf_token %}
|
<form method="post" action=".">{% csrf_token %}
|
||||||
<button type="submit">{% trans 'Delete' %}</button>
|
<button type="submit">{% trans 'Delete' %}</button>
|
||||||
<a href="{{ back_url }}">{% trans 'Cancel' %}</a>
|
<a href="{{ cancel_url }}">{% trans 'Cancel' %}</a>
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width" />
|
<meta name="viewport" content="width=device-width" />
|
||||||
<title>Login</title>
|
|
||||||
<title>{{ gas_title }} {% trans "Login" %}</title>
|
<title>{{ gas_title }} {% trans "Login" %}</title>
|
||||||
|
<link href="{% static "gas/css/gas.css" %}" rel="stylesheet" type="text/css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body id="login">
|
||||||
<form action="." method="POST">{% csrf_token %}
|
<form action="." method="POST">{% csrf_token %}
|
||||||
{% form_errors form %}
|
{% form_errors form %}
|
||||||
{% form_field form.username %}
|
{% form_field form.username %}
|
||||||
|
|
|
@ -15,7 +15,7 @@ def show_navigation(user):
|
||||||
if user.is_superuser:
|
if user.is_superuser:
|
||||||
user_roles.add('admins')
|
user_roles.add('admins')
|
||||||
menu = site.get_root_menu(user_roles)
|
menu = site.get_root_menu(user_roles)
|
||||||
menu.sort(key=lambda a: a.label)
|
menu.sort()
|
||||||
return {
|
return {
|
||||||
'menu': menu,
|
'menu': menu,
|
||||||
'user_roles': user_roles,
|
'user_roles': user_roles,
|
||||||
|
@ -29,7 +29,6 @@ def get_children(entry, roles):
|
||||||
child for child in entry.children.values()
|
child for child in entry.children.values()
|
||||||
if child.roles.intersection(roles)
|
if child.roles.intersection(roles)
|
||||||
],
|
],
|
||||||
key=lambda a: a.label
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,66 @@ class SiteTestCase(TestCase):
|
||||||
url="gas:role_list",
|
url="gas:role_list",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_menu_ordering(self):
|
||||||
|
test_site = GASSite()
|
||||||
|
admin_roles = set(('admins',))
|
||||||
|
|
||||||
|
# With no explicit order, sort by label
|
||||||
|
test_site.register_menu(name='c', label="c")
|
||||||
|
test_site.register_menu(name='b', label="b")
|
||||||
|
test_site.register_menu(name='a', label="a")
|
||||||
|
entries = [
|
||||||
|
entry.name
|
||||||
|
for entry in sorted(test_site.get_root_menu(admin_roles))
|
||||||
|
]
|
||||||
|
self.assertEqual(entries, ['a', 'b', 'c'])
|
||||||
|
|
||||||
|
# Explicit order takes preference
|
||||||
|
test_site.register_menu(name='z', label="z", order=1)
|
||||||
|
entries = [
|
||||||
|
entry.name
|
||||||
|
for entry in sorted(test_site.get_root_menu(admin_roles))
|
||||||
|
]
|
||||||
|
self.assertEqual(entries, ['z', 'a', 'b', 'c'])
|
||||||
|
|
||||||
|
# Explicit order inside parent don't change the order
|
||||||
|
test_site.register_menu(name='y', label="y", order=2, parent='a')
|
||||||
|
entries = [
|
||||||
|
entry.name
|
||||||
|
for entry in sorted(test_site.get_root_menu(admin_roles))
|
||||||
|
]
|
||||||
|
self.assertEqual(entries, ['z', 'a', 'b', 'c'])
|
||||||
|
|
||||||
|
# With same explicit order, sort by label
|
||||||
|
test_site.register_menu(name='x', label="x", order=1)
|
||||||
|
entries = [
|
||||||
|
entry.name
|
||||||
|
for entry in sorted(test_site.get_root_menu(admin_roles))
|
||||||
|
]
|
||||||
|
self.assertEqual(entries, ['x', 'z', 'a', 'b', 'c'])
|
||||||
|
|
||||||
|
def test_menu_visibility(self):
|
||||||
|
test_site = GASSite()
|
||||||
|
admin_roles = set(('admins',))
|
||||||
|
staff_roles = set(('staff',))
|
||||||
|
|
||||||
|
test_site.register_menu(name='a', label='a', roles=admin_roles)
|
||||||
|
test_site.register_menu(name='b', label='b', roles=staff_roles)
|
||||||
|
|
||||||
|
# Admins gets all menu
|
||||||
|
entries = [
|
||||||
|
entry.name
|
||||||
|
for entry in test_site.get_root_menu(admin_roles)
|
||||||
|
]
|
||||||
|
self.assertEqual(entries, ['a', 'b'])
|
||||||
|
|
||||||
|
# Staff gets filtered menu
|
||||||
|
entries = [
|
||||||
|
entry.name
|
||||||
|
for entry in test_site.get_root_menu(staff_roles)
|
||||||
|
]
|
||||||
|
self.assertEqual(entries, ['b'])
|
||||||
|
|
||||||
|
|
||||||
class SampleAppIntegrationTest(TestCase):
|
class SampleAppIntegrationTest(TestCase):
|
||||||
def test_gas_autodiscover(self):
|
def test_gas_autodiscover(self):
|
||||||
|
|
|
@ -168,7 +168,7 @@ class GASUpdateView(GASMixin, UpdateView):
|
||||||
class GASDeleteView(GASMixin, DeleteView):
|
class GASDeleteView(GASMixin, DeleteView):
|
||||||
template_name = "gas/delete_confirmation.html"
|
template_name = "gas/delete_confirmation.html"
|
||||||
confirmation_text = _("Are your sure you want to delete {object}?")
|
confirmation_text = _("Are your sure you want to delete {object}?")
|
||||||
deleted_text = _("%(obj)s deleted.")
|
deleted_text = _("{object} deleted.")
|
||||||
|
|
||||||
def get_confirmation_text(self):
|
def get_confirmation_text(self):
|
||||||
return self.confirmation_text.format(object=self.object)
|
return self.confirmation_text.format(object=self.object)
|
||||||
|
|
|
@ -13,7 +13,7 @@ classifiers =
|
||||||
Framework :: Django
|
Framework :: Django
|
||||||
Framework :: Django :: 3.1
|
Framework :: Django :: 3.1
|
||||||
Intended Audience :: Developers
|
Intended Audience :: Developers
|
||||||
License :: OSI Approved :: BSD License
|
License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
||||||
Operating System :: OS Independent
|
Operating System :: OS Independent
|
||||||
Programming Language :: Python
|
Programming Language :: Python
|
||||||
Programming Language :: Python :: 3
|
Programming Language :: Python :: 3
|
||||||
|
|
Loading…
Reference in New Issue