feat(association): affiche le menu Gérer… que sur les détails
Parent
ded158f5b1
révision
361e419268
|
@ -5,6 +5,7 @@ import pytest
|
|||
from bs4 import BeautifulSoup as bs
|
||||
|
||||
from benevalibre.association.models import Association
|
||||
from benevalibre.association.views import get_management_buttons
|
||||
from benevalibre.utils.tests import (
|
||||
ManagerOnlyViewMixin,
|
||||
count_text_in_content,
|
||||
|
@ -12,6 +13,43 @@ from benevalibre.utils.tests import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
class TestAssociationManagementButtons:
|
||||
def test_foreign(self, association, foreign):
|
||||
buttons = get_management_buttons(association, foreign)
|
||||
assert len(buttons) == 0
|
||||
|
||||
def test_manager(self, association, user, manager):
|
||||
buttons = get_management_buttons(association, user)
|
||||
assert len(buttons) == 7
|
||||
|
||||
def test_superuser(self, association, superuser):
|
||||
buttons = get_management_buttons(association, superuser)
|
||||
assert len(buttons) == 1
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'role_name, expected',
|
||||
[('Bénévole', 0), ('Animat⋅eur⋅rice', 5), ('Dirigeant', 7)],
|
||||
)
|
||||
def test_role(self, association, user, engagement, role_name, expected):
|
||||
engagement = association.get_engagement(user)
|
||||
engagement.role = association.role_set.get(name=role_name)
|
||||
engagement.save()
|
||||
|
||||
assert len(get_management_buttons(association, user)) == expected
|
||||
|
||||
def test_role_list_users(self, association, user, engagement):
|
||||
role = association.role_set.get_benevole()
|
||||
role.list_users = True
|
||||
role.save()
|
||||
|
||||
engagement = association.get_engagement(user)
|
||||
engagement.role = role
|
||||
engagement.save()
|
||||
|
||||
assert len(get_management_buttons(association, user)) == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
class TestAssosiationIndex:
|
||||
url = reverse_lazy('association:index')
|
||||
|
@ -154,76 +192,28 @@ class TestAssosiationDetail:
|
|||
)
|
||||
assert response.status_code == expected
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'use, expected', [(None, 0), ('user', 7), ('staff', 1), ('foreign', 0)]
|
||||
)
|
||||
def test_management_buttons(
|
||||
self,
|
||||
client,
|
||||
association,
|
||||
user,
|
||||
superuser,
|
||||
foreign,
|
||||
manager,
|
||||
use,
|
||||
expected,
|
||||
):
|
||||
if use == 'staff':
|
||||
client.force_login(superuser)
|
||||
elif use == 'foreign':
|
||||
client.force_login(foreign)
|
||||
elif use:
|
||||
client.force_login(user)
|
||||
|
||||
def test_titlebuttons_foreign(self, client, association, foreign):
|
||||
client.force_login(foreign)
|
||||
response = client.get(
|
||||
reverse('association:detail', args=[association.id])
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert not count_text_in_content(response, "title-buttons")
|
||||
assert not count_text_in_content(response, "Gérer")
|
||||
|
||||
buttons = (
|
||||
bs(response.content, 'html.parser')
|
||||
.find(id='main-menu')
|
||||
.find_all('a', class_='dropdown-item capabilities')
|
||||
)
|
||||
assert len(buttons) == expected
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'userole, expected',
|
||||
[
|
||||
('Bénévole', None),
|
||||
('Bénévole++', 1),
|
||||
('Animat⋅eur⋅rice', 5),
|
||||
('Dirigeant', 7),
|
||||
],
|
||||
)
|
||||
def test_manage_features(
|
||||
self, client, association, user, engagement, userole, expected
|
||||
):
|
||||
def test_titlebuttons_manager(self, client, association, user, manager):
|
||||
client.force_login(user)
|
||||
|
||||
# étends le role Bénévole
|
||||
if userole == 'Bénévole++':
|
||||
userole = 'Bénévole'
|
||||
role = association.role_set.get_benevole()
|
||||
role.list_users = True
|
||||
role.save()
|
||||
|
||||
# définis le role du bénévole
|
||||
engagement = association.get_engagement(user)
|
||||
engagement.role = association.role_set.get(name=userole)
|
||||
engagement.save()
|
||||
|
||||
response = client.get(
|
||||
reverse('association:detail', args=[association.id])
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert count_text_in_content(response, "title-buttons")
|
||||
assert count_text_in_content(response, "Gérer")
|
||||
|
||||
buttons = (
|
||||
bs(response.content, 'html.parser')
|
||||
.find(id='main-menu')
|
||||
.find_all('a', class_='dropdown-item capabilities')
|
||||
.find(class_='title-buttons')
|
||||
.find_all('a', class_='dropdown-item')
|
||||
)
|
||||
assert bool(buttons) == bool(expected) or len(buttons) == expected
|
||||
assert len(buttons) == 7
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
|
@ -322,8 +312,8 @@ class TestAssosiationCreate:
|
|||
|
||||
buttons = (
|
||||
bs(response.content, 'html.parser')
|
||||
.find(id='main-menu')
|
||||
.find_all('a', class_='dropdown-item capabilities')
|
||||
.find(class_='title-buttons')
|
||||
.find_all('a', class_='dropdown-item')
|
||||
)
|
||||
assert len(buttons) == 7
|
||||
|
||||
|
|
|
@ -14,86 +14,89 @@ from cruditor.views import (
|
|||
)
|
||||
|
||||
from benevalibre.base.tables import EngagementIndexTable
|
||||
from benevalibre.utils.html import fa_icon
|
||||
from benevalibre.utils.views import CruditorPageMixin, PageMixin
|
||||
|
||||
from . import forms, models, tables
|
||||
|
||||
|
||||
class AssociationManageMenu:
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
if hasattr(self, 'association'):
|
||||
association = self.association
|
||||
elif hasattr(self, 'object') and isinstance(
|
||||
self.object, models.Association
|
||||
):
|
||||
association = self.object
|
||||
else:
|
||||
raise NotImplementedError("No way to get any related association")
|
||||
def get_management_buttons(association, user):
|
||||
"""
|
||||
Return the management actions that `user` has on `association` as a list
|
||||
of buttons - e.g. to be displayed in the title buttons.
|
||||
"""
|
||||
buttons = []
|
||||
|
||||
capabilities = []
|
||||
if association.can_manage_engagements(self.request.user):
|
||||
capabilities.append(
|
||||
[
|
||||
'users',
|
||||
"Gérer les bénévoles",
|
||||
'association:engagement:index',
|
||||
]
|
||||
)
|
||||
elif association.can_list_users(self.request.user):
|
||||
capabilities.append(
|
||||
['users', "Voir les bénévoles", 'base:association:user']
|
||||
)
|
||||
if association.can_manage_benevalos(self.request.user):
|
||||
capabilities.append(
|
||||
[
|
||||
'gift',
|
||||
"Gérer les bénévolats",
|
||||
'base:association:benevalo:index',
|
||||
]
|
||||
)
|
||||
if association.can_manage_levels(self.request.user):
|
||||
capabilities.append(
|
||||
[
|
||||
'tachometer',
|
||||
"Gérer les niveaux de bénévolat",
|
||||
'association:level:index',
|
||||
]
|
||||
)
|
||||
if association.can_manage_projects(self.request.user):
|
||||
capabilities.append(
|
||||
[
|
||||
'wrench',
|
||||
"Gérer les projets de l'association",
|
||||
'association:project:index',
|
||||
]
|
||||
)
|
||||
if association.can_manage_categories(self.request.user):
|
||||
capabilities.append(
|
||||
[
|
||||
'tags',
|
||||
"Gérer les catégories de bénévolat",
|
||||
'association:category:index',
|
||||
]
|
||||
)
|
||||
if association.can_manage_roles(self.request.user):
|
||||
capabilities.append(
|
||||
[
|
||||
'key-modern',
|
||||
"Gérer les roles de l'association",
|
||||
'association:role:index',
|
||||
]
|
||||
)
|
||||
if association.can_manage_association(self.request.user):
|
||||
capabilities.append(
|
||||
['edit', "Modifier l'association", 'association:update']
|
||||
)
|
||||
context['capabilities'] = capabilities
|
||||
context['association'] = association
|
||||
return context
|
||||
def _reverse(viewname):
|
||||
return reverse(viewname, args=[association.id])
|
||||
|
||||
if association.can_manage_engagements(user):
|
||||
buttons.append(
|
||||
{
|
||||
'label': fa_icon('users', "Gérer les bénévoles"),
|
||||
'url': _reverse('association:engagement:index'),
|
||||
}
|
||||
)
|
||||
elif association.can_list_users(user):
|
||||
buttons.append(
|
||||
{
|
||||
'label': fa_icon('users', "Voir les bénévoles"),
|
||||
'url': _reverse('base:association:user'),
|
||||
}
|
||||
)
|
||||
if association.can_manage_benevalos(user):
|
||||
buttons.append(
|
||||
{
|
||||
'label': fa_icon('gift', "Gérer les bénévolats"),
|
||||
'url': _reverse('base:association:benevalo:index'),
|
||||
}
|
||||
)
|
||||
if association.can_manage_levels(user):
|
||||
buttons.append(
|
||||
{
|
||||
'label': fa_icon(
|
||||
'tachometer', "Gérer les niveaux de bénévolat"
|
||||
),
|
||||
'url': _reverse('association:level:index'),
|
||||
}
|
||||
)
|
||||
if association.can_manage_projects(user):
|
||||
buttons.append(
|
||||
{
|
||||
'label': fa_icon(
|
||||
'wrench', "Gérer les projets de l'association"
|
||||
),
|
||||
'url': _reverse('association:project:index'),
|
||||
}
|
||||
)
|
||||
if association.can_manage_categories(user):
|
||||
buttons.append(
|
||||
{
|
||||
'label': fa_icon('tags', "Gérer les catégories de bénévolat"),
|
||||
'url': _reverse('association:category:index'),
|
||||
}
|
||||
)
|
||||
if association.can_manage_roles(user):
|
||||
buttons.append(
|
||||
{
|
||||
'label': fa_icon(
|
||||
'key-modern', "Gérer les roles de l'association"
|
||||
),
|
||||
'url': _reverse('association:role:index'),
|
||||
}
|
||||
)
|
||||
if association.can_manage_association(user):
|
||||
buttons.append(
|
||||
{
|
||||
'label': fa_icon('edit', "Modifier l'association"),
|
||||
'url': _reverse('association:update'),
|
||||
}
|
||||
)
|
||||
|
||||
return buttons
|
||||
|
||||
|
||||
class AssociationRelatedMixin(AssociationManageMenu):
|
||||
class AssociationRelatedMixin:
|
||||
"""
|
||||
Mixin to apply to the views related to an existing `Association`. The
|
||||
object with the id given by the `association` keyword argument will be
|
||||
|
@ -242,7 +245,7 @@ class AssociationCreate(CruditorPageMixin, CruditorAddView):
|
|||
return reverse('association:detail', args=[self.object.pk])
|
||||
|
||||
|
||||
class AssociationDetail(AssociationManageMenu, PageMixin, DetailView):
|
||||
class AssociationDetail(PageMixin, DetailView):
|
||||
template_name = 'association/association_detail.html'
|
||||
|
||||
def get_queryset(self):
|
||||
|
@ -253,10 +256,21 @@ class AssociationDetail(AssociationManageMenu, PageMixin, DetailView):
|
|||
def get_title(self):
|
||||
return self.object.name
|
||||
|
||||
def get_titlebuttons(self):
|
||||
management_buttons = get_management_buttons(
|
||||
self.object, self.request.user
|
||||
)
|
||||
if management_buttons:
|
||||
return [
|
||||
{
|
||||
'label': fa_icon('gear', "Gérer…"),
|
||||
'submenu': management_buttons,
|
||||
}
|
||||
]
|
||||
return []
|
||||
|
||||
class AssociationUpdate(
|
||||
AssociationManageMenu, CruditorPageMixin, CruditorChangeView
|
||||
):
|
||||
|
||||
class AssociationUpdate(CruditorPageMixin, CruditorChangeView):
|
||||
model = models.Association
|
||||
form_class = forms.UpdateForm
|
||||
title = "Modifier une association"
|
||||
|
@ -281,9 +295,7 @@ class AssociationUpdate(
|
|||
return super().form_valid(form)
|
||||
|
||||
|
||||
class AssociationDelete(
|
||||
AssociationManageMenu, CruditorPageMixin, CruditorDeleteView
|
||||
):
|
||||
class AssociationDelete(CruditorPageMixin, CruditorDeleteView):
|
||||
model = models.Association
|
||||
title = "Supprimer une association"
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ from django_tables2.export.views import ExportMixin
|
|||
|
||||
from benevalibre.association import models as asso_models
|
||||
from benevalibre.association.views import (
|
||||
AssociationManageMenu,
|
||||
AssociationRelatedFormMixin,
|
||||
AssociationRelatedMixin,
|
||||
)
|
||||
|
@ -76,11 +75,7 @@ class Home(PageMixin, TemplateView):
|
|||
|
||||
|
||||
class AssociationEngage(
|
||||
AssociationRelatedMixin,
|
||||
AssociationManageMenu,
|
||||
CruditorPageMixin,
|
||||
SuccessMessageMixin,
|
||||
FormView,
|
||||
AssociationRelatedMixin, CruditorPageMixin, SuccessMessageMixin, FormView
|
||||
):
|
||||
"""
|
||||
Pour s'engager comme bénévole auprès d'une association, il suffit de
|
||||
|
@ -261,10 +256,7 @@ class EngagementIndex(
|
|||
|
||||
|
||||
class AssociatedEngagementReadOnlyIndex(
|
||||
AssociationRelatedMixin,
|
||||
AssociationManageMenu,
|
||||
CruditorPageMixin,
|
||||
CruditorListView,
|
||||
AssociationRelatedMixin, CruditorPageMixin, CruditorListView
|
||||
):
|
||||
model = asso_models.Engagement
|
||||
table_class = tables.EngagementReadOnlyIndexTable
|
||||
|
@ -290,7 +282,7 @@ class AssociatedFormMixin:
|
|||
return kwargs
|
||||
|
||||
|
||||
class AssociatedBenevaloMixin(AssociationRelatedMixin, AssociationManageMenu):
|
||||
class AssociatedBenevaloMixin(AssociationRelatedMixin):
|
||||
model = Benevalo
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
|
@ -395,7 +387,6 @@ class AssociatedEngagedBenevaloModerationMixin(BenevaloModerationMixin):
|
|||
|
||||
class AssociatedEngagedBenevaloIndex(
|
||||
AssociationRelatedMixin,
|
||||
AssociationManageMenu,
|
||||
AssociatedEngagedBenevaloModerationMixin,
|
||||
ExportTable,
|
||||
CruditorPageMixin,
|
||||
|
@ -472,7 +463,6 @@ class AssociatedSelfBenevaloMixin(AssociationRelatedMixin):
|
|||
|
||||
class AssociatedSelfBenevaloIndex(
|
||||
AssociationRelatedMixin,
|
||||
AssociationManageMenu,
|
||||
AssociatedBenevaloModerationMixin,
|
||||
ExportTable,
|
||||
CruditorPageMixin,
|
||||
|
|
Chargement…
Référencer dans un nouveau ticket