mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-25 20:18:38 +02:00
Form structure
This commit is contained in:
parent
8dfb183ce0
commit
ed9d215577
5 changed files with 201 additions and 71 deletions
|
@ -110,52 +110,169 @@ class PortfolioSeniorOfficialForm(forms.ModelForm):
|
|||
return cleaned_data
|
||||
|
||||
|
||||
class PortfolioMemberForm(forms.ModelForm):
|
||||
class BasePortfolioMemberForm(forms.ModelForm):
|
||||
role = forms.ChoiceField(
|
||||
label="Select permission",
|
||||
choices=[
|
||||
(UserPortfolioRoleChoices.ORGANIZATION_ADMIN.value, "Admin Access"),
|
||||
(UserPortfolioRoleChoices.ORGANIZATION_MEMBER.value, "Basic Access")
|
||||
],
|
||||
widget=forms.RadioSelect,
|
||||
required=True,
|
||||
error_messages={
|
||||
"required": "Member access level is required",
|
||||
},
|
||||
)
|
||||
# Permissions for admins
|
||||
domain_request_permissions_admin = forms.ChoiceField(
|
||||
label="Select permission",
|
||||
choices=[
|
||||
(UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS.value, "View all requests"),
|
||||
(UserPortfolioPermissionChoices.EDIT_REQUESTS.value, "Create and edit requests")
|
||||
],
|
||||
widget=forms.RadioSelect,
|
||||
required=False,
|
||||
error_messages={
|
||||
"required": "Admin domain request permission is required",
|
||||
},
|
||||
)
|
||||
member_permissions_admin = forms.ChoiceField(
|
||||
label="Select permission",
|
||||
choices=[
|
||||
(UserPortfolioPermissionChoices.VIEW_MEMBERS.value, "View all members"),
|
||||
(UserPortfolioPermissionChoices.EDIT_MEMBERS.value, "Create and edit members")
|
||||
],
|
||||
widget=forms.RadioSelect,
|
||||
required=False,
|
||||
error_messages={
|
||||
"required": "Admin member permission is required",
|
||||
},
|
||||
)
|
||||
domain_request_permissions_member = forms.ChoiceField(
|
||||
label="Select permission",
|
||||
choices=[
|
||||
(UserPortfolioPermissionChoices.VIEW_MEMBERS.value, "View all members"),
|
||||
(UserPortfolioPermissionChoices.EDIT_MEMBERS.value, "Create and edit members")
|
||||
],
|
||||
widget=forms.RadioSelect,
|
||||
required=False,
|
||||
error_messages={
|
||||
"required": "Basic member permission is required",
|
||||
},
|
||||
)
|
||||
|
||||
# this form dynamically shows/hides some fields, depending on what
|
||||
# was selected prior. This toggles which field is required or not.
|
||||
ROLE_REQUIRED_FIELDS = {
|
||||
UserPortfolioRoleChoices.ORGANIZATION_ADMIN: [
|
||||
"domain_request_permissions_admin",
|
||||
"member_permissions_admin",
|
||||
],
|
||||
UserPortfolioRoleChoices.ORGANIZATION_MEMBER: [
|
||||
"domain_request_permissions_member",
|
||||
],
|
||||
}
|
||||
|
||||
def _map_instance_to_form(self, instance):
|
||||
"""Maps model instance data to form fields"""
|
||||
if not instance:
|
||||
return {}
|
||||
mapped_data = {}
|
||||
# Map roles with priority for admin
|
||||
if instance.roles:
|
||||
if UserPortfolioRoleChoices.ORGANIZATION_ADMIN.value in instance.roles:
|
||||
mapped_data['role'] = UserPortfolioRoleChoices.ORGANIZATION_ADMIN.value
|
||||
else:
|
||||
mapped_data['role'] = UserPortfolioRoleChoices.ORGANIZATION_MEMBER.value
|
||||
|
||||
perms = UserPortfolioPermission.get_portfolio_permissions(instance.roles, instance.additional_permissions)
|
||||
# Map permissions with priority for edit permissions
|
||||
if perms:
|
||||
if UserPortfolioPermissionChoices.EDIT_REQUESTS.value in perms:
|
||||
mapped_data['domain_request_permissions_admin'] = UserPortfolioPermissionChoices.EDIT_REQUESTS.value
|
||||
elif UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS.value in perms:
|
||||
mapped_data['domain_request_permissions_admin'] = UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS.value
|
||||
|
||||
if UserPortfolioPermissionChoices.EDIT_MEMBERS.value in perms:
|
||||
mapped_data['member_permissions_admin'] = UserPortfolioPermissionChoices.EDIT_MEMBERS.value
|
||||
elif UserPortfolioPermissionChoices.VIEW_MEMBERS.value in perms:
|
||||
mapped_data['member_permissions_admin'] = UserPortfolioPermissionChoices.VIEW_MEMBERS.value
|
||||
|
||||
return mapped_data
|
||||
|
||||
def _map_form_to_instance(self, instance):
|
||||
"""Maps form data to model instance"""
|
||||
if not self.is_valid():
|
||||
return
|
||||
|
||||
role = self.cleaned_data.get("role")
|
||||
domain_request_permissions_member = self.cleaned_data.get("domain_request_permissions_member")
|
||||
domain_request_permissions_admin = self.cleaned_data.get('domain_request_permissions_admin')
|
||||
member_permissions_admin = self.cleaned_data.get('member_permissions_admin')
|
||||
|
||||
instance.roles = [role]
|
||||
additional_permissions = []
|
||||
if domain_request_permissions_member:
|
||||
additional_permissions.append(domain_request_permissions_member)
|
||||
elif domain_request_permissions_admin:
|
||||
additional_permissions.append(domain_request_permissions_admin)
|
||||
|
||||
if member_permissions_admin:
|
||||
additional_permissions.append(member_permissions_admin)
|
||||
|
||||
instance.additional_permissions = additional_permissions
|
||||
return instance
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
role = cleaned_data.get("role")
|
||||
|
||||
# Get required fields for the selected role.
|
||||
# Then validate all required fields for the role.
|
||||
required_fields = self.ROLE_REQUIRED_FIELDS.get(role, [])
|
||||
for field_name in required_fields:
|
||||
if not cleaned_data.get(field_name):
|
||||
self.add_error(
|
||||
field_name,
|
||||
self.fields.get(field_name).error_messages.get("required")
|
||||
)
|
||||
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class PortfolioMemberForm(BasePortfolioMemberForm):
|
||||
"""
|
||||
Form for updating a portfolio member.
|
||||
"""
|
||||
|
||||
roles = forms.MultipleChoiceField(
|
||||
choices=UserPortfolioRoleChoices.choices,
|
||||
widget=forms.SelectMultiple(attrs={"class": "usa-select"}),
|
||||
required=False,
|
||||
label="Roles",
|
||||
)
|
||||
|
||||
additional_permissions = forms.MultipleChoiceField(
|
||||
choices=UserPortfolioPermissionChoices.choices,
|
||||
widget=forms.SelectMultiple(attrs={"class": "usa-select"}),
|
||||
required=False,
|
||||
label="Additional Permissions",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = UserPortfolioPermission
|
||||
fields = [
|
||||
"roles",
|
||||
"additional_permissions",
|
||||
]
|
||||
def __init__(self, *args, instance=None, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['role'].descriptions = {
|
||||
"organization_admin": UserPortfolioRoleChoices.get_role_description(UserPortfolioRoleChoices.ORGANIZATION_ADMIN),
|
||||
"organization_member": UserPortfolioRoleChoices.get_role_description(UserPortfolioRoleChoices.ORGANIZATION_MEMBER)
|
||||
}
|
||||
self.instance = instance
|
||||
self.initial = self._map_instance_to_form(self.instance)
|
||||
|
||||
def save(self):
|
||||
"""Save form data to instance"""
|
||||
if not self.instance:
|
||||
self.instance = self.Meta.model()
|
||||
self._map_form_to_instance(self.instance)
|
||||
self.instance.save()
|
||||
return self.instance
|
||||
|
||||
|
||||
class PortfolioInvitedMemberForm(forms.ModelForm):
|
||||
class PortfolioInvitedMemberForm(BasePortfolioMemberForm):
|
||||
"""
|
||||
Form for updating a portfolio invited member.
|
||||
"""
|
||||
|
||||
roles = forms.MultipleChoiceField(
|
||||
choices=UserPortfolioRoleChoices.choices,
|
||||
widget=forms.SelectMultiple(attrs={"class": "usa-select"}),
|
||||
required=False,
|
||||
label="Roles",
|
||||
)
|
||||
|
||||
additional_permissions = forms.MultipleChoiceField(
|
||||
choices=UserPortfolioPermissionChoices.choices,
|
||||
widget=forms.SelectMultiple(attrs={"class": "usa-select"}),
|
||||
required=False,
|
||||
label="Additional Permissions",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = PortfolioInvitation
|
||||
fields = [
|
||||
|
|
|
@ -17,6 +17,23 @@ class UserPortfolioRoleChoices(models.TextChoices):
|
|||
@classmethod
|
||||
def get_user_portfolio_role_label(cls, user_portfolio_role):
|
||||
return cls(user_portfolio_role).label if user_portfolio_role else None
|
||||
|
||||
@classmethod
|
||||
def get_role_description(cls, user_portfolio_role):
|
||||
"""Returns a detailed description for a given role."""
|
||||
descriptions = {
|
||||
cls.ORGANIZATION_ADMIN: (
|
||||
"Grants this member access to the organization-wide information "
|
||||
"on domains, domain requests, and members. Domain management can be assigned separately."
|
||||
),
|
||||
cls.ORGANIZATION_MEMBER: (
|
||||
"Grants this member access to the organization. They can be given extra permissions to view all "
|
||||
"organization domain requests and submit domain requests on behalf of the organization. Basic access "
|
||||
"members can’t view all members of an organization or manage them. "
|
||||
"Domain management can be assigned separately."
|
||||
)
|
||||
}
|
||||
return descriptions.get(user_portfolio_role)
|
||||
|
||||
|
||||
class UserPortfolioPermissionChoices(models.TextChoices):
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
{% load static custom_filters %}
|
||||
|
||||
<div class="{{ uswds_input_class }}">
|
||||
{% for group, options, index in widget.optgroups %}
|
||||
{% if group %}<div><label>{{ group }}</label>{% endif %}
|
||||
|
@ -13,7 +15,17 @@
|
|||
<label
|
||||
class="{{ uswds_input_class }}__label{% if label_classes %} {{ label_classes }}{% endif %}"
|
||||
for="{{ option.attrs.id }}"
|
||||
>{{ option.label }}</label>
|
||||
>
|
||||
{{ option.label }}
|
||||
{% comment %} Add a description on each, if available {% endcomment %}
|
||||
{% if field and field.field and field.field.descriptions %}
|
||||
{% with description=field.field.descriptions|get_dict_value:option.value %}
|
||||
{% if description %}
|
||||
<p class="margin-0 margin-top-2">{{ description }}</p>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
</label>
|
||||
{% endfor %}
|
||||
{% if group %}</div>{% endif %}
|
||||
{% endfor %}
|
||||
|
|
|
@ -10,12 +10,6 @@
|
|||
|
||||
{% block portfolio_content %}
|
||||
|
||||
<!-- Form mesages -->
|
||||
{% include "includes/form_errors.html" with form=form %}
|
||||
{% block messages %}
|
||||
{% include "includes/form_messages.html" %}
|
||||
{% endblock messages%}
|
||||
|
||||
<!-- Navigation breadcrumbs -->
|
||||
<nav class="usa-breadcrumb padding-top-0" aria-label="Domain request breadcrumb">
|
||||
<ol class="usa-breadcrumb__list">
|
||||
|
@ -33,9 +27,7 @@
|
|||
</nav>
|
||||
|
||||
<!-- Page header -->
|
||||
{% block new_member_header %}
|
||||
<h1>Member access and permissions</h1>
|
||||
{% endblock new_member_header %}
|
||||
|
||||
{% include "includes/required_fields.html" %}
|
||||
|
||||
|
@ -45,7 +37,6 @@
|
|||
<legend>
|
||||
<h2>Member email</h2>
|
||||
</legend>
|
||||
{% comment %} TODO should default to name {% endcomment %}
|
||||
<p>
|
||||
{% if member %}
|
||||
{{ member.email }}
|
||||
|
@ -64,24 +55,15 @@
|
|||
|
||||
<em>Select the level of access for this member. <abbr class="usa-hint usa-hint--required" title="required">*</abbr></em>
|
||||
|
||||
{% with group_classes="usa-form-editable usa-form-editable--no-border padding-top-0" %}
|
||||
<div class="usa-radio">
|
||||
{% for radio in form.member_access_level %}
|
||||
{{ radio.tag }}
|
||||
<label class="usa-radio__label usa-legend" for="{{ radio.id_for_label }}">
|
||||
{{ radio.choice_label }}
|
||||
<p class="margin-0 margin-top-2">
|
||||
{% if radio.choice_label == "Admin Access" %}
|
||||
Grants this member access to the organization-wide information on domains, domain requests, and members. Domain management can be assigned separately.
|
||||
{% else %}
|
||||
Grants this member access to the organization. They can be given extra permissions to view all organization domain requests and submit domain requests on behalf of the organization. Basic access members can’t view all members of an organization or manage them. Domain management can be assigned separately.
|
||||
{% endif %}
|
||||
</p>
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% with add_class="usa-radio__input--tile" add_legend_class="usa-sr-only" %}
|
||||
{% input_with_errors form.role %}
|
||||
{% endwith %}
|
||||
|
||||
{% comment %} {% if radio.value == "organization_admin" %}
|
||||
Grants this member access to the organization-wide information on domains, domain requests, and members. Domain management can be assigned separately.
|
||||
{% elif radio.value == "organization_member" %}
|
||||
Grants this member access to the organization. They can be given extra permissions to view all organization domain requests and submit domain requests on behalf of the organization. Basic access members can’t view all members of an organization or manage them. Domain management can be assigned separately.
|
||||
{% endif %} {% endcomment %}
|
||||
</fieldset>
|
||||
|
||||
<!-- Admin access form -->
|
||||
|
@ -93,7 +75,7 @@
|
|||
text-primary-dark
|
||||
margin-bottom-0">Organization domain requests</h3>
|
||||
{% with group_classes="usa-form-editable usa-form-editable--no-border padding-top-0" %}
|
||||
{% input_with_errors form.admin_org_domain_request_permissions %}
|
||||
{% input_with_errors form.domain_request_permissions_admin %}
|
||||
{% endwith %}
|
||||
|
||||
<h3 class="summary-item__title
|
||||
|
@ -101,7 +83,7 @@
|
|||
margin-bottom-0
|
||||
margin-top-3">Organization members</h3>
|
||||
{% with group_classes="usa-form-editable usa-form-editable--no-border padding-top-0" %}
|
||||
{% input_with_errors form.admin_org_members_permissions %}
|
||||
{% input_with_errors form.member_permissions_admin %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
|
||||
|
@ -112,7 +94,7 @@
|
|||
|
||||
<h3 class="margin-bottom-0">Organization domain requests</h3>
|
||||
{% with group_classes="usa-form-editable usa-form-editable--no-border padding-top-0" %}
|
||||
{% input_with_errors form.basic_org_domain_request_permissions %}
|
||||
{% input_with_errors form.domain_request_permissions_member %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
|
||||
|
@ -123,17 +105,11 @@
|
|||
href="{% url 'members' %}"
|
||||
class="usa-button usa-button--outline"
|
||||
name="btn-cancel-click"
|
||||
aria-label="Cancel adding new member"
|
||||
>Cancel
|
||||
</a>
|
||||
<a
|
||||
id="invite_member_trigger"
|
||||
href="#invite-member-modal"
|
||||
class="usa-button usa-button--outline margin-top-1 display-none"
|
||||
aria-controls="invite-member-modal"
|
||||
data-open-modal
|
||||
>Trigger invite member modal</a>
|
||||
<button id="invite_new_member_submit" type="submit" class="usa-button">Invite Member</button>
|
||||
aria-label="Cancel editing member"
|
||||
>
|
||||
Cancel
|
||||
</a>
|
||||
<button type="submit" class="usa-button">Update Member</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
|
|
@ -282,3 +282,11 @@ def display_requesting_entity(domain_request):
|
|||
)
|
||||
|
||||
return display
|
||||
|
||||
|
||||
@register.filter
|
||||
def get_dict_value(dictionary, key):
|
||||
"""Get a value from a dictionary. Returns a string on empty."""
|
||||
if isinstance(dictionary, dict):
|
||||
return dictionary.get(key, "")
|
||||
return ""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue