Merge pull request #728 from dod-ccpo/edit-perms-pf-members

Edit Portfolio Members Access Levels
This commit is contained in:
montana-mil 2019-04-02 11:14:02 -04:00 committed by GitHub
commit 91c3cc665f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 158 additions and 12 deletions

View File

@ -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=[

View File

@ -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):

View File

@ -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": """

View File

@ -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 %}

View File

@ -6,7 +6,9 @@
{% 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">
{{ member_perms_form.csrf_token }}
<div class='member-list-header'> <div class='member-list-header'>
<div class='left'> <div class='left'>
<div class='h3'>{{ "portfolios.admin.portfolio_members_title" | translate }}</div> <div class='h3'>{{ "portfolios.admin.portfolio_members_title" | translate }}</div>

View File

@ -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()