Merge pull request #728 from dod-ccpo/edit-perms-pf-members
Edit Portfolio Members Access Levels
This commit is contained in:
commit
91c3cc665f
@ -1,6 +1,6 @@
|
|||||||
from wtforms.fields import StringField, FormField, FieldList
|
|
||||||
from wtforms.fields.html5 import EmailField, TelField
|
from wtforms.fields.html5 import EmailField, TelField
|
||||||
from wtforms.validators import Required, Email, Length, Optional
|
from wtforms.validators import Required, Email, Length, Optional
|
||||||
|
from wtforms.fields import StringField, FormField, FieldList, HiddenField
|
||||||
|
|
||||||
from atst.domain.permission_sets import PermissionSets
|
from atst.domain.permission_sets import PermissionSets
|
||||||
from .forms import BaseForm
|
from .forms import BaseForm
|
||||||
@ -11,6 +11,7 @@ from atst.utils.localization import translate
|
|||||||
|
|
||||||
class PermissionsForm(BaseForm):
|
class PermissionsForm(BaseForm):
|
||||||
member = StringField()
|
member = StringField()
|
||||||
|
user_id = HiddenField()
|
||||||
perms_app_mgmt = SelectField(
|
perms_app_mgmt = SelectField(
|
||||||
None,
|
None,
|
||||||
choices=[
|
choices=[
|
||||||
|
@ -2,9 +2,12 @@ from datetime import date, timedelta
|
|||||||
|
|
||||||
from flask import render_template, request as http_request, g, redirect, url_for
|
from flask import render_template, request as http_request, g, redirect, url_for
|
||||||
|
|
||||||
|
from atst.utils.flash import formatted_flash as flash
|
||||||
|
|
||||||
from . import portfolios_bp
|
from . import portfolios_bp
|
||||||
from atst.domain.reports import Reports
|
from atst.domain.reports import Reports
|
||||||
from atst.domain.portfolios import Portfolios
|
from atst.domain.portfolios import Portfolios
|
||||||
|
from atst.domain.portfolio_roles import PortfolioRoles
|
||||||
from atst.domain.audit_log import AuditLog
|
from atst.domain.audit_log import AuditLog
|
||||||
from atst.domain.common import Paginator
|
from atst.domain.common import Paginator
|
||||||
from atst.forms.portfolio import PortfolioForm
|
from atst.forms.portfolio import PortfolioForm
|
||||||
@ -34,6 +37,7 @@ def permission_str(member, edit_perm_set, view_perm_set):
|
|||||||
def serialize_member_form_data(member):
|
def serialize_member_form_data(member):
|
||||||
return {
|
return {
|
||||||
"member": member.user.full_name,
|
"member": member.user.full_name,
|
||||||
|
"user_id": member.user_id,
|
||||||
"perms_app_mgmt": permission_str(
|
"perms_app_mgmt": permission_str(
|
||||||
member,
|
member,
|
||||||
PermissionSets.EDIT_PORTFOLIO_APPLICATION_MANAGEMENT,
|
PermissionSets.EDIT_PORTFOLIO_APPLICATION_MANAGEMENT,
|
||||||
@ -86,6 +90,33 @@ def portfolio_admin(portfolio_id):
|
|||||||
return render_admin_page(portfolio)
|
return render_admin_page(portfolio)
|
||||||
|
|
||||||
|
|
||||||
|
@portfolios_bp.route("/portfolios/<portfolio_id>/admin", methods=["POST"])
|
||||||
|
@user_can(Permissions.EDIT_PORTFOLIO_USERS, message="view portfolio admin page")
|
||||||
|
def edit_portfolio_members(portfolio_id):
|
||||||
|
portfolio = Portfolios.get_for_update(portfolio_id)
|
||||||
|
member_perms_form = member_forms.MembersPermissionsForm(http_request.form)
|
||||||
|
|
||||||
|
if member_perms_form.validate():
|
||||||
|
for subform in member_perms_form.members_permissions:
|
||||||
|
new_perm_set = subform.data["permission_sets"]
|
||||||
|
user_id = subform.user_id.data
|
||||||
|
portfolio_role = PortfolioRoles.get(portfolio.id, user_id)
|
||||||
|
PortfolioRoles.update(portfolio_role, new_perm_set)
|
||||||
|
|
||||||
|
flash("update_portfolio_members", portfolio=portfolio)
|
||||||
|
|
||||||
|
return redirect(
|
||||||
|
url_for(
|
||||||
|
"portfolios.portfolio_admin",
|
||||||
|
portfolio_id=portfolio.id,
|
||||||
|
fragment="portfolio-members",
|
||||||
|
_anchor="portfolio-members",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return render_admin_page(portfolio)
|
||||||
|
|
||||||
|
|
||||||
@portfolios_bp.route("/portfolios/<portfolio_id>/edit", methods=["POST"])
|
@portfolios_bp.route("/portfolios/<portfolio_id>/edit", methods=["POST"])
|
||||||
@user_can(Permissions.EDIT_PORTFOLIO_NAME, message="edit portfolio")
|
@user_can(Permissions.EDIT_PORTFOLIO_NAME, message="edit portfolio")
|
||||||
def edit_portfolio(portfolio_id):
|
def edit_portfolio(portfolio_id):
|
||||||
|
@ -21,6 +21,13 @@ MESSAGES = {
|
|||||||
""",
|
""",
|
||||||
"category": "success",
|
"category": "success",
|
||||||
},
|
},
|
||||||
|
"update_portfolio_members": {
|
||||||
|
"title_template": "Success!",
|
||||||
|
"message_template": """
|
||||||
|
<p>You have successfully updated access permissions for members of {{ portfolio.name }}.</p>
|
||||||
|
""",
|
||||||
|
"category": "success",
|
||||||
|
},
|
||||||
"new_portfolio_member": {
|
"new_portfolio_member": {
|
||||||
"title_template": "Success!",
|
"title_template": "Success!",
|
||||||
"message_template": """
|
"message_template": """
|
||||||
|
@ -16,5 +16,6 @@
|
|||||||
|
|
||||||
<td><button type="button" class='{{ archive_button_class }}'>{{ "portfolios.members.archive_button" | translate }}</button>
|
<td><button type="button" class='{{ archive_button_class }}'>{{ "portfolios.members.archive_button" | translate }}</button>
|
||||||
</td>
|
</td>
|
||||||
|
{{ subform.user_id() }}
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -6,18 +6,20 @@
|
|||||||
{% if g.matchesPath("portfolio-members") %}
|
{% if g.matchesPath("portfolio-members") %}
|
||||||
{% include "fragments/flash.html" %}
|
{% include "fragments/flash.html" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<form method='POST' id="member-perms" autocomplete="off" enctype="multipart/form-data">
|
<form method='POST' id="member-perms" action='{{ url_for("portfolios.edit_portfolio_members", portfolio_id=portfolio.id) }}' autocomplete="off" enctype="multipart/form-data">
|
||||||
<div class='member-list-header'>
|
{{ member_perms_form.csrf_token }}
|
||||||
<div class='left'>
|
|
||||||
<div class='h3'>{{ "portfolios.admin.portfolio_members_title" | translate }}</div>
|
<div class='member-list-header'>
|
||||||
<div class='subheading'>
|
<div class='left'>
|
||||||
{{ "portfolios.admin.portfolio_members_subheading" | translate }}
|
<div class='h3'>{{ "portfolios.admin.portfolio_members_title" | translate }}</div>
|
||||||
</div>
|
<div class='subheading'>
|
||||||
|
{{ "portfolios.admin.portfolio_members_subheading" | translate }}
|
||||||
</div>
|
</div>
|
||||||
<a class='icon-link'>
|
</div>
|
||||||
{{ Icon('info') }}
|
<a class='icon-link'>
|
||||||
{{ "portfolios.admin.settings_info" | translate }}
|
{{ Icon('info') }}
|
||||||
</a>
|
{{ "portfolios.admin.settings_info" | translate }}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if not portfolio.members %}
|
{% if not portfolio.members %}
|
||||||
|
@ -26,3 +26,107 @@ def test_member_table_access(client, user_session):
|
|||||||
user_session(rando)
|
user_session(rando)
|
||||||
view_resp = client.get(url)
|
view_resp = client.get(url)
|
||||||
assert "<select" not in view_resp.data.decode()
|
assert "<select" not in view_resp.data.decode()
|
||||||
|
|
||||||
|
|
||||||
|
def test_update_member_permissions(client, user_session):
|
||||||
|
portfolio = PortfolioFactory.create()
|
||||||
|
rando = UserFactory.create()
|
||||||
|
rando_pf_role = PortfolioRoleFactory.create(
|
||||||
|
user=rando,
|
||||||
|
portfolio=portfolio,
|
||||||
|
permission_sets=[PermissionSets.get(PermissionSets.VIEW_PORTFOLIO_ADMIN)],
|
||||||
|
)
|
||||||
|
|
||||||
|
user = UserFactory.create()
|
||||||
|
PortfolioRoleFactory.create(
|
||||||
|
user=user,
|
||||||
|
portfolio=portfolio,
|
||||||
|
permission_sets=PermissionSets.get_many(
|
||||||
|
[PermissionSets.EDIT_PORTFOLIO_ADMIN, PermissionSets.VIEW_PORTFOLIO_ADMIN]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
user_session(user)
|
||||||
|
|
||||||
|
form_data = {
|
||||||
|
"members_permissions-0-user_id": rando.id,
|
||||||
|
"members_permissions-0-perms_app_mgmt": "edit_portfolio_application_management",
|
||||||
|
"members_permissions-0-perms_funding": "view_portfolio_funding",
|
||||||
|
"members_permissions-0-perms_reporting": "view_portfolio_reports",
|
||||||
|
"members_permissions-0-perms_portfolio_mgmt": "view_portfolio_admin",
|
||||||
|
}
|
||||||
|
|
||||||
|
response = client.post(
|
||||||
|
url_for("portfolios.edit_portfolio_members", portfolio_id=portfolio.id),
|
||||||
|
data=form_data,
|
||||||
|
follow_redirects=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert rando_pf_role.has_permission_set(
|
||||||
|
PermissionSets.EDIT_PORTFOLIO_APPLICATION_MANAGEMENT
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_update_member_permissions_without_edit_access(client, user_session):
|
||||||
|
portfolio = PortfolioFactory.create()
|
||||||
|
rando = UserFactory.create()
|
||||||
|
rando_pf_role = PortfolioRoleFactory.create(
|
||||||
|
user=rando,
|
||||||
|
portfolio=portfolio,
|
||||||
|
permission_sets=[PermissionSets.get(PermissionSets.VIEW_PORTFOLIO_ADMIN)],
|
||||||
|
)
|
||||||
|
|
||||||
|
user = UserFactory.create()
|
||||||
|
PortfolioRoleFactory.create(
|
||||||
|
user=user,
|
||||||
|
portfolio=portfolio,
|
||||||
|
permission_sets=[PermissionSets.get(PermissionSets.VIEW_PORTFOLIO_ADMIN)],
|
||||||
|
)
|
||||||
|
user_session(user)
|
||||||
|
|
||||||
|
form_data = {
|
||||||
|
"members_permissions-0-user_id": rando.id,
|
||||||
|
"members_permissions-0-perms_app_mgmt": "edit_portfolio_application_management",
|
||||||
|
"members_permissions-0-perms_funding": "view_portfolio_funding",
|
||||||
|
"members_permissions-0-perms_reporting": "view_portfolio_reports",
|
||||||
|
"members_permissions-0-perms_portfolio_mgmt": "view_portfolio_admin",
|
||||||
|
}
|
||||||
|
|
||||||
|
response = client.post(
|
||||||
|
url_for("portfolios.edit_portfolio_members", portfolio_id=portfolio.id),
|
||||||
|
data=form_data,
|
||||||
|
follow_redirects=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert not rando_pf_role.has_permission_set(
|
||||||
|
PermissionSets.EDIT_PORTFOLIO_APPLICATION_MANAGEMENT
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_rerender_admin_page_if_member_perms_form_does_not_validate(
|
||||||
|
client, user_session
|
||||||
|
):
|
||||||
|
portfolio = PortfolioFactory.create()
|
||||||
|
user = UserFactory.create()
|
||||||
|
PortfolioRoleFactory.create(
|
||||||
|
user=user,
|
||||||
|
portfolio=portfolio,
|
||||||
|
permission_sets=[PermissionSets.get(PermissionSets.EDIT_PORTFOLIO_ADMIN)],
|
||||||
|
)
|
||||||
|
user_session(user)
|
||||||
|
form_data = {
|
||||||
|
"members_permissions-0-user_id": user.id,
|
||||||
|
"members_permissions-0-perms_app_mgmt": "bad input",
|
||||||
|
"members_permissions-0-perms_funding": "view_portfolio_funding",
|
||||||
|
"members_permissions-0-perms_reporting": "view_portfolio_reports",
|
||||||
|
"members_permissions-0-perms_portfolio_mgmt": "view_portfolio_admin",
|
||||||
|
}
|
||||||
|
|
||||||
|
response = client.post(
|
||||||
|
url_for("portfolios.edit_portfolio_members", portfolio_id=portfolio.id),
|
||||||
|
data=form_data,
|
||||||
|
follow_redirects=True,
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert "Portfolio Administration" in response.data.decode()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user