mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-06-02 02:28:32 +02:00
Add permission table
This commit is contained in:
parent
4f7414f695
commit
e03e6f7d35
6 changed files with 303 additions and 96 deletions
|
@ -111,6 +111,10 @@ def login_callback(request):
|
||||||
if not user.verification_type or is_fixture_user:
|
if not user.verification_type or is_fixture_user:
|
||||||
user.set_user_verification_type()
|
user.set_user_verification_type()
|
||||||
user.save()
|
user.save()
|
||||||
|
|
||||||
|
if not user.last_selected_portfolio:
|
||||||
|
user.set_default_last_selected_portfolio()
|
||||||
|
user.save()
|
||||||
|
|
||||||
login(request, user)
|
login(request, user)
|
||||||
logger.info("Successfully logged in user %s" % user)
|
logger.info("Successfully logged in user %s" % user)
|
||||||
|
|
|
@ -118,6 +118,23 @@ class FilteredSelectMultipleArrayWidget(FilteredSelectMultiple):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class UserPortfolioPermissionsForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = models.UserPortfolioPermission
|
||||||
|
fields = "__all__"
|
||||||
|
field_classes = {"username": UsernameField}
|
||||||
|
widgets = {
|
||||||
|
"portfolio_roles": FilteredSelectMultipleArrayWidget(
|
||||||
|
"portfolio_roles", is_stacked=False, choices=UserPortfolioRoleChoices.choices
|
||||||
|
),
|
||||||
|
"portfolio_additional_permissions": FilteredSelectMultipleArrayWidget(
|
||||||
|
"portfolio_additional_permissions",
|
||||||
|
is_stacked=False,
|
||||||
|
choices=UserPortfolioPermissionChoices.choices,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class MyUserAdminForm(UserChangeForm):
|
class MyUserAdminForm(UserChangeForm):
|
||||||
"""This form utilizes the custom widget for its class's ManyToMany UIs.
|
"""This form utilizes the custom widget for its class's ManyToMany UIs.
|
||||||
|
|
||||||
|
@ -130,14 +147,6 @@ class MyUserAdminForm(UserChangeForm):
|
||||||
widgets = {
|
widgets = {
|
||||||
"groups": NoAutocompleteFilteredSelectMultiple("groups", False),
|
"groups": NoAutocompleteFilteredSelectMultiple("groups", False),
|
||||||
"user_permissions": NoAutocompleteFilteredSelectMultiple("user_permissions", False),
|
"user_permissions": NoAutocompleteFilteredSelectMultiple("user_permissions", False),
|
||||||
"portfolio_roles": FilteredSelectMultipleArrayWidget(
|
|
||||||
"portfolio_roles", is_stacked=False, choices=UserPortfolioRoleChoices.choices
|
|
||||||
),
|
|
||||||
"portfolio_additional_permissions": FilteredSelectMultipleArrayWidget(
|
|
||||||
"portfolio_additional_permissions",
|
|
||||||
is_stacked=False,
|
|
||||||
choices=UserPortfolioPermissionChoices.choices,
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -709,9 +718,7 @@ class MyUserAdmin(BaseUserAdmin, ImportExportModelAdmin):
|
||||||
"is_superuser",
|
"is_superuser",
|
||||||
"groups",
|
"groups",
|
||||||
"user_permissions",
|
"user_permissions",
|
||||||
"portfolio",
|
"last_selected_portfolio",
|
||||||
"portfolio_roles",
|
|
||||||
"portfolio_additional_permissions",
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -719,7 +726,7 @@ class MyUserAdmin(BaseUserAdmin, ImportExportModelAdmin):
|
||||||
)
|
)
|
||||||
|
|
||||||
autocomplete_fields = [
|
autocomplete_fields = [
|
||||||
"portfolio",
|
"last_selected_portfolio",
|
||||||
]
|
]
|
||||||
|
|
||||||
readonly_fields = ("verification_type",)
|
readonly_fields = ("verification_type",)
|
||||||
|
@ -741,9 +748,7 @@ class MyUserAdmin(BaseUserAdmin, ImportExportModelAdmin):
|
||||||
"fields": (
|
"fields": (
|
||||||
"is_active",
|
"is_active",
|
||||||
"groups",
|
"groups",
|
||||||
"portfolio",
|
"last_selected_portfolio",
|
||||||
"portfolio_roles",
|
|
||||||
"portfolio_additional_permissions",
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -798,9 +803,7 @@ class MyUserAdmin(BaseUserAdmin, ImportExportModelAdmin):
|
||||||
"Important dates",
|
"Important dates",
|
||||||
"last_login",
|
"last_login",
|
||||||
"date_joined",
|
"date_joined",
|
||||||
"portfolio",
|
"last_selected_portfolio",
|
||||||
"portfolio_roles",
|
|
||||||
"portfolio_additional_permissions",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# TODO: delete after we merge organization feature
|
# TODO: delete after we merge organization feature
|
||||||
|
@ -1208,6 +1211,27 @@ class UserDomainRoleResource(resources.ModelResource):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.UserDomainRole
|
model = models.UserDomainRole
|
||||||
|
|
||||||
|
class UserPortfolioPermissionAdmin(ListHeaderAdmin):
|
||||||
|
form = UserPortfolioPermissionsForm
|
||||||
|
class Meta:
|
||||||
|
"""Contains meta information about this class"""
|
||||||
|
|
||||||
|
model = models.UserPortfolioPermission
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
_meta = Meta()
|
||||||
|
|
||||||
|
# Columns
|
||||||
|
list_display = [
|
||||||
|
"user",
|
||||||
|
"portfolio",
|
||||||
|
]
|
||||||
|
|
||||||
|
autocomplete_fields = [
|
||||||
|
"user",
|
||||||
|
"portfolio"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class UserDomainRoleAdmin(ListHeaderAdmin, ImportExportModelAdmin):
|
class UserDomainRoleAdmin(ListHeaderAdmin, ImportExportModelAdmin):
|
||||||
"""Custom user domain role admin class."""
|
"""Custom user domain role admin class."""
|
||||||
|
@ -3176,6 +3200,7 @@ admin.site.register(models.Portfolio, PortfolioAdmin)
|
||||||
admin.site.register(models.DomainGroup, DomainGroupAdmin)
|
admin.site.register(models.DomainGroup, DomainGroupAdmin)
|
||||||
admin.site.register(models.Suborganization, SuborganizationAdmin)
|
admin.site.register(models.Suborganization, SuborganizationAdmin)
|
||||||
admin.site.register(models.SeniorOfficial, SeniorOfficialAdmin)
|
admin.site.register(models.SeniorOfficial, SeniorOfficialAdmin)
|
||||||
|
admin.site.register(models.UserPortfolioPermission, UserPortfolioPermissionAdmin)
|
||||||
|
|
||||||
# Register our custom waffle implementations
|
# Register our custom waffle implementations
|
||||||
admin.site.register(models.WaffleFlag, WaffleFlagAdmin)
|
admin.site.register(models.WaffleFlag, WaffleFlagAdmin)
|
||||||
|
|
108
src/registrar/migrations/0119_remove_user_portfolio_and_more.py
Normal file
108
src/registrar/migrations/0119_remove_user_portfolio_and_more.py
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
# Generated by Django 4.2.10 on 2024-08-16 20:41
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
import django.contrib.postgres.fields
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("registrar", "0118_alter_portfolio_options_alter_portfolio_creator_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="user",
|
||||||
|
name="portfolio",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="user",
|
||||||
|
name="portfolio_additional_permissions",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="user",
|
||||||
|
name="portfolio_roles",
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="user",
|
||||||
|
name="last_selected_portfolio",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name="portfolio_selected_by_users",
|
||||||
|
to="registrar.portfolio",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="UserPortfolioPermission",
|
||||||
|
fields=[
|
||||||
|
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||||
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||||
|
("updated_at", models.DateTimeField(auto_now=True)),
|
||||||
|
(
|
||||||
|
"portfolio_roles",
|
||||||
|
django.contrib.postgres.fields.ArrayField(
|
||||||
|
base_field=models.CharField(
|
||||||
|
choices=[
|
||||||
|
("organization_admin", "Admin"),
|
||||||
|
("organization_admin_read_only", "Admin read only"),
|
||||||
|
("organization_member", "Member"),
|
||||||
|
],
|
||||||
|
max_length=50,
|
||||||
|
),
|
||||||
|
blank=True,
|
||||||
|
help_text="Select one or more roles.",
|
||||||
|
null=True,
|
||||||
|
size=None,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"portfolio_additional_permissions",
|
||||||
|
django.contrib.postgres.fields.ArrayField(
|
||||||
|
base_field=models.CharField(
|
||||||
|
choices=[
|
||||||
|
("view_all_domains", "View all domains and domain reports"),
|
||||||
|
("view_managed_domains", "View managed domains"),
|
||||||
|
("view_member", "View members"),
|
||||||
|
("edit_member", "Create and edit members"),
|
||||||
|
("view_all_requests", "View all requests"),
|
||||||
|
("view_created_requests", "View created requests"),
|
||||||
|
("edit_requests", "Create and edit requests"),
|
||||||
|
("view_portfolio", "View organization"),
|
||||||
|
("edit_portfolio", "Edit organization"),
|
||||||
|
("view_suborganization", "View suborganization"),
|
||||||
|
("edit_suborganization", "Edit suborganization"),
|
||||||
|
],
|
||||||
|
max_length=50,
|
||||||
|
),
|
||||||
|
blank=True,
|
||||||
|
help_text="Select one or more additional permissions.",
|
||||||
|
null=True,
|
||||||
|
size=None,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"portfolio",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="portfolio_users",
|
||||||
|
to="registrar.portfolio",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="portfolio_permissions",
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"unique_together": {("user", "portfolio")},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
|
@ -21,6 +21,7 @@ from .portfolio import Portfolio
|
||||||
from .domain_group import DomainGroup
|
from .domain_group import DomainGroup
|
||||||
from .suborganization import Suborganization
|
from .suborganization import Suborganization
|
||||||
from .senior_official import SeniorOfficial
|
from .senior_official import SeniorOfficial
|
||||||
|
from .user_portfolio_permission import UserPortfolioPermission
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
@ -46,6 +47,7 @@ __all__ = [
|
||||||
"DomainGroup",
|
"DomainGroup",
|
||||||
"Suborganization",
|
"Suborganization",
|
||||||
"SeniorOfficial",
|
"SeniorOfficial",
|
||||||
|
"UserPortfolioPermission",
|
||||||
]
|
]
|
||||||
|
|
||||||
auditlog.register(Contact)
|
auditlog.register(Contact)
|
||||||
|
@ -70,3 +72,4 @@ auditlog.register(Portfolio)
|
||||||
auditlog.register(DomainGroup)
|
auditlog.register(DomainGroup)
|
||||||
auditlog.register(Suborganization)
|
auditlog.register(Suborganization)
|
||||||
auditlog.register(SeniorOfficial)
|
auditlog.register(SeniorOfficial)
|
||||||
|
auditlog.register(UserPortfolioPermission)
|
|
@ -5,8 +5,7 @@ from django.db import models
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
|
|
||||||
from registrar.models.domain_information import DomainInformation
|
from registrar.models import DomainInformation, UserDomainRole
|
||||||
from registrar.models.user_domain_role import UserDomainRole
|
|
||||||
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices
|
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices
|
||||||
|
|
||||||
from .domain_invitation import DomainInvitation
|
from .domain_invitation import DomainInvitation
|
||||||
|
@ -112,34 +111,14 @@ class User(AbstractUser):
|
||||||
related_name="users",
|
related_name="users",
|
||||||
)
|
)
|
||||||
|
|
||||||
portfolio = models.ForeignKey(
|
last_selected_portfolio = models.ForeignKey(
|
||||||
"registrar.Portfolio",
|
"registrar.Portfolio",
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
related_name="user",
|
related_name="portfolio_selected_by_users",
|
||||||
on_delete=models.SET_NULL,
|
on_delete=models.SET_NULL,
|
||||||
)
|
)
|
||||||
|
|
||||||
portfolio_roles = ArrayField(
|
|
||||||
models.CharField(
|
|
||||||
max_length=50,
|
|
||||||
choices=UserPortfolioRoleChoices.choices,
|
|
||||||
),
|
|
||||||
null=True,
|
|
||||||
blank=True,
|
|
||||||
help_text="Select one or more roles.",
|
|
||||||
)
|
|
||||||
|
|
||||||
portfolio_additional_permissions = ArrayField(
|
|
||||||
models.CharField(
|
|
||||||
max_length=50,
|
|
||||||
choices=UserPortfolioPermissionChoices.choices,
|
|
||||||
),
|
|
||||||
null=True,
|
|
||||||
blank=True,
|
|
||||||
help_text="Select one or more additional permissions.",
|
|
||||||
)
|
|
||||||
|
|
||||||
phone = PhoneNumberField(
|
phone = PhoneNumberField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
|
@ -234,64 +213,17 @@ class User(AbstractUser):
|
||||||
"""Extends clean method to perform additional validation, which can raise errors in django admin."""
|
"""Extends clean method to perform additional validation, which can raise errors in django admin."""
|
||||||
super().clean()
|
super().clean()
|
||||||
|
|
||||||
if self.portfolio is None and self._get_portfolio_permissions():
|
portfolio_perms = self.portfolio_permissions.filter(portfolio=self.last_selected_portfolio).first()
|
||||||
|
if self.last_selected_portfolio is None and portfolio_perms._get_portfolio_permissions():
|
||||||
raise ValidationError("When portfolio roles or additional permissions are assigned, portfolio is required.")
|
raise ValidationError("When portfolio roles or additional permissions are assigned, portfolio is required.")
|
||||||
|
|
||||||
if self.portfolio is not None and not self._get_portfolio_permissions():
|
if self.last_selected_portfolio is not None and not portfolio_perms._get_portfolio_permissions():
|
||||||
raise ValidationError("When portfolio is assigned, portfolio roles or additional permissions are required.")
|
raise ValidationError("When portfolio is assigned, portfolio roles or additional permissions are required.")
|
||||||
|
|
||||||
def _get_portfolio_permissions(self):
|
def set_default_last_selected_portfolio(self):
|
||||||
"""
|
permission = self.portfolio_permissions.first()
|
||||||
Retrieve the permissions for the user's portfolio roles.
|
if permission:
|
||||||
"""
|
self.last_selected_portfolio = permission.portfolio
|
||||||
portfolio_permissions = set() # Use a set to avoid duplicate permissions
|
|
||||||
|
|
||||||
if self.portfolio_roles:
|
|
||||||
for role in self.portfolio_roles:
|
|
||||||
if role in self.PORTFOLIO_ROLE_PERMISSIONS:
|
|
||||||
portfolio_permissions.update(self.PORTFOLIO_ROLE_PERMISSIONS[role])
|
|
||||||
if self.portfolio_additional_permissions:
|
|
||||||
portfolio_permissions.update(self.portfolio_additional_permissions)
|
|
||||||
return list(portfolio_permissions) # Convert back to list if necessary
|
|
||||||
|
|
||||||
def _has_portfolio_permission(self, portfolio_permission):
|
|
||||||
"""The views should only call this function when testing for perms and not rely on roles."""
|
|
||||||
|
|
||||||
if not self.portfolio:
|
|
||||||
return False
|
|
||||||
|
|
||||||
portfolio_permissions = self._get_portfolio_permissions()
|
|
||||||
|
|
||||||
return portfolio_permission in portfolio_permissions
|
|
||||||
|
|
||||||
# the methods below are checks for individual portfolio permissions. They are defined here
|
|
||||||
# to make them easier to call elsewhere throughout the application
|
|
||||||
def has_base_portfolio_permission(self):
|
|
||||||
return self._has_portfolio_permission(UserPortfolioPermissionChoices.VIEW_PORTFOLIO)
|
|
||||||
|
|
||||||
def has_edit_org_portfolio_permission(self):
|
|
||||||
return self._has_portfolio_permission(UserPortfolioPermissionChoices.EDIT_PORTFOLIO)
|
|
||||||
|
|
||||||
def has_domains_portfolio_permission(self):
|
|
||||||
return self._has_portfolio_permission(
|
|
||||||
UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS
|
|
||||||
) or self._has_portfolio_permission(UserPortfolioPermissionChoices.VIEW_MANAGED_DOMAINS)
|
|
||||||
|
|
||||||
def has_domain_requests_portfolio_permission(self):
|
|
||||||
return self._has_portfolio_permission(
|
|
||||||
UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS
|
|
||||||
) or self._has_portfolio_permission(UserPortfolioPermissionChoices.VIEW_CREATED_REQUESTS)
|
|
||||||
|
|
||||||
def has_view_all_domains_permission(self):
|
|
||||||
"""Determines if the current user can view all available domains in a given portfolio"""
|
|
||||||
return self._has_portfolio_permission(UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS)
|
|
||||||
|
|
||||||
# Field specific permission checks
|
|
||||||
def has_view_suborganization(self):
|
|
||||||
return self._has_portfolio_permission(UserPortfolioPermissionChoices.VIEW_SUBORGANIZATION)
|
|
||||||
|
|
||||||
def has_edit_suborganization(self):
|
|
||||||
return self._has_portfolio_permission(UserPortfolioPermissionChoices.EDIT_SUBORGANIZATION)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def needs_identity_verification(cls, email, uuid):
|
def needs_identity_verification(cls, email, uuid):
|
||||||
|
@ -434,6 +366,46 @@ class User(AbstractUser):
|
||||||
def is_org_user(self, request):
|
def is_org_user(self, request):
|
||||||
has_organization_feature_flag = flag_is_active(request, "organization_feature")
|
has_organization_feature_flag = flag_is_active(request, "organization_feature")
|
||||||
return has_organization_feature_flag and self.has_base_portfolio_permission()
|
return has_organization_feature_flag and self.has_base_portfolio_permission()
|
||||||
|
|
||||||
|
def _has_portfolio_permission(self, portfolio_permission):
|
||||||
|
"""The views should only call this function when testing for perms and not rely on roles."""
|
||||||
|
|
||||||
|
if not self.last_selected_portfolio:
|
||||||
|
return False
|
||||||
|
|
||||||
|
portfolio_perms = self.portfolio_permissions.filter(portfolio=self.last_selected_portfolio).first()
|
||||||
|
if not portfolio_perms:
|
||||||
|
return False
|
||||||
|
|
||||||
|
portfolio_permissions = portfolio_perms._get_portfolio_permissions()
|
||||||
|
return portfolio_permission in portfolio_permissions
|
||||||
|
|
||||||
|
def has_base_portfolio_permission(self):
|
||||||
|
return self._has_portfolio_permission(UserPortfolioPermissionChoices.VIEW_PORTFOLIO)
|
||||||
|
|
||||||
|
def has_edit_org_portfolio_permission(self):
|
||||||
|
return self._has_portfolio_permission(UserPortfolioPermissionChoices.EDIT_PORTFOLIO)
|
||||||
|
|
||||||
|
def has_domains_portfolio_permission(self):
|
||||||
|
return self._has_portfolio_permission(
|
||||||
|
UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS
|
||||||
|
) or self._has_portfolio_permission(UserPortfolioPermissionChoices.VIEW_MANAGED_DOMAINS)
|
||||||
|
|
||||||
|
def has_domain_requests_portfolio_permission(self):
|
||||||
|
return self._has_portfolio_permission(
|
||||||
|
UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS
|
||||||
|
) or self._has_portfolio_permission(UserPortfolioPermissionChoices.VIEW_CREATED_REQUESTS)
|
||||||
|
|
||||||
|
def has_view_all_domains_permission(self):
|
||||||
|
"""Determines if the current user can view all available domains in a given portfolio"""
|
||||||
|
return self._has_portfolio_permission(UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS)
|
||||||
|
|
||||||
|
# Field specific permission checks
|
||||||
|
def has_view_suborganization(self):
|
||||||
|
return self._has_portfolio_permission(UserPortfolioPermissionChoices.VIEW_SUBORGANIZATION)
|
||||||
|
|
||||||
|
def has_edit_suborganization(self):
|
||||||
|
return self._has_portfolio_permission(UserPortfolioPermissionChoices.EDIT_SUBORGANIZATION)
|
||||||
|
|
||||||
def get_user_domain_ids(self, request):
|
def get_user_domain_ids(self, request):
|
||||||
"""Returns either the domains ids associated with this user on UserDomainRole or Portfolio"""
|
"""Returns either the domains ids associated with this user on UserDomainRole or Portfolio"""
|
||||||
|
|
95
src/registrar/models/user_portfolio_permission.py
Normal file
95
src/registrar/models/user_portfolio_permission.py
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
from django.db import models
|
||||||
|
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices
|
||||||
|
from .utility.time_stamped_model import TimeStampedModel
|
||||||
|
from django.contrib.postgres.fields import ArrayField
|
||||||
|
|
||||||
|
|
||||||
|
class UserPortfolioPermission(TimeStampedModel):
|
||||||
|
"""This is a linking table that connects a user with a role on a portfolio."""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = ["user", "portfolio"]
|
||||||
|
|
||||||
|
PORTFOLIO_ROLE_PERMISSIONS = {
|
||||||
|
UserPortfolioRoleChoices.ORGANIZATION_ADMIN: [
|
||||||
|
UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS,
|
||||||
|
UserPortfolioPermissionChoices.VIEW_MEMBER,
|
||||||
|
UserPortfolioPermissionChoices.EDIT_MEMBER,
|
||||||
|
UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS,
|
||||||
|
UserPortfolioPermissionChoices.EDIT_REQUESTS,
|
||||||
|
UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
|
||||||
|
UserPortfolioPermissionChoices.EDIT_PORTFOLIO,
|
||||||
|
# Domain: field specific permissions
|
||||||
|
UserPortfolioPermissionChoices.VIEW_SUBORGANIZATION,
|
||||||
|
UserPortfolioPermissionChoices.EDIT_SUBORGANIZATION,
|
||||||
|
],
|
||||||
|
UserPortfolioRoleChoices.ORGANIZATION_ADMIN_READ_ONLY: [
|
||||||
|
UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS,
|
||||||
|
UserPortfolioPermissionChoices.VIEW_MEMBER,
|
||||||
|
UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS,
|
||||||
|
UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
|
||||||
|
# Domain: field specific permissions
|
||||||
|
UserPortfolioPermissionChoices.VIEW_SUBORGANIZATION,
|
||||||
|
],
|
||||||
|
UserPortfolioRoleChoices.ORGANIZATION_MEMBER: [
|
||||||
|
UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
user = models.ForeignKey(
|
||||||
|
"registrar.User",
|
||||||
|
null=False,
|
||||||
|
# when a portfolio is deleted, permissions are too
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="portfolio_permissions",
|
||||||
|
)
|
||||||
|
|
||||||
|
portfolio = models.ForeignKey(
|
||||||
|
"registrar.Portfolio",
|
||||||
|
null=False,
|
||||||
|
# when a portfolio is deleted, permissions are too
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="portfolio_users",
|
||||||
|
)
|
||||||
|
|
||||||
|
portfolio_roles = ArrayField(
|
||||||
|
models.CharField(
|
||||||
|
max_length=50,
|
||||||
|
choices=UserPortfolioRoleChoices.choices,
|
||||||
|
),
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Select one or more roles.",
|
||||||
|
)
|
||||||
|
|
||||||
|
portfolio_additional_permissions = ArrayField(
|
||||||
|
models.CharField(
|
||||||
|
max_length=50,
|
||||||
|
choices=UserPortfolioPermissionChoices.choices,
|
||||||
|
),
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Select one or more additional permissions.",
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return (
|
||||||
|
f"User '{self.user}' on Portfolio '{self.portfolio}' "
|
||||||
|
f"<Roles: {self.portfolio_roles}>"
|
||||||
|
)
|
||||||
|
|
||||||
|
def _get_portfolio_permissions(self):
|
||||||
|
"""
|
||||||
|
Retrieve the permissions for the user's portfolio roles.
|
||||||
|
"""
|
||||||
|
# Use a set to avoid duplicate permissions
|
||||||
|
portfolio_permissions = set()
|
||||||
|
|
||||||
|
if self.portfolio_roles:
|
||||||
|
for role in self.portfolio_roles:
|
||||||
|
portfolio_permissions.update(self.PORTFOLIO_ROLE_PERMISSIONS.get(role, []))
|
||||||
|
|
||||||
|
if self.portfolio_additional_permissions:
|
||||||
|
portfolio_permissions.update(self.portfolio_additional_permissions)
|
||||||
|
|
||||||
|
return list(portfolio_permissions)
|
Loading…
Add table
Add a link
Reference in a new issue