categories: add new export_roles and statistics_roles attributes (#53667)
This commit is contained in:
parent
fe12631493
commit
7225537069
|
@ -191,6 +191,8 @@ def test_categories_new_duplicate_name(pub):
|
|||
|
||||
|
||||
def test_categories_reorder(pub):
|
||||
create_superuser(pub)
|
||||
|
||||
CardDefCategory.wipe()
|
||||
category = CardDefCategory(name='foo')
|
||||
category.store()
|
||||
|
|
|
@ -202,6 +202,8 @@ def test_categories_new_duplicate_name(pub):
|
|||
|
||||
|
||||
def test_categories_reorder(pub):
|
||||
create_superuser(pub)
|
||||
|
||||
Category.wipe()
|
||||
category = Category(name='foo')
|
||||
category.store()
|
||||
|
@ -220,3 +222,34 @@ def test_categories_reorder(pub):
|
|||
categories = Category.select()
|
||||
Category.sort_by_position(categories)
|
||||
assert [x.id for x in categories] == ['3', '1', '2']
|
||||
|
||||
|
||||
def test_categories_edit_roles(pub):
|
||||
create_superuser(pub)
|
||||
|
||||
pub.role_class.wipe()
|
||||
role_a = pub.role_class(name='a')
|
||||
role_a.store()
|
||||
role_b = pub.role_class(name='b')
|
||||
role_b.store()
|
||||
|
||||
Category.wipe()
|
||||
category = Category(name='foobar')
|
||||
category.store()
|
||||
|
||||
app = login(get_app(pub))
|
||||
resp = app.get('/backoffice/forms/categories/1/edit')
|
||||
|
||||
resp.form['export_roles$element0'] = role_a.id
|
||||
resp = resp.form.submit('export_roles$add_element')
|
||||
resp.form['export_roles$element1'] = role_b.id
|
||||
|
||||
resp.form['statistics_roles$element0'] = role_a.id
|
||||
resp = resp.form.submit('submit')
|
||||
|
||||
category = Category.get(category.id)
|
||||
assert set(x.id for x in category.export_roles) == {role_a.id, role_b.id}
|
||||
assert set(x.id for x in category.statistics_roles) == {role_a.id}
|
||||
|
||||
resp = app.get('/backoffice/forms/categories/1/edit')
|
||||
assert resp.form['export_roles$element0'].value == role_a.id
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from quixote import get_request, get_response, redirect
|
||||
from quixote import get_publisher, get_request, get_response, redirect
|
||||
from quixote.directory import Directory
|
||||
from quixote.html import TemplateIO, htmltext
|
||||
|
||||
|
@ -23,7 +23,7 @@ from wcs.categories import CardDefCategory, Category
|
|||
from wcs.formdef import FormDef
|
||||
from wcs.qommon import _, template
|
||||
from wcs.qommon.backoffice.menu import html_top
|
||||
from wcs.qommon.form import Form, HtmlWidget, StringWidget, WysiwygTextWidget
|
||||
from wcs.qommon.form import Form, HtmlWidget, SingleSelectWidget, StringWidget, WidgetList, WysiwygTextWidget
|
||||
|
||||
|
||||
class CategoryUI:
|
||||
|
@ -34,7 +34,7 @@ class CategoryUI:
|
|||
if self.category is None:
|
||||
self.category = self.category_class()
|
||||
|
||||
def get_form(self):
|
||||
def get_form(self, new=False):
|
||||
form = Form(enctype='multipart/form-data')
|
||||
form.add(
|
||||
StringWidget, 'name', title=_('Category Name'), required=True, size=30, value=self.category.name
|
||||
|
@ -47,7 +47,7 @@ class CategoryUI:
|
|||
rows=10,
|
||||
value=self.category.description,
|
||||
)
|
||||
if self.category_class == Category:
|
||||
if self.category_class is Category:
|
||||
form.add(
|
||||
StringWidget,
|
||||
'redirect_url',
|
||||
|
@ -56,6 +56,40 @@ class CategoryUI:
|
|||
hint=_('If set, redirect the site category page to the given URL.'),
|
||||
value=self.category.redirect_url,
|
||||
)
|
||||
|
||||
if not new:
|
||||
# include permission fields
|
||||
roles = list(get_publisher().role_class.select(order_by='name'))
|
||||
form.add(
|
||||
WidgetList,
|
||||
'export_roles',
|
||||
title=_('Export Roles'),
|
||||
element_type=SingleSelectWidget,
|
||||
value=self.category.export_roles,
|
||||
add_element_label=_('Add Role'),
|
||||
element_kwargs={
|
||||
'render_br': False,
|
||||
'options': [(None, '---', None)]
|
||||
+ [(x, x.name, x.id) for x in roles if not x.is_internal()],
|
||||
},
|
||||
hint=_('Roles allowed to export data'),
|
||||
)
|
||||
if self.category_class is Category:
|
||||
form.add(
|
||||
WidgetList,
|
||||
'statistics_roles',
|
||||
title=_('Statistics Roles'),
|
||||
element_type=SingleSelectWidget,
|
||||
value=self.category.statistics_roles,
|
||||
add_element_label=_('Add Role'),
|
||||
element_kwargs={
|
||||
'render_br': False,
|
||||
'options': [(None, '---', None)]
|
||||
+ [(x, x.name, x.id) for x in roles if not x.is_internal()],
|
||||
},
|
||||
hint=_('Roles with access to the statistics page'),
|
||||
)
|
||||
|
||||
form.add_submit('submit', _('Submit'))
|
||||
form.add_submit('cancel', _('Cancel'))
|
||||
return form
|
||||
|
@ -69,9 +103,11 @@ class CategoryUI:
|
|||
form.get_widget('name').set_error(_('This name is already used'))
|
||||
raise ValueError()
|
||||
|
||||
self.category.description = form.get_widget('description').parse()
|
||||
if form.get_widget('redirect_url'):
|
||||
self.category.redirect_url = form.get_widget('redirect_url').parse()
|
||||
for attribute in ('description', 'redirect_url', 'export_roles', 'statistics_roles'):
|
||||
widget = form.get_widget(attribute)
|
||||
if widget:
|
||||
setattr(self.category, attribute, widget.parse())
|
||||
|
||||
self.category.store()
|
||||
|
||||
|
||||
|
@ -107,10 +143,10 @@ class CategoryPage(Directory):
|
|||
|
||||
def edit(self):
|
||||
form = self.category_ui.get_form()
|
||||
if form.get_widget('cancel').parse():
|
||||
if form.get_submit() == 'cancel':
|
||||
return redirect('..')
|
||||
|
||||
if form.is_submitted() and not form.has_errors():
|
||||
if form.get_submit() == 'submit' and not form.has_errors():
|
||||
try:
|
||||
self.category_ui.submit_form(form)
|
||||
except ValueError:
|
||||
|
@ -224,7 +260,7 @@ class CategoriesDirectory(Directory):
|
|||
def new(self):
|
||||
get_response().breadcrumb.append(('new', _('New')))
|
||||
category_ui = self.category_ui_class(None)
|
||||
form = category_ui.get_form()
|
||||
form = category_ui.get_form(new=True)
|
||||
if form.get_widget('cancel').parse():
|
||||
return redirect('.')
|
||||
|
||||
|
|
|
@ -14,12 +14,6 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from quixote import get_publisher
|
||||
|
||||
from wcs.qommon.misc import xml_node_text
|
||||
from wcs.qommon.storage import Equal, Or
|
||||
from wcs.qommon.xml_storage import XmlStorableObject
|
||||
|
||||
|
||||
|
@ -60,27 +54,6 @@ class ApiAccess(XmlStorableObject):
|
|||
def get_roles(self):
|
||||
return self.roles or []
|
||||
|
||||
def export_roles_to_xml(self, element, attribute_name, include_id=False, **kwargs):
|
||||
for role in self.get_roles():
|
||||
sub = ET.SubElement(element, 'role')
|
||||
if include_id:
|
||||
sub.attrib['role-id'] = role.id
|
||||
sub.attrib['role-slug'] = role.slug
|
||||
sub.text = role.name
|
||||
|
||||
def import_roles_from_xml(self, element, include_id=False, **kwargs):
|
||||
criterias = []
|
||||
for sub in element:
|
||||
if include_id and 'role-id' in sub.attrib:
|
||||
criterias.append(Equal('id', sub.attrib['role-id']))
|
||||
elif 'role-slug' in sub.attrib:
|
||||
criterias.append(Equal('slug', sub.attrib['role-slug']))
|
||||
else:
|
||||
role_name = xml_node_text(sub)
|
||||
if role_name:
|
||||
criterias.append(Equal('name', role_name))
|
||||
return get_publisher().role_class.select([Or(criterias)], order_by='name')
|
||||
|
||||
def get_as_api_user(self):
|
||||
class RestrictedApiUser:
|
||||
# kept as inner class so cannot be pickled
|
||||
|
|
|
@ -33,6 +33,9 @@ class Category(XmlStorableObject):
|
|||
position = None
|
||||
redirect_url = None
|
||||
|
||||
export_roles = None
|
||||
statistics_roles = None
|
||||
|
||||
# declarations for serialization
|
||||
XML_NODES = [
|
||||
('name', 'str'),
|
||||
|
@ -40,6 +43,8 @@ class Category(XmlStorableObject):
|
|||
('description', 'str'),
|
||||
('redirect_url', 'str'),
|
||||
('position', 'int'),
|
||||
('export_roles', 'roles'),
|
||||
('statistics_roles', 'roles'),
|
||||
]
|
||||
|
||||
def __init__(self, name=None):
|
||||
|
@ -125,7 +130,13 @@ class CardDefCategory(Category):
|
|||
xml_root_node = 'carddef_category'
|
||||
|
||||
# declarations for serialization
|
||||
XML_NODES = [('name', 'str'), ('url_name', 'str'), ('description', 'str'), ('position', 'int')]
|
||||
XML_NODES = [
|
||||
('name', 'str'),
|
||||
('url_name', 'str'),
|
||||
('description', 'str'),
|
||||
('position', 'int'),
|
||||
('export_roles', 'roles'),
|
||||
]
|
||||
|
||||
|
||||
Substitutions.register('category_name', category=_('General'), comment=_('Category Name'))
|
||||
|
|
|
@ -21,7 +21,7 @@ from django.utils.encoding import force_text
|
|||
from quixote import get_publisher
|
||||
|
||||
from .misc import indent_xml, xml_node_text
|
||||
from .storage import StorableObject
|
||||
from .storage import Equal, Or, StorableObject
|
||||
|
||||
|
||||
class XmlStorableObject(StorableObject):
|
||||
|
@ -75,6 +75,14 @@ class XmlStorableObject(StorableObject):
|
|||
indent_xml(x)
|
||||
return ET.tostring(x)
|
||||
|
||||
def export_roles_to_xml(self, element, attribute_name, include_id=False, **kwargs):
|
||||
for role in getattr(self, attribute_name, None) or []:
|
||||
sub = ET.SubElement(element, 'role')
|
||||
if include_id:
|
||||
sub.attrib['role-id'] = role.id
|
||||
sub.attrib['role-slug'] = role.slug
|
||||
sub.text = role.name
|
||||
|
||||
@classmethod
|
||||
def import_from_xml(cls, fd, charset=None, include_id=False):
|
||||
try:
|
||||
|
@ -127,3 +135,16 @@ class XmlStorableObject(StorableObject):
|
|||
for item in element.findall('item'):
|
||||
value.append(item.text)
|
||||
return value
|
||||
|
||||
def import_roles_from_xml(self, element, include_id=False, **kwargs):
|
||||
criterias = []
|
||||
for sub in element:
|
||||
if include_id and 'role-id' in sub.attrib:
|
||||
criterias.append(Equal('id', sub.attrib['role-id']))
|
||||
elif 'role-slug' in sub.attrib:
|
||||
criterias.append(Equal('slug', sub.attrib['role-slug']))
|
||||
else:
|
||||
role_name = xml_node_text(sub)
|
||||
if role_name:
|
||||
criterias.append(Equal('name', role_name))
|
||||
return get_publisher().role_class.select([Or(criterias)], order_by='name')
|
||||
|
|
|
@ -29,4 +29,28 @@
|
|||
{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
|
||||
{% if category.export_roles or category.statistics_roles %}
|
||||
<div class="section">
|
||||
<h3>{% trans "Permissions" %}</h3>
|
||||
<div>
|
||||
<ul>
|
||||
{% if category.export_roles %}
|
||||
<li>{% trans "Export roles:" %}
|
||||
<ul>
|
||||
{% for role in category.export_roles %}<li>{{ role.name }}</li>{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if category.statistics_roles %}
|
||||
<li>{% trans "Statistics roles:" %}
|
||||
<ul>
|
||||
{% for role in category.statistics_roles %}<li>{{ role.name }}</li>{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
Loading…
Reference in New Issue