From 93530e903fd9fff2cbcc9c9e9d358ba5e82176ab Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Fri, 13 Sep 2019 12:18:49 -0400 Subject: [PATCH] Create route for updating app member --- .secrets.baseline | 4 +- atst/forms/application_member.py | 2 - atst/routes/applications/settings.py | 27 ++++++++-- atst/utils/flash.py | 10 ++-- tests/routes/applications/test_settings.py | 63 ++++++++++++++++++++++ tests/test_access.py | 18 +++++++ 6 files changed, 112 insertions(+), 12 deletions(-) diff --git a/.secrets.baseline b/.secrets.baseline index e477008c..b8c620f6 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "^.secrets.baseline$", "lines": null }, - "generated_at": "2019-09-10T18:56:49Z", + "generated_at": "2019-09-13T17:44:56Z", "plugins_used": [ { "base64_limit": 4.5, @@ -194,7 +194,7 @@ "hashed_secret": "e4f14805dfd1e6af030359090c535e149e6b4207", "is_secret": false, "is_verified": false, - "line_number": 507, + "line_number": 525, "type": "Hex High Entropy String" } ] diff --git a/atst/forms/application_member.py b/atst/forms/application_member.py index 30af4097..687b0e0e 100644 --- a/atst/forms/application_member.py +++ b/atst/forms/application_member.py @@ -1,11 +1,9 @@ -from flask_wtf import FlaskForm from wtforms.fields import FormField, FieldList, HiddenField, BooleanField from wtforms import Form from .forms import BaseForm from .member import NewForm as BaseNewMemberForm from .data import ENV_ROLES, ENV_ROLE_NO_ACCESS as NO_ACCESS -from atst.domain.permission_sets import PermissionSets from atst.forms.fields import SelectField from atst.utils.localization import translate diff --git a/atst/routes/applications/settings.py b/atst/routes/applications/settings.py index 399a2d89..8b99c643 100644 --- a/atst/routes/applications/settings.py +++ b/atst/routes/applications/settings.py @@ -14,9 +14,7 @@ from atst.forms.application_member import ( UpdateMemberForm, PermissionsForm, ) -from atst.forms.data import ENV_ROLE_NO_ACCESS as NO_ACCESS from atst.domain.authz.decorator import user_can_access_decorator as user_can -from atst.models.environment_role import CSPRole from atst.models.permissions import Permissions from atst.domain.permission_sets import PermissionSets from atst.utils.flash import formatted_flash as flash @@ -346,4 +344,27 @@ def remove_member(application_id, application_role_id): ) @user_can(Permissions.EDIT_APPLICATION_MEMBER, message="update application member") def update_member(application_id, application_role_id): - return redirect(url_for("applications.settings", application_id=g.application.id)) + app_role = ApplicationRoles.get_by_id(application_role_id) + form = UpdateMemberForm(http_request.form) + + if form.validate(): + new_perm_sets_names = perm_sets_obj_to_list(form.permission_sets.data) + ApplicationRoles.update_permission_sets(app_role, new_perm_sets_names) + + for env_role in form.environment_roles: + environment = Environments.get(env_role.environment_id.data) + Environments.update_env_role(environment, app_role, env_role.data["role"]) + + flash("application_member_updated", user_name=app_role.user_name) + else: + pass + # TODO: flash error message + + return redirect( + url_for( + "applications.settings", + application_id=application_id, + fragment="application-members", + _anchor="application-members", + ) + ) diff --git a/atst/utils/flash.py b/atst/utils/flash.py index b511f4d2..dfb0d324 100644 --- a/atst/utils/flash.py +++ b/atst/utils/flash.py @@ -7,11 +7,6 @@ MESSAGES = { "message_template": "Portfolio '{{portfolio_name}}' has been deleted", "category": "success", }, - "application_environment_members_updated": { - "title_template": "Application environment members updated", - "message_template": "Application environment members have been updated", - "category": "success", - }, "application_deleted": { "title_template": translate("flash.success"), "message_template": """ @@ -30,6 +25,11 @@ MESSAGES = { "message_template": "You have successfully deleted {{ user_name }} from {{ application_name }}", "category": "success", }, + "application_member_updated": { + "title_template": "Team member updated", + "message_template": "You have successfully updated the permissions for {{ user_name }}", + "category": "success", + }, "ccpo_user_added": { "title_template": translate("flash.success"), "message_template": "You have successfully given {{ user_name }} CCPO permissions.", diff --git a/tests/routes/applications/test_settings.py b/tests/routes/applications/test_settings.py index 8a69c22e..4cfceed7 100644 --- a/tests/routes/applications/test_settings.py +++ b/tests/routes/applications/test_settings.py @@ -13,6 +13,7 @@ from atst.domain.permission_sets import PermissionSets from atst.domain.portfolios import Portfolios from atst.domain.exceptions import NotFoundError from atst.models.environment_role import CSPRole +from atst.models.permissions import Permissions from atst.models.portfolio_role import Status as PortfolioRoleStatus from atst.forms.application import EditEnvironmentForm from atst.forms.data import ENV_ROLE_NO_ACCESS as NO_ACCESS @@ -453,3 +454,65 @@ def test_remove_member_failure(client, user_session): ) assert response.status_code == 404 + + +def test_update_member(client, user_session): + role = PermissionSets.get(PermissionSets.EDIT_APPLICATION_TEAM) + app_role = ApplicationRoleFactory.create(permission_sets=[role]) + application = app_role.application + env = EnvironmentFactory.create(application=application) + env_1 = EnvironmentFactory.create(application=application) + env_2 = EnvironmentFactory.create(application=application) + EnvironmentRoleFactory.create( + environment=env, application_role=app_role, role=CSPRole.BASIC_ACCESS.value + ) + EnvironmentRoleFactory.create( + environment=env_1, application_role=app_role, role=CSPRole.BASIC_ACCESS.value + ) + + user_session(application.portfolio.owner) + + response = client.post( + url_for( + "applications.update_member", + application_id=application.id, + application_role_id=app_role.id, + ), + data={ + "environment_roles-0-environment_id": env.id, + "environment_roles-0-role": CSPRole.TECHNICAL_READ.value, + "environment_roles-0-environment_name": env.name, + "environment_roles-1-environment_id": env_1.id, + "environment_roles-1-role": NO_ACCESS, + "environment_roles-1-environment_name": env_1.name, + "environment_roles-2-environment_id": env_2.id, + "environment_roles-2-role": CSPRole.NETWORK_ADMIN.value, + "environment_roles-2-environment_name": env_2.name, + "permission_sets-perms_env_mgmt": True, + "permission_sets-perms_team_mgmt": True, + "permission_sets-perms_del_env": True, + }, + ) + + assert response.status_code == 302 + expected_url = url_for( + "applications.settings", + application_id=application.id, + fragment="application-members", + _anchor="application-members", + _external=True, + ) + assert response.location == expected_url + assert len(application.roles) == 1 + assert bool(app_role.has_permission_set(PermissionSets.EDIT_APPLICATION_TEAM)) + assert bool( + app_role.has_permission_set(PermissionSets.EDIT_APPLICATION_ENVIRONMENTS) + ) + assert bool( + app_role.has_permission_set(PermissionSets.DELETE_APPLICATION_ENVIRONMENTS) + ) + + environment_roles = application.roles[0].environment_roles + assert len(environment_roles) == 2 + assert environment_roles[0].environment in [env, env_2] + assert environment_roles[1].environment in [env, env_2] diff --git a/tests/test_access.py b/tests/test_access.py index 5f0563fe..779ef7f6 100644 --- a/tests/test_access.py +++ b/tests/test_access.py @@ -464,6 +464,24 @@ def test_applications_update_environments(post_url_assert_status): post_url_assert_status(rando, url, 404) +# applications.update_member +def test_applications_update_member(post_url_assert_status): + ccpo = UserFactory.create_ccpo() + rando = UserFactory.create() + + application_role = ApplicationRoleFactory.create() + application = application_role.application + + url = url_for( + "applications.update_member", + application_id=application.id, + application_role_id=application_role.id, + ) + post_url_assert_status(application.portfolio.owner, url, 302) + post_url_assert_status(ccpo, url, 302) + post_url_assert_status(rando, url, 404) + + # task_orders.download_task_order_pdf def test_task_orders_download_task_order_pdf_access(get_url_assert_status, monkeypatch): monkeypatch.setattr(