Delete an application member
This commit is contained in:
parent
547d813970
commit
27a4ef12c6
@ -3,6 +3,7 @@ from sqlalchemy.orm.exc import NoResultFound
|
||||
from atst.database import db
|
||||
from . import BaseDomainClass
|
||||
from atst.domain.application_roles import ApplicationRoles
|
||||
from atst.domain.environment_roles import EnvironmentRoles
|
||||
from atst.domain.environments import Environments
|
||||
from atst.domain.exceptions import NotFoundError
|
||||
from atst.domain.users import Users
|
||||
@ -100,3 +101,15 @@ class Applications(BaseDomainClass):
|
||||
Environments.add_member(environment, user, env_role_data.get("role"))
|
||||
|
||||
return application_role
|
||||
|
||||
@classmethod
|
||||
def remove_member(cls, application, user):
|
||||
application_role = ApplicationRoles.get(
|
||||
user_id=user.id, application_id=application.id
|
||||
)
|
||||
|
||||
db.session.delete(application_role)
|
||||
db.session.commit()
|
||||
|
||||
for env in application.environments:
|
||||
EnvironmentRoles.delete(user_id=user.id, environment_id=env.id)
|
||||
|
@ -158,3 +158,31 @@ def create_member(application_id):
|
||||
_anchor="application-members",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@applications_bp.route(
|
||||
"/applications/<application_id>/members/<user_id>/delete", methods=["POST"]
|
||||
)
|
||||
# TODO: Is this correct??
|
||||
@user_can(Permissions.EDIT_APPLICATION_MEMBER, message="remove application member")
|
||||
def remove_member(application_id, user_id):
|
||||
application_role = ApplicationRoles.get(
|
||||
application_id=application_id, user_id=user_id
|
||||
)
|
||||
|
||||
Applications.remove_member(application=g.application, user=application_role.user)
|
||||
|
||||
flash(
|
||||
"application_member_removed",
|
||||
user_name=application_role.user.full_name,
|
||||
application_name=g.application.name,
|
||||
)
|
||||
|
||||
return redirect(
|
||||
url_for(
|
||||
"applications.team",
|
||||
_anchor="application-members",
|
||||
application_id=g.application.id,
|
||||
fragment="application-members",
|
||||
)
|
||||
)
|
||||
|
@ -2,6 +2,11 @@ from flask import flash, render_template_string
|
||||
from atst.utils.localization import translate
|
||||
|
||||
MESSAGES = {
|
||||
"application_member_removed": {
|
||||
"title_template": "Team member removed from application",
|
||||
"message_template": "You have successfully deleted {{ user_name }} from {{ application_name }}",
|
||||
"category": "success",
|
||||
},
|
||||
"environment_deleted": {
|
||||
"title_template": "{{ environment_name }} deleted",
|
||||
"message_template": 'The environment "{{ environment_name }}" has been deleted',
|
||||
|
@ -1,12 +1,12 @@
|
||||
import ally from 'ally.js'
|
||||
|
||||
import checkboxinput from '../checkbox_input'
|
||||
import DateSelector from '../date_selector'
|
||||
import FormMixin from '../../mixins/form'
|
||||
import levelofwarrant from '../levelofwarrant'
|
||||
import Modal from '../../mixins/modal'
|
||||
import multicheckboxinput from '../multi_checkbox_input'
|
||||
import MultiStepModalForm from './multi_step_modal_form'
|
||||
import checkboxinput from '../checkbox_input'
|
||||
import levelofwarrant from '../levelofwarrant'
|
||||
import multicheckboxinput from '../multi_checkbox_input'
|
||||
import optionsinput from '../options_input'
|
||||
import textinput from '../text_input'
|
||||
import toggler from '../toggler'
|
||||
@ -14,12 +14,12 @@ import toggler from '../toggler'
|
||||
export default {
|
||||
name: 'base-form',
|
||||
components: {
|
||||
checkboxinput,
|
||||
DateSelector,
|
||||
levelofwarrant,
|
||||
Modal,
|
||||
multicheckboxinput,
|
||||
MultiStepModalForm,
|
||||
checkboxinput,
|
||||
levelofwarrant,
|
||||
multicheckboxinput,
|
||||
optionsinput,
|
||||
textinput,
|
||||
toggler,
|
||||
|
@ -3,6 +3,7 @@
|
||||
{{ team_form.csrf_token }}
|
||||
|
||||
{% for member_form in team_form.members %}
|
||||
{% set delete_modal_id = "delete-user-{}".format(member_form.id) %}
|
||||
{% set environment_roles_form = member_form.environment_roles %}
|
||||
{% set permissions_form = member_form.permission_sets %}
|
||||
|
||||
@ -38,6 +39,13 @@
|
||||
{{ environment_form.environment_name.data }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% if user_can(permissions.EDIT_APPLICATION_MEMBER) %}
|
||||
<li class="accordion-table__item__expanded action-group">
|
||||
<span class="usa-button button-danger" v-on:click="openModal('{{ delete_modal_id }}')">
|
||||
{{ "portfolios.members.archive_button" | translate }}
|
||||
</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% endcall %}
|
||||
{{ member_form.user_id() }}
|
||||
|
@ -6,6 +6,9 @@
|
||||
{% from "components/toggle_list.html" import ToggleButton, ToggleSection %}
|
||||
{% from "components/multi_step_modal_form.html" import MultiStepModalForm %}
|
||||
{% import "fragments/applications/new_member_modal_content.html" as member_steps %}
|
||||
{% from "components/alert.html" import Alert %}
|
||||
{% from "components/delete_confirmation.html" import DeleteConfirmation %}
|
||||
{% from "components/modal.html" import Modal %}
|
||||
|
||||
{% set secondary_breadcrumb = 'portfolios.applications.team_settings.title' | translate({ "application_name": application.name }) %}
|
||||
|
||||
@ -109,6 +112,35 @@
|
||||
</div>
|
||||
</form>
|
||||
</base-form>
|
||||
|
||||
{% if user_can(permissions.EDIT_APPLICATION_MEMBER) %}
|
||||
{% for member_form in team_form.members %}
|
||||
{% set delete_modal_id = "delete-user-{}".format(member_form.id) %}
|
||||
{% call Modal(name=delete_modal_id, dismissable=True) %}
|
||||
<h1>
|
||||
{{ "portfolios.applications.remove_member.header" | translate }}
|
||||
</h1>
|
||||
|
||||
{{
|
||||
Alert(
|
||||
title=("portfolios.applications.remove_member.alert.title" | translate),
|
||||
message=("portfolios.applications.remove_member.alert.message" | translate({"user_name": member_form.user_name.data})),
|
||||
level="warning"
|
||||
)
|
||||
}}
|
||||
|
||||
{{
|
||||
DeleteConfirmation(
|
||||
modal_id=delete_modal_id,
|
||||
delete_text=('portfolios.applications.remove_member.button' | translate),
|
||||
delete_action=url_for('applications.remove_member', application_id=application.id, user_id=member_form.data.user_id),
|
||||
form=member_form
|
||||
)
|
||||
}}
|
||||
{% endcall %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if user_can(permissions.CREATE_APPLICATION_MEMBER) %}
|
||||
{% import "fragments/applications/new_member_modal_content.html" as member_steps %}
|
||||
{{ MultiStepModalForm(
|
||||
|
@ -2,16 +2,19 @@ import pytest
|
||||
from uuid import uuid4
|
||||
|
||||
from atst.models import CSPRole, ApplicationRoleStatus
|
||||
from atst.domain.application_roles import ApplicationRoles
|
||||
from atst.domain.applications import Applications
|
||||
from atst.domain.permission_sets import PermissionSets
|
||||
from atst.domain.environment_roles import EnvironmentRoles
|
||||
from atst.domain.exceptions import NotFoundError
|
||||
from atst.domain.permission_sets import PermissionSets
|
||||
|
||||
from tests.factories import (
|
||||
ApplicationFactory,
|
||||
ApplicationRoleFactory,
|
||||
UserFactory,
|
||||
PortfolioFactory,
|
||||
EnvironmentFactory,
|
||||
EnvironmentRoleFactory,
|
||||
PortfolioFactory,
|
||||
UserFactory,
|
||||
)
|
||||
|
||||
|
||||
@ -155,3 +158,25 @@ def test_for_user():
|
||||
assert len(portfolio.applications) == 4
|
||||
user_applications = Applications.for_user(user, portfolio)
|
||||
assert len(user_applications) == 2
|
||||
|
||||
|
||||
def test_remove_member():
|
||||
application = ApplicationFactory.create()
|
||||
user = UserFactory.create()
|
||||
member_role = ApplicationRoleFactory.create(application=application, user=user)
|
||||
environment = EnvironmentFactory.create(application=application)
|
||||
environment_role = EnvironmentRoleFactory.create(user=user, environment=environment)
|
||||
|
||||
assert member_role == ApplicationRoles.get(
|
||||
user_id=user.id, application_id=application.id
|
||||
)
|
||||
|
||||
Applications.remove_member(application=application, user=member_role.user)
|
||||
|
||||
with pytest.raises(NotFoundError):
|
||||
ApplicationRoles.get(user_id=user.id, application_id=application.id)
|
||||
|
||||
#
|
||||
# TODO: Why does above raise NotFoundError and this returns None
|
||||
#
|
||||
assert EnvironmentRoles.get(user_id=user.id, environment_id=environment.id) == None
|
||||
|
@ -1,4 +1,5 @@
|
||||
import pytest
|
||||
import uuid
|
||||
from flask import url_for
|
||||
|
||||
from atst.domain.permission_sets import PermissionSets
|
||||
@ -128,3 +129,43 @@ def test_create_member(client, user_session):
|
||||
assert user.application_roles[0].application == application
|
||||
assert len(user.environment_roles) == 1
|
||||
assert user.environment_roles[0].environment == env
|
||||
|
||||
|
||||
def test_remove_member_success(client, user_session):
|
||||
user = UserFactory.create()
|
||||
application = ApplicationFactory.create()
|
||||
application_role = ApplicationRoleFactory.create(application=application, user=user)
|
||||
|
||||
user_session(application.portfolio.owner)
|
||||
|
||||
response = client.post(
|
||||
url_for(
|
||||
"applications.remove_member", application_id=application.id, user_id=user.id
|
||||
)
|
||||
)
|
||||
|
||||
assert response.status_code == 302
|
||||
assert response.location == url_for(
|
||||
"applications.team",
|
||||
_anchor="application-members",
|
||||
_external=True,
|
||||
application_id=application.id,
|
||||
fragment="application-members",
|
||||
)
|
||||
|
||||
|
||||
def test_remove_member_failure(client, user_session):
|
||||
user = UserFactory.create()
|
||||
application = ApplicationFactory.create()
|
||||
|
||||
user_session(application.portfolio.owner)
|
||||
|
||||
response = client.post(
|
||||
url_for(
|
||||
"applications.remove_member",
|
||||
application_id=application.id,
|
||||
user_id=uuid.uuid4(),
|
||||
)
|
||||
)
|
||||
|
||||
assert response.status_code == 404
|
||||
|
@ -416,6 +416,12 @@ portfolios:
|
||||
app_settings_text: App settings
|
||||
create_button_text: Create
|
||||
csp_console_text: CSP console
|
||||
remove_member:
|
||||
alert:
|
||||
message: '{user_name} will no longer be able to access this application'
|
||||
title: Warning! This action is permanent.
|
||||
button: Remove member
|
||||
header: Are you sure you want to remove this team member?
|
||||
delete:
|
||||
alert:
|
||||
message: You will lose access to this application and all of its reporting and metrics tools. The activity log will be retained.
|
||||
|
Loading…
x
Reference in New Issue
Block a user