Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added descriptions to group selections in Wagtail admin #3636

Merged
merged 19 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 3.2.22 on 2023-11-01 15:18

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("funds", "0112_add_organization_name"),
]

operations = [
migrations.AlterField(
model_name="assignedreviewers",
name="reviewer",
field=models.ForeignKey(
limit_choices_to={
"groups__name__in": ["Staff", "Reviewer", "Community Reviewer"],
"is_active": True,
},
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 4.2.7 on 2023-11-29 20:04

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("funds", "0113_alter_assignedreviewers_reviewer"),
]

operations = [
migrations.AlterField(
model_name="assignedreviewers",
name="reviewer",
field=models.ForeignKey(
limit_choices_to={
"groups__name__in": ["Staff", "Reviewer", "Community reviewer"],
"is_active": True,
},
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
]
41 changes: 40 additions & 1 deletion hypha/apply/users/admin_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@
from django.db.models import Q
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.template.defaultfilters import mark_safe
from django.template.response import TemplateResponse
from django.utils.translation import gettext as _
from django.views.decorators.vary import vary_on_headers
from wagtail.admin.auth import any_permission_required
from wagtail.admin.filters import WagtailFilterSet
from wagtail.admin.forms.search import SearchForm
from wagtail.compat import AUTH_USER_APP_LABEL, AUTH_USER_MODEL_NAME
from wagtail.users.views.groups import GroupViewSet
from wagtail.users.views.groups import GroupViewSet, IndexView

from .models import GroupDesc

User = get_user_model()

Expand Down Expand Up @@ -200,12 +203,48 @@ def index(request, *args):
)


class CustomGroupIndexView(IndexView):
"""
Overriding of wagtail.users.views.groups.IndexView to allow for the addition of help text to the displayed group names. This is done utilizing the get_queryset method
"""

def get_queryset(self):
"""
Overriding the normal queryset that would return all Group objects, this returnd an iterable of groups with custom names containing HTML help text.
"""
group_qs = super().get_queryset()

custom_groups = []

for group in group_qs:
help_text = GroupDesc.get_from_group(group)
if help_text:
group.name = mark_safe(
f"{group.name}<p class=group-help-text>{help_text}</p>"
)

custom_groups.append(group)

return custom_groups


class CustomGroupViewSet(GroupViewSet):
"""
Overriding the wagtail.users.views.groups.GroupViewSet just to use custom users view(index)
when getting all users for a group.
"""

index_view_class = CustomGroupIndexView

@property
def users_view(self):
return index

def __init__(self, name, **kwargs):
super().__init__(name, **kwargs)

@property
def index_view(self):
return self.index_view_class.as_view(
**self.get_index_view_kwargs(),
)
59 changes: 53 additions & 6 deletions hypha/apply/users/forms.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import AuthenticationForm
from django.template.defaultfilters import mark_safe
from django.utils.translation import gettext_lazy as _
from django_select2.forms import Select2Widget
from wagtail.users.forms import UserCreationForm, UserEditForm

from .models import AuthSettings
from .models import AuthSettings, GroupDesc

User = get_user_model()

Expand Down Expand Up @@ -68,27 +69,73 @@ def __init__(self, *args, **kwargs):
)


class GroupsModelMultipleChoiceField(forms.ModelMultipleChoiceField):
"""
A custom ModelMultipleChoiceField utilized to provide a custom label for the group prompts
"""

@classmethod
def get_group_mmcf(
cls, model_mulitple_choice_field: forms.ModelMultipleChoiceField
): # Handle the insertion of group help text
group_field_dict = model_mulitple_choice_field.__dict__
queryset = group_field_dict[
"_queryset"
] # Pull the queryset form the group field
unneeded_keys = ("empty_label", "_queryset")
for key in unneeded_keys:
group_field_dict.pop(
key, None
) # Pop unneeded keys/values, ignore if they don't exist.

# Overwrite the existing group's ModelMultipleChoiceField with the custom GroupsModelMultipleChoiceField that will provide the help text
return GroupsModelMultipleChoiceField(queryset=queryset, **group_field_dict)

def label_from_instance(self, group_obj):
"""
Overwriting ModelMultipleChoiceField's label from instance to provide help_text (if it exists)
"""
help_text = GroupDesc.get_from_group(group_obj)
if help_text:
return mark_safe(
f'{group_obj.name}<p class="group-help-text">{help_text}</p>'
)
return group_obj.name


class CustomUserEditForm(CustomUserAdminFormBase, UserEditForm):
pass
# pass
"""
A custom UserEditForm used to provide custom fields (ie. custom group fields)
"""

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

class CustomWagtailUserCreationForm(CustomUserAdminFormBase, UserCreationForm):
pass
# Overwrite the existing group's ModelMultipleChoiceField with the custom GroupsModelMultipleChoiceField that will provide the help text
self.fields["groups"] = GroupsModelMultipleChoiceField.get_group_mmcf(
self.fields["groups"]
)


class CustomUserCreationForm(CustomUserAdminFormBase, UserCreationForm):
def __init__(self, request=None, *args, **kwargs):
def __init__(self, register_view=False, request=None, *args, **kwargs):
self.request = request
super().__init__(*args, **kwargs)

self.user_settings = AuthSettings.load(request_or_site=self.request)
if self.user_settings.consent_show:
if register_view and self.user_settings.consent_show:
self.fields["consent"] = forms.BooleanField(
label=self.user_settings.consent_text,
help_text=self.user_settings.consent_help,
required=True,
)

# Overwrite the existing group's ModelMultipleChoiceField with the custom GroupsModelMultipleChoiceField that will provide the help text
self.fields["groups"] = GroupsModelMultipleChoiceField.get_group_mmcf(
self.fields["groups"]
)


class ProfileForm(forms.ModelForm):
class Meta:
Expand Down
60 changes: 51 additions & 9 deletions hypha/apply/users/groups.py
Original file line number Diff line number Diff line change
@@ -1,51 +1,93 @@
from django.utils.translation import gettext_lazy as _

SUPERADMIN = _("Administrator")
APPLICANT_GROUP_NAME = "Applicant"
STAFF_GROUP_NAME = "Staff"
REVIEWER_GROUP_NAME = "Reviewer"
TEAMADMIN_GROUP_NAME = "Staff Admin"
PARTNER_GROUP_NAME = "Partner"
COMMUNITY_REVIEWER_GROUP_NAME = "Community reviewer"
APPROVER_GROUP_NAME = "Approver"
FINANCE_GROUP_NAME = "Finance"
CONTRACTING_GROUP_NAME = "Contracting"
APPLICANT_GROUP_NAME = _("Applicant")
STAFF_GROUP_NAME = _("Staff")
REVIEWER_GROUP_NAME = _("Reviewer")
TEAMADMIN_GROUP_NAME = _("Staff Admin")
PARTNER_GROUP_NAME = _("Partner")
COMMUNITY_REVIEWER_GROUP_NAME = _("Community reviewer")
APPROVER_GROUP_NAME = _("Approver")
FINANCE_GROUP_NAME = _("Finance")
CONTRACTING_GROUP_NAME = _("Contracting")

APPLICANT_HELP_TEXT = _(
"Can access their own application and communicate via the communication tab."
)
STAFF_HELP_TEXT = _(
"View and edit all submissions, submit reviews, send determinations, and set up applications."
)
REVIEWER_HELP_TEXT = _(
"Has a dashboard and can submit reviews. Advisory Council Members are typically assigned this role."
)

TEAMADMIN_HELP_TEXT = _(
"Can view application message log. Must also be in group Staff."
)

PARTNER_HELP_TEXT = _(
"Can view, edit, and comment on a specific application they are assigned to."
)

COMMUNITY_REVIEWER_HELP_TEXT = _(
"An applicant with access to other applications utilizing the community/peer review workflow."
)

APPROVER_HELP_TEXT = _(
"Can review/approve PAF, and access compliance documents. Must also be in group: Staff, Contracting, or Finance."
)
FINANCE_HELP_TEXT = _(
"Can review/approve the PAF, access documents associated with contracting, and access invoices approved by Staff."
)
CONTRACTING_HELP_TEXT = _(
"Can review/approve the PAF and access documents associated with contracting."
)


GROUPS = [
{
"name": APPLICANT_GROUP_NAME,
"permissions": [],
"help_text": APPLICANT_HELP_TEXT,
},
{
"name": STAFF_GROUP_NAME,
"permissions": [],
"help_text": STAFF_HELP_TEXT,
},
{
"name": REVIEWER_GROUP_NAME,
"permissions": [],
"help_text": REVIEWER_HELP_TEXT,
},
{
"name": TEAMADMIN_GROUP_NAME,
"permissions": [],
"help_text": TEAMADMIN_HELP_TEXT,
},
{
"name": PARTNER_GROUP_NAME,
"permissions": [],
"help_text": PARTNER_HELP_TEXT,
},
{
"name": COMMUNITY_REVIEWER_GROUP_NAME,
"permissions": [],
"help_text": COMMUNITY_REVIEWER_HELP_TEXT,
},
{
"name": APPROVER_GROUP_NAME,
"permissions": [],
"help_text": APPROVER_HELP_TEXT,
},
{
"name": FINANCE_GROUP_NAME,
"permissions": [],
"help_text": FINANCE_HELP_TEXT,
},
{
"name": CONTRACTING_GROUP_NAME,
"permissions": [],
"help_text": CONTRACTING_HELP_TEXT,
},
]
44 changes: 44 additions & 0 deletions hypha/apply/users/migrations/0021_groupdesc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Generated by Django 3.2.22 on 2023-10-31 17:26

from django.db import migrations, models
from django.contrib.auth.models import Group
import django.db.models.deletion

from hypha.apply.users.groups import GROUPS
from hypha.apply.users.models import GroupDesc


def add_desc_groups(apps, schema_editor):
for group_data in GROUPS:
group, created = Group.objects.get_or_create(name=group_data["name"])
if group_data.get("help_text") is not None:
GroupDesc.objects.create(group=group, help_text=group_data["help_text"])


class Migration(migrations.Migration):
dependencies = [
("auth", "0012_alter_user_first_name_max_length"),
("users", "0020_auto_20230625_1825"),
]

operations = [
migrations.CreateModel(
name="GroupDesc",
fields=[
(
"group",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
primary_key=True,
serialize=False,
to="auth.group",
),
),
(
"help_text",
models.CharField(max_length=255, verbose_name="Help Text"),
),
],
),
migrations.RunPython(add_desc_groups),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Generated by Django 4.1.13 on 2023-11-27 14:46

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("users", "0021_groupdesc"),
("users", "0022_confirmaccesstoken"),
]

operations = []
Loading