mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-25 20:18:38 +02:00
Fix portfolio transfer
This commit is contained in:
parent
6a196665dd
commit
e1e812c5c7
4 changed files with 60 additions and 51 deletions
|
@ -6,7 +6,7 @@ from django.db.models import Q
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
|
|
||||||
from registrar.models import DomainInformation, UserDomainRole
|
from registrar.models import DomainInformation, UserDomainRole
|
||||||
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices
|
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices
|
||||||
|
|
||||||
from .domain_invitation import DomainInvitation
|
from .domain_invitation import DomainInvitation
|
||||||
from .portfolio_invitation import PortfolioInvitation
|
from .portfolio_invitation import PortfolioInvitation
|
||||||
|
@ -64,32 +64,6 @@ class User(AbstractUser):
|
||||||
# after they login.
|
# after they login.
|
||||||
FIXTURE_USER = "fixture_user", "Created by fixtures"
|
FIXTURE_USER = "fixture_user", "Created by fixtures"
|
||||||
|
|
||||||
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,
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
# #### Constants for choice fields ####
|
# #### Constants for choice fields ####
|
||||||
RESTRICTED = "restricted"
|
RESTRICTED = "restricted"
|
||||||
STATUS_CHOICES = ((RESTRICTED, RESTRICTED),)
|
STATUS_CHOICES = ((RESTRICTED, RESTRICTED),)
|
||||||
|
|
|
@ -111,6 +111,18 @@
|
||||||
None
|
None
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</dd>
|
</dd>
|
||||||
|
<dt>Portfolios:</dt>
|
||||||
|
<dd>
|
||||||
|
{% if selected_user_portfolios %}
|
||||||
|
<ul>
|
||||||
|
{% for portfolio in selected_user_portfolios %}
|
||||||
|
<li>{{ portfolio.portfolio }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
None
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>No user selected yet.</p>
|
<p>No user selected yet.</p>
|
||||||
|
@ -167,6 +179,18 @@
|
||||||
None
|
None
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</dd>
|
</dd>
|
||||||
|
<dt>Portfolios:</dt>
|
||||||
|
<dd>
|
||||||
|
{% if current_user_portfolios %}
|
||||||
|
<ul>
|
||||||
|
{% for portfolio in current_user_portfolios %}
|
||||||
|
<li>{{ portfolio.portfolio }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
None
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -45,7 +45,8 @@ from registrar.models import (
|
||||||
from registrar.models.portfolio_invitation import PortfolioInvitation
|
from registrar.models.portfolio_invitation import PortfolioInvitation
|
||||||
from registrar.models.senior_official import SeniorOfficial
|
from registrar.models.senior_official import SeniorOfficial
|
||||||
from registrar.models.user_domain_role import UserDomainRole
|
from registrar.models.user_domain_role import UserDomainRole
|
||||||
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices
|
from registrar.models.user_portfolio_permission import UserPortfolioPermission
|
||||||
|
from registrar.models.utility.portfolio_helper import UserPortfolioRoleChoices
|
||||||
from registrar.models.verified_by_staff import VerifiedByStaff
|
from registrar.models.verified_by_staff import VerifiedByStaff
|
||||||
from .common import (
|
from .common import (
|
||||||
MockDbForSharedTests,
|
MockDbForSharedTests,
|
||||||
|
@ -2162,6 +2163,14 @@ class TestTransferUser(WebTest):
|
||||||
)
|
)
|
||||||
domain_request.status = DomainRequest.DomainRequestStatus.APPROVED
|
domain_request.status = DomainRequest.DomainRequestStatus.APPROVED
|
||||||
domain_request.save()
|
domain_request.save()
|
||||||
|
portfolio1 = Portfolio.objects.create(organization_name="Hotel California", creator=self.user2)
|
||||||
|
UserPortfolioPermission.objects.create(
|
||||||
|
user=self.user1, portfolio=portfolio1, roles=[UserPortfolioRoleChoices.ORGANIZATION_ADMIN]
|
||||||
|
)
|
||||||
|
portfolio2 = Portfolio.objects.create(organization_name="Tokyo Hotel", creator=self.user2)
|
||||||
|
UserPortfolioPermission.objects.create(
|
||||||
|
user=self.user2, portfolio=portfolio2, roles=[UserPortfolioRoleChoices.ORGANIZATION_ADMIN]
|
||||||
|
)
|
||||||
|
|
||||||
user_transfer_page = self.app.get(reverse("transfer_user", args=[self.user1.pk]))
|
user_transfer_page = self.app.get(reverse("transfer_user", args=[self.user1.pk]))
|
||||||
|
|
||||||
|
@ -2171,6 +2180,7 @@ class TestTransferUser(WebTest):
|
||||||
self.assertContains(user_transfer_page, "Road warrior")
|
self.assertContains(user_transfer_page, "Road warrior")
|
||||||
self.assertContains(user_transfer_page, "wasteland.gov")
|
self.assertContains(user_transfer_page, "wasteland.gov")
|
||||||
self.assertContains(user_transfer_page, "citadel.gov")
|
self.assertContains(user_transfer_page, "citadel.gov")
|
||||||
|
self.assertContains(user_transfer_page, "Hotel California")
|
||||||
|
|
||||||
select_form = user_transfer_page.forms[0]
|
select_form = user_transfer_page.forms[0]
|
||||||
select_form["selected_user"] = str(self.user2.id)
|
select_form["selected_user"] = str(self.user2.id)
|
||||||
|
@ -2180,19 +2190,15 @@ class TestTransferUser(WebTest):
|
||||||
self.assertContains(preview_result, "Furiosa")
|
self.assertContains(preview_result, "Furiosa")
|
||||||
self.assertContains(preview_result, "Jabassa")
|
self.assertContains(preview_result, "Jabassa")
|
||||||
self.assertContains(preview_result, "Imperator")
|
self.assertContains(preview_result, "Imperator")
|
||||||
|
self.assertContains(preview_result, "Tokyo Hotel")
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_transfer_user_transfers_portfolio_roles_and_permissions_and_portfolio_creator(self):
|
def test_transfer_user_transfers_user_portfolio_roles(self):
|
||||||
"""Assert that a portfolio gets copied over
|
"""Assert that a portfolio user role gets transferred"""
|
||||||
NOTE: Should be revised for #2644"""
|
portfolio = Portfolio.objects.create(organization_name="Hotel California", creator=self.user2)
|
||||||
portfolio = Portfolio.objects.create(organization_name="Citadel", creator=self.user2)
|
user_portfolio_permission = UserPortfolioPermission.objects.create(
|
||||||
self.user2.portfolio = portfolio
|
user=self.user2, portfolio=portfolio, roles=[UserPortfolioRoleChoices.ORGANIZATION_ADMIN]
|
||||||
self.user2.portfolio_roles = [UserPortfolioRoleChoices.ORGANIZATION_ADMIN]
|
)
|
||||||
self.user2.portfolio_additional_permissions = [
|
|
||||||
UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
|
|
||||||
UserPortfolioPermissionChoices.EDIT_PORTFOLIO,
|
|
||||||
]
|
|
||||||
self.user2.save()
|
|
||||||
|
|
||||||
user_transfer_page = self.app.get(reverse("transfer_user", args=[self.user1.pk]))
|
user_transfer_page = self.app.get(reverse("transfer_user", args=[self.user1.pk]))
|
||||||
|
|
||||||
|
@ -2200,16 +2206,9 @@ class TestTransferUser(WebTest):
|
||||||
submit_form["selected_user"] = self.user2.pk
|
submit_form["selected_user"] = self.user2.pk
|
||||||
submit_form.submit()
|
submit_form.submit()
|
||||||
|
|
||||||
self.user1.refresh_from_db()
|
user_portfolio_permission.refresh_from_db()
|
||||||
portfolio.refresh_from_db()
|
|
||||||
|
|
||||||
self.assertEquals(portfolio.creator, self.user1)
|
self.assertEquals(user_portfolio_permission.user, self.user1)
|
||||||
self.assertEquals(self.user1.portfolio, portfolio)
|
|
||||||
self.assertEquals(self.user1.portfolio_roles, [UserPortfolioRoleChoices.ORGANIZATION_ADMIN])
|
|
||||||
self.assertEquals(
|
|
||||||
self.user1.portfolio_additional_permissions,
|
|
||||||
[UserPortfolioPermissionChoices.VIEW_PORTFOLIO, UserPortfolioPermissionChoices.EDIT_PORTFOLIO],
|
|
||||||
)
|
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_transfer_user_transfers_domain_request_creator_and_investigator(self):
|
def test_transfer_user_transfers_domain_request_creator_and_investigator(self):
|
||||||
|
|
|
@ -11,7 +11,9 @@ from django.contrib.admin import site
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
|
||||||
from registrar.models.user_domain_role import UserDomainRole
|
from registrar.models.user_domain_role import UserDomainRole
|
||||||
|
from registrar.models.user_portfolio_permission import UserPortfolioPermission
|
||||||
from registrar.models.verified_by_staff import VerifiedByStaff
|
from registrar.models.verified_by_staff import VerifiedByStaff
|
||||||
|
from typing import Any, List
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -26,9 +28,12 @@ class TransferUserView(View):
|
||||||
(DomainRequest, "investigator"),
|
(DomainRequest, "investigator"),
|
||||||
(UserDomainRole, "user"),
|
(UserDomainRole, "user"),
|
||||||
(VerifiedByStaff, "requestor"),
|
(VerifiedByStaff, "requestor"),
|
||||||
|
(UserPortfolioPermission, "user"),
|
||||||
]
|
]
|
||||||
|
|
||||||
USER_FIELDS = ["portfolio", "portfolio_roles", "portfolio_additional_permissions"]
|
# Future-proofing in case joined fields get added on the user model side
|
||||||
|
# This was tested in the first portfolio model iteration and works
|
||||||
|
USER_FIELDS: List[Any] = []
|
||||||
|
|
||||||
def get(self, request, user_id):
|
def get(self, request, user_id):
|
||||||
"""current_user referes to the 'source' user where the button that redirects to this view was clicked.
|
"""current_user referes to the 'source' user where the button that redirects to this view was clicked.
|
||||||
|
@ -51,6 +56,7 @@ class TransferUserView(View):
|
||||||
**admin_context, # Include the admin context
|
**admin_context, # Include the admin context
|
||||||
"current_user_domains": self.get_domains(current_user),
|
"current_user_domains": self.get_domains(current_user),
|
||||||
"current_user_domain_requests": self.get_domain_requests(current_user),
|
"current_user_domain_requests": self.get_domain_requests(current_user),
|
||||||
|
"current_user_portfolios": self.get_portfolios(current_user),
|
||||||
}
|
}
|
||||||
|
|
||||||
selected_user_id = request.GET.get("selected_user")
|
selected_user_id = request.GET.get("selected_user")
|
||||||
|
@ -59,6 +65,7 @@ class TransferUserView(View):
|
||||||
context["selected_user"] = selected_user
|
context["selected_user"] = selected_user
|
||||||
context["selected_user_domains"] = self.get_domains(selected_user)
|
context["selected_user_domains"] = self.get_domains(selected_user)
|
||||||
context["selected_user_domain_requests"] = self.get_domain_requests(selected_user)
|
context["selected_user_domain_requests"] = self.get_domain_requests(selected_user)
|
||||||
|
context["selected_user_portfolios"] = self.get_portfolios(selected_user)
|
||||||
|
|
||||||
return render(request, "admin/transfer_user.html", context)
|
return render(request, "admin/transfer_user.html", context)
|
||||||
|
|
||||||
|
@ -121,8 +128,6 @@ class TransferUserView(View):
|
||||||
"""
|
"""
|
||||||
Transfers portfolio fields from the selected_user to the current_user.
|
Transfers portfolio fields from the selected_user to the current_user.
|
||||||
Logs the changes for each transferred field.
|
Logs the changes for each transferred field.
|
||||||
|
|
||||||
NOTE: This will be refactored in #2644
|
|
||||||
"""
|
"""
|
||||||
for field in cls.USER_FIELDS:
|
for field in cls.USER_FIELDS:
|
||||||
field_value = getattr(selected_user, field, None)
|
field_value = getattr(selected_user, field, None)
|
||||||
|
@ -158,3 +163,10 @@ class TransferUserView(View):
|
||||||
domain_requests = DomainRequest.objects.filter(creator=user)
|
domain_requests = DomainRequest.objects.filter(creator=user)
|
||||||
|
|
||||||
return domain_requests
|
return domain_requests
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_portfolios(cls, user):
|
||||||
|
"""Get portfolios"""
|
||||||
|
portfolios = UserPortfolioPermission.objects.filter(user=user)
|
||||||
|
|
||||||
|
return portfolios
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue