Merge pull request #304 from dod-ccpo/assign-csp-roles
Assign and Update Environment Roles for Workspace Users
This commit is contained in:
commit
b7a33de29d
16
atst/domain/environment_roles.py
Normal file
16
atst/domain/environment_roles.py
Normal file
@ -0,0 +1,16 @@
|
||||
from atst.models.environment_role import EnvironmentRole
|
||||
from atst.database import db
|
||||
|
||||
|
||||
class EnvironmentRoles(object):
|
||||
@classmethod
|
||||
def get(cls, user_id, environment_id):
|
||||
existing_env_role = (
|
||||
db.session.query(EnvironmentRole)
|
||||
.filter(
|
||||
EnvironmentRole.user_id == user_id,
|
||||
EnvironmentRole.environment_id == environment_id,
|
||||
)
|
||||
.one_or_none()
|
||||
)
|
||||
return existing_env_role
|
@ -1,7 +1,14 @@
|
||||
from sqlalchemy.orm.exc import NoResultFound
|
||||
|
||||
from atst.database import db
|
||||
from atst.models.environment import Environment
|
||||
from atst.models.environment_role import EnvironmentRole, CSPRole
|
||||
from atst.models.environment_role import EnvironmentRole
|
||||
from atst.models.project import Project
|
||||
from atst.models.permissions import Permissions
|
||||
from atst.domain.authz import Authorization
|
||||
from atst.domain.environment_roles import EnvironmentRoles
|
||||
|
||||
from .exceptions import NotFoundError
|
||||
|
||||
|
||||
class Environments(object):
|
||||
@ -20,9 +27,9 @@ class Environments(object):
|
||||
db.session.commit()
|
||||
|
||||
@classmethod
|
||||
def add_member(cls, user, environment, member, role=CSPRole.NONSENSE_ROLE):
|
||||
def add_member(cls, environment, user, role):
|
||||
environment_user = EnvironmentRole(
|
||||
user=member, environment=environment, role=role.value
|
||||
user=user, environment=environment, role=role
|
||||
)
|
||||
db.session.add(environment_user)
|
||||
db.session.commit()
|
||||
@ -39,3 +46,35 @@ class Environments(object):
|
||||
.filter(Project.id == Environment.project_id)
|
||||
.all()
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get(cls, environment_id):
|
||||
try:
|
||||
env = db.session.query(Environment).filter_by(id=environment_id).one()
|
||||
except NoResultFound:
|
||||
raise NotFoundError("environment")
|
||||
|
||||
return env
|
||||
|
||||
@classmethod
|
||||
def update_environment_role(cls, user, ids_and_roles, workspace_user):
|
||||
Authorization.check_workspace_permission(
|
||||
user,
|
||||
workspace_user.workspace,
|
||||
Permissions.ADD_AND_ASSIGN_CSP_ROLES,
|
||||
"assign environment roles",
|
||||
)
|
||||
|
||||
for id_and_role in ids_and_roles:
|
||||
new_role = id_and_role["role"]
|
||||
environment = Environments.get(id_and_role["id"])
|
||||
env_role = EnvironmentRoles.get(workspace_user.user_id, id_and_role["id"])
|
||||
if env_role:
|
||||
env_role.role = new_role
|
||||
else:
|
||||
env_role = EnvironmentRole(
|
||||
user=workspace_user.user, environment=environment, role=new_role
|
||||
)
|
||||
db.session.add(env_role)
|
||||
|
||||
db.session.commit()
|
||||
|
@ -14,9 +14,6 @@ class Projects(object):
|
||||
project = Project(workspace=workspace, name=name, description=description)
|
||||
Environments.create_many(project, environment_names)
|
||||
|
||||
for environment in project.environments:
|
||||
Environments.add_member(user, environment, user)
|
||||
|
||||
db.session.add(project)
|
||||
db.session.commit()
|
||||
|
||||
@ -49,3 +46,21 @@ class Projects(object):
|
||||
.filter(EnvironmentRole.user_id == user.id)
|
||||
.all()
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_all(cls, user, workspace_user, workspace):
|
||||
Authorization.check_workspace_permission(
|
||||
user,
|
||||
workspace,
|
||||
Permissions.VIEW_APPLICATION_IN_WORKSPACE,
|
||||
"view project in workspace",
|
||||
)
|
||||
|
||||
try:
|
||||
projects = (
|
||||
db.session.query(Project).filter_by(workspace_id=workspace.id).all()
|
||||
)
|
||||
except NoResultFound:
|
||||
raise NotFoundError("projects")
|
||||
|
||||
return projects
|
||||
|
@ -1,13 +1,15 @@
|
||||
from flask_wtf import Form
|
||||
from wtforms.validators import Optional
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms.validators import Required
|
||||
|
||||
from atst.forms.fields import SelectField
|
||||
|
||||
from .data import WORKSPACE_ROLES
|
||||
|
||||
|
||||
class EditMemberForm(Form):
|
||||
class EditMemberForm(FlaskForm):
|
||||
# This form also accepts a field for each environment in each project
|
||||
# that the user is a member of
|
||||
|
||||
workspace_role = SelectField(
|
||||
"Workspace Role", choices=WORKSPACE_ROLES, validators=[Optional()]
|
||||
"Workspace Role", choices=WORKSPACE_ROLES, validators=[Required()]
|
||||
)
|
||||
|
@ -7,7 +7,7 @@ from atst.models import Base, types, mixins
|
||||
|
||||
|
||||
class CSPRole(Enum):
|
||||
NONSENSE_ROLE = "nonesense_role"
|
||||
NONSENSE_ROLE = "nonsense_role"
|
||||
|
||||
|
||||
class EnvironmentRole(Base, mixins.TimestampsMixin):
|
||||
|
@ -1,3 +1,4 @@
|
||||
import re
|
||||
from datetime import date, timedelta
|
||||
|
||||
from flask import (
|
||||
@ -14,10 +15,13 @@ from atst.domain.projects import Projects
|
||||
from atst.domain.reports import Reports
|
||||
from atst.domain.workspaces import Workspaces
|
||||
from atst.domain.workspace_users import WorkspaceUsers
|
||||
from atst.domain.environments import Environments
|
||||
from atst.domain.environment_roles import EnvironmentRoles
|
||||
from atst.forms.new_project import NewProjectForm
|
||||
from atst.forms.new_member import NewMemberForm
|
||||
from atst.forms.edit_member import EditMemberForm
|
||||
from atst.forms.workspace import WorkspaceForm
|
||||
from atst.forms.data import ENVIRONMENT_ROLES
|
||||
from atst.domain.authz import Authorization
|
||||
from atst.models.permissions import Permissions
|
||||
|
||||
@ -213,9 +217,16 @@ def view_member(workspace_id, member_id):
|
||||
"edit this workspace user",
|
||||
)
|
||||
member = WorkspaceUsers.get(workspace_id, member_id)
|
||||
projects = Projects.get_all(g.current_user, member, workspace)
|
||||
form = EditMemberForm(workspace_role=member.role)
|
||||
return render_template(
|
||||
"workspaces/members/edit.html", form=form, workspace=workspace, member=member
|
||||
"workspaces/members/edit.html",
|
||||
workspace=workspace,
|
||||
member=member,
|
||||
projects=projects,
|
||||
form=form,
|
||||
choices=ENVIRONMENT_ROLES,
|
||||
EnvironmentRoles=EnvironmentRoles,
|
||||
)
|
||||
|
||||
|
||||
@ -231,6 +242,16 @@ def update_member(workspace_id, member_id):
|
||||
"edit this workspace user",
|
||||
)
|
||||
member = WorkspaceUsers.get(workspace_id, member_id)
|
||||
|
||||
ids_and_roles = []
|
||||
form_dict = http_request.form.to_dict()
|
||||
for entry in form_dict:
|
||||
if re.match("env_", entry):
|
||||
env_id = entry[4:]
|
||||
env_role = form_dict[entry]
|
||||
if env_role:
|
||||
ids_and_roles.append({"id": env_id, "role": env_role})
|
||||
|
||||
form = EditMemberForm(http_request.form)
|
||||
|
||||
if form.validate():
|
||||
@ -241,6 +262,8 @@ def update_member(workspace_id, member_id):
|
||||
)
|
||||
new_role_name = member.role_displayname
|
||||
|
||||
Environments.update_environment_role(g.current_user, ids_and_roles, member)
|
||||
|
||||
return redirect(
|
||||
url_for(
|
||||
"workspaces.workspace_members",
|
||||
|
54
js/components/forms/edit_workspace_member.js
Normal file
54
js/components/forms/edit_workspace_member.js
Normal file
@ -0,0 +1,54 @@
|
||||
import FormMixin from '../../mixins/form'
|
||||
import textinput from '../text_input'
|
||||
import Selector from '../selector'
|
||||
import Modal from '../../mixins/modal'
|
||||
import toggler from '../toggler'
|
||||
|
||||
export default {
|
||||
name: 'edit-workspace-member',
|
||||
|
||||
mixins: [FormMixin, Modal],
|
||||
|
||||
components: {
|
||||
toggler,
|
||||
Modal,
|
||||
Selector,
|
||||
textinput
|
||||
},
|
||||
|
||||
props: {
|
||||
choices: Array,
|
||||
initialData: String,
|
||||
},
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
new_role: this.initialData,
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
change: function (e) {
|
||||
e.preventDefault()
|
||||
this.new_role = e.target.value
|
||||
},
|
||||
cancel: function () {
|
||||
this.new_role = this.initialData
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
displayName: function () {
|
||||
for (var arr in this.choices) {
|
||||
if (this.choices[arr][0] == this.new_role) {
|
||||
return this.choices[arr][1].name
|
||||
}
|
||||
}
|
||||
return this.new_role ? this.new_role : "no access"
|
||||
},
|
||||
label_class: function () {
|
||||
return this.displayName === "no access" ?
|
||||
"label" : "label label--success"
|
||||
},
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ import poc from './components/forms/poc'
|
||||
import financial from './components/forms/financial'
|
||||
import toggler from './components/toggler'
|
||||
import NewProject from './components/forms/new_project'
|
||||
import EditWorkspaceMember from './components/forms/edit_workspace_member'
|
||||
import Modal from './mixins/modal'
|
||||
import selector from './components/selector'
|
||||
import BudgetChart from './components/charts/budget_chart'
|
||||
@ -39,7 +40,8 @@ const app = new Vue({
|
||||
BudgetChart,
|
||||
SpendTable,
|
||||
CcpoApproval,
|
||||
LocalDatetime
|
||||
LocalDatetime,
|
||||
EditWorkspaceMember,
|
||||
},
|
||||
|
||||
mounted: function() {
|
||||
|
@ -1,23 +1,17 @@
|
||||
export default {
|
||||
methods: {
|
||||
closeModal: function(name) {
|
||||
this.modals[name] = false
|
||||
this.activeModal = null
|
||||
this.$emit('modalOpen', false)
|
||||
},
|
||||
openModal: function (name) {
|
||||
this.modals[name] = true
|
||||
this.activeModal = name
|
||||
this.$emit('modalOpen', true)
|
||||
}
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
modals: {
|
||||
styleguideModal: false,
|
||||
rolesModal: false,
|
||||
newProjectConfirmation: false,
|
||||
pendingFinancialVerification: false,
|
||||
pendingCCPOApproval: false,
|
||||
}
|
||||
activeModal: null,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ WORKSPACE_USERS = [
|
||||
"first_name": "Mario",
|
||||
"last_name": "Hudson",
|
||||
"email": "hudson@mil.gov",
|
||||
"workspace_role": "ccpo",
|
||||
"workspace_role": "billing_auditor",
|
||||
"dod_id": "0000000002",
|
||||
},
|
||||
{
|
||||
|
@ -1,7 +1,7 @@
|
||||
{% from "components/icon.html" import Icon %}
|
||||
|
||||
{% macro Modal(name, dismissable=False) -%}
|
||||
<template v-if='modals.{{name}} === true' v-cloak>
|
||||
<div v-show="activeModal === '{{name}}'" v-cloak>
|
||||
<div class='modal {% if dismissable %}modal--dismissable{% endif%}'>
|
||||
<div class='modal__container'>
|
||||
<div class='modal__dialog' role='dialog' aria-modal='true'>
|
||||
@ -18,5 +18,5 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
{%- endmacro %}
|
||||
|
@ -3,6 +3,7 @@
|
||||
{% from "components/icon.html" import Icon %}
|
||||
{% from "components/modal.html" import Modal %}
|
||||
{% from "components/selector.html" import Selector %}
|
||||
{% from "components/options_input.html" import OptionsInput %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
@ -49,173 +50,82 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% call Modal(name='rolesModal', dismissable=False) %}
|
||||
<div class="block-list">
|
||||
<header class="block-list__header">
|
||||
<div>
|
||||
<h2 class="block-list__title">
|
||||
Environment access for Danny Knight
|
||||
<div class='subtitle'>Project Name - Environment Name</div>
|
||||
</h2>
|
||||
<div class="block-list__description">
|
||||
<p>An environment role determines the permissions a member of the workspace assumes when using the JEDI Cloud.</p>
|
||||
<p>A member may have different environment roles across different projects. A member can only have one assigned environment role in a given environment.</p>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<form method="post" action="">
|
||||
<ul>
|
||||
<li class='block-list__item block-list__item--selectable'>
|
||||
<input type='radio' name='radio' id='radio-' />
|
||||
<label for='radio-'>
|
||||
<dl>
|
||||
<dt>Developer</dt>
|
||||
<dd>Configures cloud-based IaaS and PaaS computing, networking, and storage services.</dd>
|
||||
</dl>
|
||||
</label>
|
||||
</li>
|
||||
|
||||
<li class='block-list__item block-list__item--selectable'>
|
||||
<input type='radio' name='radio' id='radio-' />
|
||||
<label for='radio-'>
|
||||
<dl>
|
||||
<dt>Database Administrator</dt>
|
||||
<dd>Configures cloud-based database services.</dd>
|
||||
</dl>
|
||||
</label>
|
||||
</li>
|
||||
|
||||
<li class='block-list__item block-list__item--selectable'>
|
||||
<input type='radio' name='radio' id='radio-' />
|
||||
<label for='radio-'>
|
||||
<dl>
|
||||
<dt>DevOps</dt>
|
||||
<dd>Provisions, deprovisions, and deploys cloud-based IaaS and PaaS computing, networking, and storage services, including pre-configured machine images.</dd>
|
||||
</dl>
|
||||
</label>
|
||||
</li>
|
||||
|
||||
<li class='block-list__item block-list__item--selectable'>
|
||||
<input type='radio' name='radio' id='radio-' />
|
||||
<label for='radio-'>
|
||||
<dl>
|
||||
<dt>Billing Administrator</dt>
|
||||
<dd>Views cloud resource usage, budget reports, and invoices; tracks budgets, including spend reports, cost planning and projections, and sets limits based on cloud service usage.</dd>
|
||||
</dl>
|
||||
</label>
|
||||
</li>
|
||||
|
||||
<li class='block-list__item block-list__item--selectable'>
|
||||
<input type='radio' name='radio' id='radio-' />
|
||||
<label for='radio-'>
|
||||
<dl>
|
||||
<dt>Security Administrator</dt>
|
||||
<dd>Accesses information security and control tools of cloud resources which include viewing cloud resource usage logging, user roles and permissioning history.</dd>
|
||||
</dl>
|
||||
</label>
|
||||
</li>
|
||||
|
||||
<li class='block-list__item block-list__item--selectable'>
|
||||
<input type='radio' name='radio' id='radio-' />
|
||||
<label for='radio-'>
|
||||
<dl>
|
||||
<dt>Financial Auditor</dt>
|
||||
<dd>Views cloud resource usage and budget reports.</dd>
|
||||
</dl>
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class='block-list__footer'>
|
||||
<div class='action-group'>
|
||||
<a v-on:click="closeModal('rolesModal')" class='action-group__action usa-button'>Select Access Role</a>
|
||||
<a class='action-group__action icon-link icon-link--danger' v-on:click="closeModal('rolesModal')">No Access</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
{% endcall %}
|
||||
|
||||
{% for project in projects %}
|
||||
<div is='toggler' default-visible class='block-list project-list-item'>
|
||||
<template slot-scope='props'>
|
||||
<header class='block-list__header'>
|
||||
<button type='button' v-on:click='props.toggle' class='icon-link icon-link--large icon-link--default spend-table__project__toggler'>
|
||||
<button v-on:click='props.toggle' class='icon-link icon-link--large icon-link--default spend-table__project__toggler'>
|
||||
<template v-if='props.isVisible'>{{ Icon('caret_down') }}</template>
|
||||
<template v-else>{{ Icon('caret_right') }}</template>
|
||||
<h3 class="block-list__title">Code.mil</h3>
|
||||
<h3 class="block-list__title">{{ project.name }}</h3>
|
||||
</button>
|
||||
<span><a href="#" class="icon-link icon-link--danger">revoke all access</a></span>
|
||||
</header>
|
||||
<ul v-show='props.isVisible'>
|
||||
<li class='block-list__item project-list-item__environment'>
|
||||
<span class='project-list-item__environment'>
|
||||
Development
|
||||
</span>
|
||||
<div class='project-list-item__environment__actions'>
|
||||
<span class="label">no access </span><button v-on:click="openModal('rolesModal')" type="button" class="icon-link">set role</button>
|
||||
</div>
|
||||
</li>
|
||||
<li class='block-list__item project-list-item__environment'>
|
||||
<span class='project-list-item__environment'>
|
||||
Sandbox
|
||||
</span>
|
||||
<div class='project-list-item__environment__actions'>
|
||||
<span class="label">no access</span><button v-on:click="openModal('rolesModal')" type="button" class="icon-link">set role</button>
|
||||
</div>
|
||||
</li>
|
||||
<li class='block-list__item project-list-item__environment'>
|
||||
<span class='project-list-item__environment'>
|
||||
Production
|
||||
</span>
|
||||
<div class='project-list-item__environment__actions'>
|
||||
<span class="label label--success">Billing</span><button v-on:click="openModal('rolesModal')" type="button" class="icon-link">set role</button>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
</div>
|
||||
{% for env in project.environments %}
|
||||
|
||||
<div is="toggler" class='block-list project-list-item'>
|
||||
<template slot-scope='props'>
|
||||
<header class='block-list__header'>
|
||||
<button type='button' v-on:click='props.toggle' class='icon-link icon-link--large icon-link--default spend-table__project__toggler'>
|
||||
<template v-if='props.isVisible'>{{ Icon('caret_down') }}</template>
|
||||
<template v-else>{{ Icon('caret_right') }}</template>
|
||||
<h3 class="block-list__title">Digital Dojo</h3>
|
||||
</button>
|
||||
<span class="label">no access</span>
|
||||
</header>
|
||||
<ul v-show='props.isVisible'>
|
||||
<li class='block-list__item project-list-item__environment'>
|
||||
<span class='project-list-item__environment'>
|
||||
Development
|
||||
</span>
|
||||
<div class='project-list-item__environment__actions'>
|
||||
<span class="label">no access </span><button v-on:click="openModal('rolesModal')" type="button" class="icon-link">set role</button>
|
||||
</div>
|
||||
</li>
|
||||
<li class='block-list__item project-list-item__environment'>
|
||||
<span class='project-list-item__environment'>
|
||||
Sandbox
|
||||
</span>
|
||||
<div class='project-list-item__environment__actions'>
|
||||
<span class="label">no access</span><button v-on:click="openModal('rolesModal')" type="button" class="icon-link">set role</button>
|
||||
</div>
|
||||
</li>
|
||||
<li class='block-list__item project-list-item__environment'>
|
||||
<span class='project-list-item__environment'>
|
||||
Production
|
||||
</span>
|
||||
<div class='project-list-item__environment__actions'>
|
||||
<span class="label">no access</span><button v-on:click="openModal('rolesModal')" type="button" class="icon-link">set role</button>
|
||||
{% set role = EnvironmentRoles.get(member.user_id, env.id).role %}
|
||||
|
||||
<li class='block-list__item'>
|
||||
<edit-workspace-member inline-template initial-data='{{ role }}' v-bind:choices='{{ choices | tojson }}'>
|
||||
<div class='project-list-item__environment'>
|
||||
<span class='project-list-item__environment__link'>
|
||||
{{ env.name }}
|
||||
</span>
|
||||
|
||||
<div class='project-list-item__environment__actions'>
|
||||
<span v-bind:class="label_class" v-html:on=displayName></span>
|
||||
<button v-on:click="openModal('{{ env.name }}RolesModal')" type="button" class="icon-link">set role</button>
|
||||
{% call Modal(name=env.name + 'RolesModal', dismissable=False) %}
|
||||
<div class='block-list'>
|
||||
<ul>
|
||||
{% for choice in choices %}
|
||||
<li class='block-list__item block-list__item--selectable'>
|
||||
|
||||
{% if choice[0] != "" %}
|
||||
<input
|
||||
name='radio_input_{{ env.id }}'
|
||||
v-on:change='change'
|
||||
type='radio'
|
||||
id="env_{{ env.id }}_{{ choice[0] }}"
|
||||
value='{{ choice[0] }}'
|
||||
{% if role == choice[0] %}
|
||||
checked='checked'
|
||||
{% endif %}
|
||||
/>
|
||||
<label for="env_{{ env.id }}_{{ choice[0] }}">
|
||||
{% if choice[1].description %}
|
||||
<dl>
|
||||
<dt>{{ choice[1].name }}</dt>
|
||||
<dd>{{ choice[1].description }}</dd>
|
||||
</dl>
|
||||
{% else %}
|
||||
{{ choice[1].name }}
|
||||
{% endif %}
|
||||
</label>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<input type='hidden' name='env_{{ env.id }}' v-bind:value='new_role'/>
|
||||
<div class='block-list__footer'>
|
||||
<div class='action-group'>
|
||||
<a v-on:click="closeModal('{{ env.name }}RolesModal')" class='action-group__action usa-button'>Select Access Role</a>
|
||||
<a class='action-group__action icon-link icon-link--danger' v-on:click="closeModal('{{ env.name }}RolesModal'); cancel();" value="{{ value if value == role else role }}" >Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endcall %}
|
||||
</div>
|
||||
</div>
|
||||
</edit-workspace-member>
|
||||
</li>
|
||||
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</template>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class='action-group'>
|
||||
<button class='action-group__action usa-button usa-button-big'>
|
||||
@ -227,7 +137,7 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</form>
|
||||
|
||||
|
||||
|
||||
|
45
tests/domain/test_environments.py
Normal file
45
tests/domain/test_environments.py
Normal file
@ -0,0 +1,45 @@
|
||||
import pytest
|
||||
from uuid import uuid4
|
||||
|
||||
from atst.domain.environments import Environments
|
||||
from atst.domain.environment_roles import EnvironmentRoles
|
||||
from atst.domain.projects import Projects
|
||||
from atst.domain.workspaces import Workspaces
|
||||
from atst.domain.workspace_users import WorkspaceUsers
|
||||
from atst.domain.exceptions import NotFoundError
|
||||
|
||||
from tests.factories import RequestFactory, UserFactory
|
||||
|
||||
|
||||
def test_update_environment_roles():
|
||||
owner = UserFactory.create()
|
||||
developer_data = {
|
||||
"dod_id": "1234567890",
|
||||
"first_name": "Test",
|
||||
"last_name": "User",
|
||||
"email": "test.user@mail.com",
|
||||
"workspace_role": "developer",
|
||||
}
|
||||
|
||||
workspace = Workspaces.create(RequestFactory.create(creator=owner))
|
||||
workspace_user = Workspaces.create_member(owner, workspace, developer_data)
|
||||
project = Projects.create(
|
||||
owner, workspace, "my test project", "It's mine.", ["dev", "staging", "prod"]
|
||||
)
|
||||
|
||||
dev_env = project.environments[0]
|
||||
staging_env = project.environments[1]
|
||||
Environments.add_member(dev_env, workspace_user.user, "devops")
|
||||
Environments.add_member(staging_env, workspace_user.user, "developer")
|
||||
|
||||
new_ids_and_roles = [
|
||||
{"id": dev_env.id, "role": "billing_admin"},
|
||||
{"id": staging_env.id, "role": "developer"},
|
||||
]
|
||||
|
||||
Environments.update_environment_role(owner, new_ids_and_roles, workspace_user)
|
||||
new_dev_env_role = EnvironmentRoles.get(workspace_user.user.id, dev_env.id)
|
||||
staging_env_role = EnvironmentRoles.get(workspace_user.user.id, staging_env.id)
|
||||
|
||||
assert new_dev_env_role.role == "billing_admin"
|
||||
assert staging_env_role.role == "developer"
|
@ -169,7 +169,7 @@ def test_scoped_workspace_only_returns_a_users_projects_and_environments(
|
||||
)
|
||||
developer = UserFactory.from_atat_role("developer")
|
||||
dev_environment = Environments.add_member(
|
||||
workspace_owner, new_project.environments[0], developer
|
||||
new_project.environments[0], developer, "developer"
|
||||
)
|
||||
|
||||
scoped_workspace = Workspaces.get(developer, workspace.id)
|
||||
|
@ -14,5 +14,5 @@ def test_add_user_to_environment():
|
||||
)
|
||||
dev_environment = project.environments[0]
|
||||
|
||||
dev_environment = Environments.add_member(owner, dev_environment, developer)
|
||||
dev_environment = Environments.add_member(dev_environment, developer, "developer")
|
||||
assert developer in dev_environment.users
|
||||
|
@ -36,7 +36,7 @@ def test_has_environment_roles():
|
||||
project = Projects.create(
|
||||
owner, workspace, "my test project", "It's mine.", ["dev", "staging", "prod"]
|
||||
)
|
||||
Environments.add_member(owner, project.environments[0], workspace_user.user)
|
||||
Environments.add_member(project.environments[0], workspace_user.user, "developer")
|
||||
assert workspace_user.has_environment_roles
|
||||
|
||||
|
||||
|
@ -2,6 +2,10 @@ from flask import url_for
|
||||
|
||||
from tests.factories import UserFactory, WorkspaceFactory
|
||||
from atst.domain.workspaces import Workspaces
|
||||
from atst.domain.workspace_users import WorkspaceUsers
|
||||
from atst.domain.projects import Projects
|
||||
from atst.domain.environments import Environments
|
||||
from atst.domain.environment_roles import EnvironmentRoles
|
||||
from atst.models.workspace_user import WorkspaceUser
|
||||
|
||||
|
||||
@ -67,3 +71,56 @@ def test_update_workspace_name(client, user_session):
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert workspace.name == "a cool new name"
|
||||
|
||||
|
||||
def test_update_member_workspace_role(client, user_session):
|
||||
owner = UserFactory.create()
|
||||
workspace = WorkspaceFactory.create()
|
||||
Workspaces._create_workspace_role(owner, workspace, "admin")
|
||||
user = UserFactory.create()
|
||||
member = WorkspaceUsers.add(user, workspace.id, "developer")
|
||||
user_session(owner)
|
||||
response = client.post(
|
||||
url_for(
|
||||
"workspaces.update_member", workspace_id=workspace.id, member_id=user.id
|
||||
),
|
||||
data={"workspace_role": "security_auditor"},
|
||||
follow_redirects=True,
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert member.role == "security_auditor"
|
||||
|
||||
|
||||
def test_update_member_environment_role(client, user_session):
|
||||
owner = UserFactory.create()
|
||||
workspace = WorkspaceFactory.create()
|
||||
Workspaces._create_workspace_role(owner, workspace, "admin")
|
||||
|
||||
user = UserFactory.create()
|
||||
member = WorkspaceUsers.add(user, workspace.id, "developer")
|
||||
project = Projects.create(
|
||||
owner,
|
||||
workspace,
|
||||
"Snazzy Project",
|
||||
"A new project for me and my friends",
|
||||
{"env1", "env2"},
|
||||
)
|
||||
env1_id = project.environments[0].id
|
||||
env2_id = project.environments[1].id
|
||||
for env in project.environments:
|
||||
Environments.add_member(env, user, "developer")
|
||||
user_session(owner)
|
||||
response = client.post(
|
||||
url_for(
|
||||
"workspaces.update_member", workspace_id=workspace.id, member_id=user.id
|
||||
),
|
||||
data={
|
||||
"workspace_role": "developer",
|
||||
"env_" + str(env1_id): "security_auditor",
|
||||
"env_" + str(env2_id): "devops",
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert EnvironmentRoles.get(user.id, env1_id).role == "security_auditor"
|
||||
assert EnvironmentRoles.get(user.id, env2_id).role == "devops"
|
||||
|
Loading…
x
Reference in New Issue
Block a user