Merge pull request #252 from dod-ccpo/view-member-list-workspace-owner
View member list as workspace owner
This commit is contained in:
commit
a96af2d095
@ -0,0 +1,53 @@
|
||||
"""add view_workspace_members_permission
|
||||
|
||||
Revision ID: ad30159ef19b
|
||||
Revises: 2c2a2af465d3
|
||||
Create Date: 2018-09-05 11:17:17.204089
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
from atst.models.role import Role
|
||||
from atst.models.permissions import Permissions
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'ad30159ef19b'
|
||||
down_revision = 'c1d074288e99'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
def upgrade():
|
||||
|
||||
session = Session(bind=op.get_bind())
|
||||
|
||||
all_roles_but_default = session.query(Role).filter(Role.name != "default").all()
|
||||
for role in all_roles_but_default:
|
||||
role.add_permission(Permissions.VIEW_WORKSPACE)
|
||||
session.add(role)
|
||||
|
||||
owner_and_ccpo = session.query(Role).filter(Role.name.in_(["owner", "ccpo", "admin"])).all()
|
||||
for role in owner_and_ccpo:
|
||||
role.add_permission(Permissions.VIEW_WORKSPACE_MEMBERS)
|
||||
session.add(role)
|
||||
|
||||
session.flush()
|
||||
session.commit()
|
||||
|
||||
|
||||
def downgrade():
|
||||
session = Session(bind=op.get_bind())
|
||||
|
||||
all_roles_but_default = session.query(Role).filter(Role.name != "default").all()
|
||||
for role in all_roles_but_default:
|
||||
role.remove_permission(Permissions.VIEW_WORKSPACE)
|
||||
session.add(role)
|
||||
|
||||
owner_and_ccpo = session.query(Role).filter(Role.name.in_(["owner", "ccpo"])).all()
|
||||
for role in owner_and_ccpo:
|
||||
role.remove_permission(Permissions.VIEW_WORKSPACE_MEMBERS)
|
||||
session.add(role)
|
||||
|
||||
session.flush()
|
||||
session.commit()
|
@ -3,7 +3,7 @@ from sqlalchemy.orm.exc import NoResultFound
|
||||
from atst.database import db
|
||||
from atst.models.workspace import Workspace
|
||||
from atst.models.workspace_role import WorkspaceRole
|
||||
from atst.domain.exceptions import NotFoundError, UnauthorizedError
|
||||
from atst.domain.exceptions import NotFoundError
|
||||
from atst.domain.roles import Roles
|
||||
from atst.domain.authz import Authorization
|
||||
from atst.models.permissions import Permissions
|
||||
@ -25,19 +25,16 @@ class Workspaces(object):
|
||||
|
||||
@classmethod
|
||||
def get(cls, user, workspace_id):
|
||||
try:
|
||||
workspace = db.session.query(Workspace).filter_by(id=workspace_id).one()
|
||||
except NoResultFound:
|
||||
raise NotFoundError("workspace")
|
||||
|
||||
if not Authorization.is_in_workspace(user, workspace):
|
||||
raise UnauthorizedError(user, "get workspace")
|
||||
workspace = Workspaces._get(workspace_id)
|
||||
Authorization.check_workspace_permission(
|
||||
user, workspace, Permissions.VIEW_WORKSPACE, "get workspace"
|
||||
)
|
||||
|
||||
return workspace
|
||||
|
||||
@classmethod
|
||||
def get_for_update(cls, user, workspace_id):
|
||||
workspace = Workspaces.get(user, workspace_id)
|
||||
workspace = Workspaces._get(workspace_id)
|
||||
Authorization.check_workspace_permission(
|
||||
user, workspace, Permissions.ADD_APPLICATION_IN_WORKSPACE, "add project"
|
||||
)
|
||||
@ -53,6 +50,18 @@ class Workspaces(object):
|
||||
|
||||
return workspace
|
||||
|
||||
@classmethod
|
||||
def get_with_members(cls, user, workspace_id):
|
||||
workspace = Workspaces._get(workspace_id)
|
||||
Authorization.check_workspace_permission(
|
||||
user,
|
||||
workspace,
|
||||
Permissions.VIEW_WORKSPACE_MEMBERS,
|
||||
"view workspace members",
|
||||
)
|
||||
|
||||
return workspace
|
||||
|
||||
@classmethod
|
||||
def get_many(cls, user):
|
||||
workspaces = (
|
||||
@ -100,3 +109,12 @@ class Workspaces(object):
|
||||
workspace_role = WorkspaceRole(user=user, role=role, workspace=workspace)
|
||||
db.session.add(workspace_role)
|
||||
return workspace_role
|
||||
|
||||
@classmethod
|
||||
def _get(cls, workspace_id):
|
||||
try:
|
||||
workspace = db.session.query(Workspace).filter_by(id=workspace_id).one()
|
||||
except NoResultFound:
|
||||
raise NotFoundError("workspace")
|
||||
|
||||
return workspace
|
||||
|
@ -23,6 +23,8 @@ class Permissions(object):
|
||||
DEACTIVATE_WORKSPACE = "deactivate_workspace"
|
||||
VIEW_ATAT_PERMISSIONS = "view_atat_permissions"
|
||||
TRANSFER_OWNERSHIP_OF_WORKSPACE = "transfer_ownership_of_workspace"
|
||||
VIEW_WORKSPACE_MEMBERS = "view_workspace_members"
|
||||
VIEW_WORKSPACE = "view_workspace"
|
||||
|
||||
ADD_APPLICATION_IN_WORKSPACE = "add_application_in_workspace"
|
||||
DELETE_APPLICATION_IN_WORKSPACE = "delete_application_in_workspace"
|
||||
|
@ -1,5 +1,6 @@
|
||||
from sqlalchemy import String, Column
|
||||
from sqlalchemy.dialects.postgresql import ARRAY
|
||||
from sqlalchemy.orm.attributes import flag_modified
|
||||
|
||||
from atst.models import Base
|
||||
from .types import Id
|
||||
@ -12,3 +13,15 @@ class Role(Base):
|
||||
name = Column(String, index=True, unique=True)
|
||||
description = Column(String)
|
||||
permissions = Column(ARRAY(String), index=True, server_default="{}")
|
||||
|
||||
def add_permission(self, permission):
|
||||
perms_set = set(self.permissions)
|
||||
perms_set.add(permission)
|
||||
self.permissions = list(perms_set)
|
||||
flag_modified(self, "permissions")
|
||||
|
||||
def remove_permission(self, permission):
|
||||
perms_set = set(self.permissions)
|
||||
perms_set.discard(permission)
|
||||
self.permissions = list(perms_set)
|
||||
flag_modified(self, "permissions")
|
||||
|
@ -4,8 +4,8 @@ from sqlalchemy.orm import relationship
|
||||
from atst.models import Base
|
||||
from atst.models.types import Id
|
||||
from atst.models.mixins import TimestampsMixin
|
||||
from atst.utils import first_or_none
|
||||
from atst.models.workspace_user import WorkspaceUser
|
||||
from atst.utils import first_or_none
|
||||
|
||||
|
||||
class Workspace(Base, TimestampsMixin):
|
||||
|
@ -38,7 +38,7 @@ class WorkspaceUser(object):
|
||||
|
||||
@property
|
||||
def status(self):
|
||||
return "radical"
|
||||
return "active"
|
||||
|
||||
@property
|
||||
def has_environment_roles(self):
|
||||
|
@ -63,7 +63,7 @@ def show_workspace(workspace_id):
|
||||
|
||||
@bp.route("/workspaces/<workspace_id>/members")
|
||||
def workspace_members(workspace_id):
|
||||
workspace = Workspaces.get(g.current_user, workspace_id)
|
||||
workspace = Workspaces.get_with_members(g.current_user, workspace_id)
|
||||
return render_template("workspaces/members/index.html", workspace=workspace)
|
||||
|
||||
|
||||
|
@ -15,6 +15,29 @@ from atst.domain.exceptions import AlreadyExistsError
|
||||
from tests.factories import RequestFactory
|
||||
from atst.routes.dev import _DEV_USERS as DEV_USERS
|
||||
|
||||
WORKSPACE_USERS = [
|
||||
{
|
||||
"first_name": "Danny",
|
||||
"last_name": "Knight",
|
||||
"email": "knight@mil.gov",
|
||||
"workspace_role": "developer",
|
||||
"dod_id": "0000000001"
|
||||
},
|
||||
{
|
||||
"first_name": "Mario",
|
||||
"last_name": "Hudson",
|
||||
"email": "hudson@mil.gov",
|
||||
"workspace_role": "ccpo",
|
||||
"dod_id": "0000000002"
|
||||
},
|
||||
{
|
||||
"first_name": "Louise",
|
||||
"last_name": "Greer",
|
||||
"email": "greer@mil.gov",
|
||||
"workspace_role": "admin",
|
||||
"dod_id": "0000000003"
|
||||
},
|
||||
]
|
||||
|
||||
def seed_db():
|
||||
users = []
|
||||
@ -41,6 +64,9 @@ def seed_db():
|
||||
requests.append(request)
|
||||
|
||||
workspace = Workspaces.create(requests[0], name="{}'s workspace".format(user.first_name))
|
||||
for workspace_user in WORKSPACE_USERS:
|
||||
Workspaces.create_member(user, workspace, workspace_user)
|
||||
|
||||
Projects.create(
|
||||
workspace=workspace,
|
||||
name="First Project",
|
||||
|
@ -155,3 +155,27 @@ def test_need_permission_to_update_workspace_user_role():
|
||||
|
||||
with pytest.raises(UnauthorizedError):
|
||||
Workspaces.update_member(random_user, workspace, member, role_name)
|
||||
|
||||
|
||||
def test_owner_can_view_workspace_members():
|
||||
owner = UserFactory.create()
|
||||
workspace = Workspaces.create(RequestFactory.create(creator=owner))
|
||||
workspace = Workspaces.get_with_members(owner, workspace.id)
|
||||
|
||||
assert workspace
|
||||
|
||||
|
||||
def test_ccpo_can_view_workspace_members():
|
||||
workspace = Workspaces.create(RequestFactory.create(creator=UserFactory.create()))
|
||||
ccpo = UserFactory.from_atat_role("ccpo")
|
||||
workspace = Workspaces.get_with_members(ccpo, workspace.id)
|
||||
|
||||
assert workspace
|
||||
|
||||
|
||||
def test_random_user_cannot_view_workspace_members():
|
||||
workspace = Workspaces.create(RequestFactory.create(creator=UserFactory.create()))
|
||||
developer = UserFactory.from_atat_role("developer")
|
||||
|
||||
with pytest.raises(UnauthorizedError):
|
||||
workspace = Workspaces.get_with_members(developer, workspace.id)
|
||||
|
Loading…
x
Reference in New Issue
Block a user