Rewrite function that builds form data for app environment roles form.

- Adds a property to ApplicationRole model so that it knows its related
  EnvironmentRole models.
- Rewrite the form data builder in the routes file so that it loops the
  application members and their environment roles to build the data
  structure.
This commit is contained in:
dandds 2019-05-23 15:58:54 -04:00
parent 7f745302ec
commit 129f5e3031
5 changed files with 76 additions and 87 deletions

View File

@ -113,15 +113,6 @@ class Environments(object):
environment=environment, user=member, new_role=new_role environment=environment, user=member, new_role=new_role
) )
@classmethod
def get_members_by_role(cls, env, role):
return (
db.session.query(EnvironmentRole)
.filter(EnvironmentRole.environment_id == env.id)
.filter(EnvironmentRole.role == role)
.all()
)
@classmethod @classmethod
def revoke_access(cls, environment, target_user): def revoke_access(cls, environment, target_user):
EnvironmentRoles.delete(environment.id, target_user.id) EnvironmentRoles.delete(environment.id, target_user.id)

View File

@ -1,12 +1,14 @@
from enum import Enum from enum import Enum
from sqlalchemy import Index, ForeignKey, Column, Enum as SQLAEnum, Table from sqlalchemy import Index, ForeignKey, Column, Enum as SQLAEnum, Table
from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship from sqlalchemy.orm import object_session, relationship
from sqlalchemy.event import listen from sqlalchemy.event import listen
from atst.utils import first_or_none from atst.utils import first_or_none
from atst.models import Base, mixins from atst.models import Base, mixins
from atst.models.mixins.auditable import record_permission_sets_updates from atst.models.mixins.auditable import record_permission_sets_updates
from atst.models.environment import Environment
from atst.models.environment_role import EnvironmentRole
from .types import Id from .types import Id
@ -91,6 +93,22 @@ class ApplicationRole(
"portfolio": self.application.portfolio.name, "portfolio": self.application.portfolio.name,
} }
@property
def environment_roles(self):
if getattr(self, "_environment_roles", None) is None:
roles = (
object_session(self)
.query(EnvironmentRole)
.join(Environment, Environment.application_id == self.application_id)
.filter(EnvironmentRole.environment_id == Environment.id)
.filter(EnvironmentRole.user_id == self.user_id)
.all()
)
setattr(self, "_environment_roles", roles)
return self._environment_roles
Index( Index(
"application_role_user_application", "application_role_user_application",

View File

@ -30,54 +30,54 @@ def get_environments_obj_for_app(application):
return environments_obj return environments_obj
def serialize_members(member_list, role):
serialized_list = []
for member in member_list:
serialized_list.append(
{
"user_id": str(member.user_id),
"user_name": member.user.full_name,
"role_name": role,
}
)
return serialized_list
def sort_env_users_by_role(env):
users_list = []
no_access_users = env.application.users - env.users
no_access_list = [
{"user_id": str(user.id), "user_name": user.full_name, "role_name": NO_ACCESS}
for user in no_access_users
]
users_list.append({"role": NO_ACCESS, "members": no_access_list})
for role in CSPRole:
users_list.append(
{
"role": role.value,
"members": serialize_members(
Environments.get_members_by_role(env, role.value), role.value
),
}
)
return users_list
def data_for_app_env_roles_form(application): def data_for_app_env_roles_form(application):
data = {"envs": []} csp_roles = [role.value for role in CSPRole]
for environment in application.environments: csp_roles.insert(0, NO_ACCESS)
data["envs"].append( # dictionary for sorting application members by environments
{ # and roles within those environments
"env_id": environment.id, environments_dict = {
"team_roles": sort_env_users_by_role(environment), e.id: {role_name: [] for role_name in csp_roles}
} for e in application.environments
) }
for member in application.members:
env_ids = set(environments_dict.keys())
for env_role in member.environment_roles:
role_members_list = environments_dict[env_role.environment_id][
env_role.role
]
role_members_list.append(
{
"user_id": str(member.user.id),
"user_name": member.user_name,
"role_name": env_role.role,
}
)
env_ids.remove(env_role.environment_id)
return data # any leftover environment IDs are ones the app member
# does not have access to
for env_id in env_ids:
role_members_list = environments_dict[env_id][NO_ACCESS]
role_members_list.append(
{
"user_id": str(member.user.id),
"user_name": member.user_name,
"role_name": NO_ACCESS,
}
)
# transform the data into the shape the form needs
nested_data = [
{
"env_id": env_id,
"team_roles": [
{"role": role, "members": members} for role, members in roles.items()
],
}
for env_id, roles in environments_dict.items()
]
return {"envs": nested_data}
def check_users_are_in_application(user_ids, application): def check_users_are_in_application(user_ids, application):

View File

@ -136,36 +136,6 @@ def test_update_env_roles_by_member():
assert not EnvironmentRoles.get(user.id, testing.id) assert not EnvironmentRoles.get(user.id, testing.id)
def test_get_members_by_role(db):
environment = EnvironmentFactory.create()
env_role_1 = EnvironmentRoleFactory.create(
environment=environment, role=CSPRole.BASIC_ACCESS.value
)
env_role_2 = EnvironmentRoleFactory.create(
environment=environment, role=CSPRole.TECHNICAL_READ.value
)
env_role_3 = EnvironmentRoleFactory.create(
environment=environment, role=CSPRole.TECHNICAL_READ.value
)
rando_env = EnvironmentFactory.create()
rando_env_role = EnvironmentRoleFactory.create(
environment=rando_env, role=CSPRole.BASIC_ACCESS.value
)
basic_access_members = Environments.get_members_by_role(
environment, CSPRole.BASIC_ACCESS.value
)
technical_read_members = Environments.get_members_by_role(
environment, CSPRole.TECHNICAL_READ.value
)
assert basic_access_members == [env_role_1]
assert rando_env_role not in basic_access_members
assert technical_read_members == [env_role_2, env_role_3]
assert (
Environments.get_members_by_role(environment, CSPRole.BUSINESS_READ.value) == []
)
def test_get_scoped_environments(db): def test_get_scoped_environments(db):
developer = UserFactory.create() developer = UserFactory.create()
portfolio = PortfolioFactory.create( portfolio = PortfolioFactory.create(

View File

@ -1,7 +1,7 @@
from atst.domain.permission_sets import PermissionSets from atst.domain.permission_sets import PermissionSets
from atst.models.audit_event import AuditEvent from atst.models.audit_event import AuditEvent
from tests.factories import PortfolioFactory, UserFactory from tests.factories import *
def test_has_application_role_history(session): def test_has_application_role_history(session):
@ -38,3 +38,13 @@ def test_has_application_role_history(session):
old_state, new_state = changed_event.changed_state["permission_sets"] old_state, new_state = changed_event.changed_state["permission_sets"]
assert old_state == [PermissionSets.VIEW_APPLICATION] assert old_state == [PermissionSets.VIEW_APPLICATION]
assert new_state == [PermissionSets.EDIT_APPLICATION_TEAM] assert new_state == [PermissionSets.EDIT_APPLICATION_TEAM]
def test_environment_roles():
application = ApplicationFactory.create()
environment = EnvironmentFactory.create(application=application)
user = UserFactory.create()
application_role = ApplicationRoleFactory.create(application=application, user=user)
environment_role = EnvironmentRoleFactory.create(environment=environment, user=user)
assert application_role.environment_roles == [environment_role]