Merge pull request #801 from dod-ccpo/app-team-permissions
Application Team Table Permissions
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
from sqlalchemy.orm.exc import NoResultFound
|
||||
|
||||
from atst.database import db
|
||||
from atst.models import ApplicationRole, ApplicationRoleStatus
|
||||
from atst.domain.permission_sets import PermissionSets
|
||||
from .permission_sets import PermissionSets
|
||||
from .exceptions import NotFoundError
|
||||
|
||||
|
||||
class ApplicationRoles(object):
|
||||
@@ -28,3 +31,27 @@ class ApplicationRoles(object):
|
||||
|
||||
db.session.add(role)
|
||||
db.session.commit()
|
||||
|
||||
@classmethod
|
||||
def get(cls, user_id, application_id):
|
||||
try:
|
||||
app_role = (
|
||||
db.session.query(ApplicationRole)
|
||||
.filter_by(user_id=user_id, application_id=application_id)
|
||||
.one()
|
||||
)
|
||||
except NoResultFound:
|
||||
raise NotFoundError("application_role")
|
||||
|
||||
return app_role
|
||||
|
||||
@classmethod
|
||||
def update_permission_sets(cls, application_role, new_perm_sets_names):
|
||||
application_role.permission_sets = ApplicationRoles._permission_sets_for_names(
|
||||
new_perm_sets_names
|
||||
)
|
||||
|
||||
db.session.add(application_role)
|
||||
db.session.commit()
|
||||
|
||||
return application_role
|
||||
|
@@ -1,7 +1,7 @@
|
||||
from flask import current_app as app
|
||||
|
||||
from atst.database import db
|
||||
from atst.models import EnvironmentRole
|
||||
from atst.models import EnvironmentRole, Application, Environment
|
||||
|
||||
|
||||
class EnvironmentRoles(object):
|
||||
@@ -35,3 +35,15 @@ class EnvironmentRoles(object):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def get_for_application_and_user(cls, user_id, application_id):
|
||||
return (
|
||||
db.session.query(EnvironmentRole)
|
||||
.join(Environment)
|
||||
.join(Application, Environment.application_id == Application.id)
|
||||
.filter(EnvironmentRole.user_id == user_id)
|
||||
.filter(Application.id == application_id)
|
||||
.filter(EnvironmentRole.environment_id == Environment.id)
|
||||
.all()
|
||||
)
|
||||
|
54
atst/forms/team.py
Normal file
54
atst/forms/team.py
Normal file
@@ -0,0 +1,54 @@
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms.fields import FormField, FieldList, HiddenField, StringField
|
||||
from wtforms.validators import Required
|
||||
|
||||
from .application_member import EnvironmentForm
|
||||
from .forms import BaseForm
|
||||
from atst.forms.fields import SelectField
|
||||
from atst.domain.permission_sets import PermissionSets
|
||||
from atst.utils.localization import translate
|
||||
|
||||
|
||||
class PermissionsForm(FlaskForm):
|
||||
perms_team_mgmt = SelectField(
|
||||
translate("portfolios.applications.members.new.manage_team"),
|
||||
choices=[
|
||||
(PermissionSets.VIEW_APPLICATION, "View only"),
|
||||
(PermissionSets.EDIT_APPLICATION_TEAM, "Edit access"),
|
||||
],
|
||||
)
|
||||
perms_env_mgmt = SelectField(
|
||||
translate("portfolios.applications.members.new.manage_envs"),
|
||||
choices=[
|
||||
(PermissionSets.VIEW_APPLICATION, "View only"),
|
||||
(PermissionSets.EDIT_APPLICATION_ENVIRONMENTS, "Edit access"),
|
||||
],
|
||||
)
|
||||
perms_del_env = SelectField(
|
||||
choices=[
|
||||
(PermissionSets.VIEW_APPLICATION, "No"),
|
||||
(PermissionSets.DELETE_APPLICATION_ENVIRONMENTS, "Yes"),
|
||||
]
|
||||
)
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
_data = super().data
|
||||
_data.pop("csrf_token", None)
|
||||
permission_sets = []
|
||||
for field in _data:
|
||||
if _data[field] is not None:
|
||||
permission_sets.append(_data[field])
|
||||
|
||||
return permission_sets
|
||||
|
||||
|
||||
class MemberForm(FlaskForm):
|
||||
user_id = HiddenField(validators=[Required()])
|
||||
user_name = StringField()
|
||||
environment_roles = FieldList(FormField(EnvironmentForm))
|
||||
permission_sets = FormField(PermissionsForm)
|
||||
|
||||
|
||||
class TeamForm(BaseForm):
|
||||
members = FieldList(FormField(MemberForm))
|
@@ -28,6 +28,7 @@ class Application(
|
||||
back_populates="application",
|
||||
primaryjoin="and_(Environment.application_id==Application.id, Environment.deleted==False)",
|
||||
)
|
||||
# TODO: filter condition on this relationship?
|
||||
roles = relationship("ApplicationRole")
|
||||
|
||||
@property
|
||||
|
@@ -2,62 +2,120 @@ from flask import render_template, request as http_request, g, url_for, redirect
|
||||
|
||||
|
||||
from . import applications_bp
|
||||
from atst.domain.environments import Environments
|
||||
from atst.domain.applications import Applications
|
||||
from atst.domain.application_roles import ApplicationRoles
|
||||
from atst.domain.authz.decorator import user_can_access_decorator as user_can
|
||||
from atst.domain.permission_sets import PermissionSets
|
||||
from atst.domain.environment_roles import EnvironmentRoles
|
||||
from atst.domain.exceptions import AlreadyExistsError
|
||||
from atst.domain.permission_sets import PermissionSets
|
||||
from atst.forms.application_member import NewForm as NewMemberForm
|
||||
from atst.forms.team import TeamForm
|
||||
from atst.models import Permissions
|
||||
from atst.services.invitation import Invitation as InvitationService
|
||||
from atst.utils.flash import formatted_flash as flash
|
||||
from atst.utils.localization import translate
|
||||
|
||||
|
||||
def permission_str(member, edit_perm_set):
|
||||
def get_form_permission_value(member, edit_perm_set):
|
||||
if member.has_permission_set(edit_perm_set):
|
||||
return translate("portfolios.members.permissions.edit_access")
|
||||
return edit_perm_set
|
||||
else:
|
||||
return translate("portfolios.members.permissions.view_only")
|
||||
return PermissionSets.VIEW_APPLICATION
|
||||
|
||||
|
||||
def get_team_form(application):
|
||||
team_data = []
|
||||
for member in application.members:
|
||||
user_id = member.user.id
|
||||
user_name = member.user.full_name
|
||||
permission_sets = {
|
||||
"perms_team_mgmt": get_form_permission_value(
|
||||
member, PermissionSets.EDIT_APPLICATION_TEAM
|
||||
),
|
||||
"perms_env_mgmt": get_form_permission_value(
|
||||
member, PermissionSets.EDIT_APPLICATION_ENVIRONMENTS
|
||||
),
|
||||
"perms_del_env": get_form_permission_value(
|
||||
member, PermissionSets.DELETE_APPLICATION_ENVIRONMENTS
|
||||
),
|
||||
}
|
||||
roles = EnvironmentRoles.get_for_application_and_user(
|
||||
member.user.id, application.id
|
||||
)
|
||||
environment_roles = [
|
||||
{
|
||||
"environment_id": str(role.environment.id),
|
||||
"environment_name": role.environment.name,
|
||||
"role": role.role,
|
||||
}
|
||||
for role in roles
|
||||
]
|
||||
team_data.append(
|
||||
{
|
||||
"user_id": str(user_id),
|
||||
"user_name": user_name,
|
||||
"permission_sets": permission_sets,
|
||||
"environment_roles": environment_roles,
|
||||
}
|
||||
)
|
||||
|
||||
return TeamForm(data={"members": team_data})
|
||||
|
||||
|
||||
def get_new_member_form(application):
|
||||
env_roles = [
|
||||
{"environment_id": e.id, "environment_name": e.name}
|
||||
for e in application.environments
|
||||
]
|
||||
|
||||
return NewMemberForm(data={"environment_roles": env_roles})
|
||||
|
||||
|
||||
def render_team_page(application):
|
||||
team_form = get_team_form(application)
|
||||
new_member_form = get_new_member_form(application)
|
||||
|
||||
return render_template(
|
||||
"portfolios/applications/team.html",
|
||||
application=application,
|
||||
team_form=team_form,
|
||||
new_member_form=new_member_form,
|
||||
)
|
||||
|
||||
|
||||
@applications_bp.route("/applications/<application_id>/team")
|
||||
@user_can(Permissions.VIEW_APPLICATION, message="view portfolio applications")
|
||||
def team(application_id):
|
||||
application = Applications.get(resource_id=application_id)
|
||||
return render_team_page(application)
|
||||
|
||||
environment_users = {}
|
||||
for member in application.members:
|
||||
user_id = member.user.id
|
||||
environment_users[user_id] = {
|
||||
"permissions": {
|
||||
"delete_access": permission_str(
|
||||
member, PermissionSets.DELETE_APPLICATION_ENVIRONMENTS
|
||||
),
|
||||
"environment_management": permission_str(
|
||||
member, PermissionSets.EDIT_APPLICATION_ENVIRONMENTS
|
||||
),
|
||||
"team_management": permission_str(
|
||||
member, PermissionSets.EDIT_APPLICATION_TEAM
|
||||
),
|
||||
},
|
||||
"environments": Environments.for_user(
|
||||
user=member.user, application=application
|
||||
),
|
||||
}
|
||||
|
||||
env_roles = [
|
||||
{"environment_id": e.id, "environment_name": e.name}
|
||||
for e in application.environments
|
||||
]
|
||||
member_form = NewMemberForm(data={"environment_roles": env_roles})
|
||||
@applications_bp.route("/application/<application_id>/team", methods=["POST"])
|
||||
@user_can(Permissions.EDIT_APPLICATION_MEMBER, message="update application member")
|
||||
def update_team(application_id):
|
||||
application = Applications.get(application_id)
|
||||
form = TeamForm(http_request.form)
|
||||
|
||||
return render_template(
|
||||
"portfolios/applications/team.html",
|
||||
application=application,
|
||||
environment_users=environment_users,
|
||||
member_form=member_form,
|
||||
)
|
||||
if form.validate():
|
||||
for member in form.members:
|
||||
app_role = ApplicationRoles.get(member.data["user_id"], application.id)
|
||||
new_perms = [
|
||||
perm
|
||||
for perm in member.data["permission_sets"]
|
||||
if perm != PermissionSets.VIEW_APPLICATION
|
||||
]
|
||||
ApplicationRoles.update_permission_sets(app_role, new_perms)
|
||||
flash("updated_application_members_permissions")
|
||||
|
||||
return redirect(
|
||||
url_for(
|
||||
"applications.team",
|
||||
application_id=application_id,
|
||||
fragment="application-members",
|
||||
_anchor="application-members",
|
||||
)
|
||||
)
|
||||
else:
|
||||
return (render_team_page(application), 400)
|
||||
|
||||
|
||||
@applications_bp.route("/application/<application_id>/members/new", methods=["POST"])
|
||||
|
@@ -173,6 +173,13 @@ MESSAGES = {
|
||||
""",
|
||||
"category": "success",
|
||||
},
|
||||
"updated_application_members_permissions": {
|
||||
"title_template": translate("flash.success"),
|
||||
"message_template": """
|
||||
<p>{{ "flash.updated_application_members_permissions" | translate }}</p>
|
||||
""",
|
||||
"category": "success",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user