WIP: use team form for application team page

This commit is contained in:
dandds 2019-05-01 15:30:42 -04:00 committed by Montana
parent 926f89d975
commit 0da0f6a0ae
8 changed files with 134 additions and 61 deletions

View File

@ -1,7 +1,7 @@
from flask import current_app as app from flask import current_app as app
from atst.database import db from atst.database import db
from atst.models import EnvironmentRole from atst.models import EnvironmentRole, Application, Environment
class EnvironmentRoles(object): class EnvironmentRoles(object):
@ -35,3 +35,15 @@ class EnvironmentRoles(object):
return True return True
else: else:
return False 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()
)

View File

@ -1,5 +1,5 @@
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms.fields import FormField, FieldList, HiddenField from wtforms.fields import FormField, FieldList, HiddenField, StringField
from .application_member import EnvironmentForm from .application_member import EnvironmentForm
from .forms import BaseForm from .forms import BaseForm
@ -43,6 +43,7 @@ class PermissionsForm(FlaskForm):
class MemberForm(FlaskForm): class MemberForm(FlaskForm):
user_id = HiddenField() user_id = HiddenField()
user_name = StringField()
environment_roles = FieldList(FormField(EnvironmentForm)) environment_roles = FieldList(FormField(EnvironmentForm))
permission_sets = FormField(PermissionsForm) permission_sets = FormField(PermissionsForm)

View File

@ -28,6 +28,7 @@ class Application(
back_populates="application", back_populates="application",
primaryjoin="and_(Environment.application_id==Application.id, Environment.deleted==False)", primaryjoin="and_(Environment.application_id==Application.id, Environment.deleted==False)",
) )
# TODO: filter condition on this relationship?
roles = relationship("ApplicationRole") roles = relationship("ApplicationRole")
@property @property

View File

@ -2,12 +2,14 @@ from flask import render_template, request as http_request, g, url_for, redirect
from . import applications_bp from . import applications_bp
from atst.domain.environments import Environments
from atst.domain.applications import Applications from atst.domain.applications import Applications
from atst.domain.environments import Environments
from atst.domain.environment_roles import EnvironmentRoles
from atst.domain.authz.decorator import user_can_access_decorator as user_can from atst.domain.authz.decorator import user_can_access_decorator as user_can
from atst.domain.permission_sets import PermissionSets from atst.domain.permission_sets import PermissionSets
from atst.domain.exceptions import AlreadyExistsError from atst.domain.exceptions import AlreadyExistsError
from atst.forms.application_member import NewForm as NewMemberForm from atst.forms.application_member import NewForm as NewMemberForm
from atst.forms.team import TeamForm
from atst.models import Permissions from atst.models import Permissions
from atst.services.invitation import Invitation as InvitationService from atst.services.invitation import Invitation as InvitationService
from atst.utils.flash import formatted_flash as flash from atst.utils.flash import formatted_flash as flash
@ -27,8 +29,10 @@ def team(application_id):
application = Applications.get(resource_id=application_id) application = Applications.get(resource_id=application_id)
environment_users = {} environment_users = {}
team_data = []
for member in application.members: for member in application.members:
user_id = member.user.id user_id = member.user.id
user_name = member.user.full_name
environment_users[user_id] = { environment_users[user_id] = {
"permissions": { "permissions": {
"delete_access": permission_str( "delete_access": permission_str(
@ -45,18 +49,51 @@ def team(application_id):
user=member.user, application=application user=member.user, application=application
), ),
} }
permission_sets = {
"perms_env_mgmt": PermissionSets.EDIT_APPLICATION_ENVIRONMENTS
if member.has_permission_set(PermissionSets.EDIT_APPLICATION_ENVIRONMENTS)
else "",
"perms_team_mgmt": PermissionSets.EDIT_APPLICATION_TEAM
if member.has_permission_set(PermissionSets.EDIT_APPLICATION_TEAM)
else "",
"perms_del_env": PermissionSets.DELETE_APPLICATION_ENVIRONMENTS
if member.has_permission_set(PermissionSets.DELETE_APPLICATION_ENVIRONMENTS)
else "",
}
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,
}
)
team_form = TeamForm(data={"members": team_data})
env_roles = [ env_roles = [
{"environment_id": e.id, "environment_name": e.name} {"environment_id": e.id, "environment_name": e.name}
for e in application.environments for e in application.environments
] ]
member_form = NewMemberForm(data={"environment_roles": env_roles}) new_member_form = NewMemberForm(data={"environment_roles": env_roles})
return render_template( return render_template(
"portfolios/applications/team.html", "portfolios/applications/team.html",
application=application, application=application,
environment_users=environment_users, environment_users=environment_users,
member_form=member_form, team_form=team_form,
new_member_form=new_member_form,
) )

View File

@ -9,23 +9,23 @@
</div> </div>
<div class='form-row'> <div class='form-row'>
<div class='form-col form-col--half'> <div class='form-col form-col--half'>
{{ TextInput(member_form.user_data.first_name, validation='requiredField') }} {{ TextInput(new_member_form.user_data.first_name, validation='requiredField') }}
</div> </div>
<div class='form-col form-col--half'> <div class='form-col form-col--half'>
{{ TextInput(member_form.user_data.last_name, validation='requiredField') }} {{ TextInput(new_member_form.user_data.last_name, validation='requiredField') }}
</div> </div>
</div> </div>
<div class='form-row'> <div class='form-row'>
<div class='form-col form-col--half'> <div class='form-col form-col--half'>
{{ TextInput(member_form.user_data.email, validation='email') }} {{ TextInput(new_member_form.user_data.email, validation='email') }}
</div> </div>
<div class='form-col form-col--half'> <div class='form-col form-col--half'>
{{ TextInput(member_form.user_data.phone_number, validation='usPhone', optional=True) }} {{ TextInput(new_member_form.user_data.phone_number, validation='usPhone', optional=True) }}
</div> </div>
</div> </div>
<div class='form-row'> <div class='form-row'>
<div class='form-col form-col--half'> <div class='form-col form-col--half'>
{{ TextInput(member_form.user_data.dod_id, validation='dodId') }} {{ TextInput(new_member_form.user_data.dod_id, validation='dodId') }}
</div> </div>
<div class='form-col form-col--half'> <div class='form-col form-col--half'>
</div> </div>
@ -61,7 +61,7 @@
</span> </span>
</div> </div>
</div> </div>
{% for environment_data in member_form.environment_roles %} {% for environment_data in new_member_form.environment_roles %}
<optionsinput inline-template <optionsinput inline-template
v-bind:initial-value="'{{ environment_data.role.data | string }}'" v-bind:initial-value="'{{ environment_data.role.data | string }}'"
> >
@ -86,9 +86,9 @@
{% endfor %} {% endfor %}
</div> </div>
<h1>{{ "portfolios.applications.members.new.manage_perms" | translate({"application_name": application.name}) }}</h1> <h1>{{ "portfolios.applications.members.new.manage_perms" | translate({"application_name": application.name}) }}</h1>
{{ CheckboxInput(member_form.permission_sets.perms_team_mgmt, classes="input__inline-fields") }} {{ CheckboxInput(new_member_form.permission_sets.perms_team_mgmt, classes="input__inline-fields") }}
{% call CheckboxInput(member_form.permission_sets.perms_env_mgmt, classes="input__inline-fields") %} {% call CheckboxInput(new_member_form.permission_sets.perms_env_mgmt, classes="input__inline-fields") %}
{% set field=member_form.permission_sets.perms_del_env %} {% set field=new_member_form.permission_sets.perms_del_env %}
<nestedcheckboxinput <nestedcheckboxinput
name='{{ field.name }}' name='{{ field.name }}'
inline-template inline-template
@ -128,7 +128,7 @@
{% endset %} {% endset %}
{{ MultiStepModalForm( {{ MultiStepModalForm(
'add-app-mem', 'add-app-mem',
member_form, new_member_form,
url_for("applications.create_member", application_id=application.id), url_for("applications.create_member", application_id=application.id),
[step_one, step_two], [step_one, step_two],
button_text=("portfolios.admin.add_new_member" | translate), button_text=("portfolios.admin.add_new_member" | translate),

View File

@ -0,0 +1,46 @@
{% for member in application.members %}
{% set user = member.user %}
{% set user_info = environment_users[user.id] %}
{% set user_permissions = user_info["permissions"] %}
{% macro PermissionField(value) %}
<div class="col col--grow user-permission{% if "Edit" in value %} green{% endif %}">{{ value }}</div>
{% endmacro %}
<toggler inline-template>
<li class="accordion-table__item">
<div class="accordion-table__item-content row">
<div class="col col--grow">{{ user.full_name }}</div>
{{ PermissionField(user_permissions["delete_access"]) }}
{{ PermissionField(user_permissions["environment_management"]) }}
{{ PermissionField(user_permissions["team_management"]) }}
<div class="col col--grow icon-link icon-link--large accordion-table__item__toggler">
{% set open_html %}
{{ "portfolios.applications.team_settings.environments" | translate }} ({{ user_info['environments'] | length }}) {{ Icon('caret_down') }}
{% endset %}
{% set close_html %}
{{ "portfolios.applications.team_settings.environments" | translate }} ({{ user_info['environments'] | length }}) {{ Icon('caret_up') }}
{% endset %}
{{
ToggleButton(
open_html=open_html,
close_html=close_html,
section_name="environments"
)
}}
</div>
</div>
{% call ToggleSection(section_name="environments") %}
<ul>
{% for environment in user_info["environments"] %}
<li class="accordion-table__item__expanded">
{{ environment.name }}
</li>
{% endfor %}
</ul>
{% endcall %}
</li>
</toggler>
{% endfor %}

View File

@ -61,52 +61,12 @@
</div> </div>
</div> </div>
<ul class="accordion-table__items"> <ul class="accordion-table__items">
{% for member in application.members %} {% if user_can(permissions.EDIT_APPLICATION_MEMBER) %}
{% set user = member.user %} {# edit version goes here #}
{% set user_info = environment_users[user.id] %} {% include "fragments/applications/read_only_team.html" %}
{% set user_permissions = user_info["permissions"] %} {% elif user_can(permissions.VIEW_APPLICATION_MEMBER) %}
{% include "fragments/applications/read_only_team.html" %}
{% macro PermissionField(value) %} {% endif %}
<div class="col col--grow user-permission{% if "Edit" in value %} green{% endif %}">{{ value }}</div>
{% endmacro %}
<toggler inline-template>
<li class="accordion-table__item">
<div class="accordion-table__item-content row">
<div class="col col--grow">{{ user.full_name }}</div>
{{ PermissionField(user_permissions["delete_access"]) }}
{{ PermissionField(user_permissions["environment_management"]) }}
{{ PermissionField(user_permissions["team_management"]) }}
<div class="col col--grow icon-link icon-link--large accordion-table__item__toggler">
{% set open_html %}
{{ "portfolios.applications.team_settings.environments" | translate }} ({{ user_info['environments'] | length }}) {{ Icon('caret_down') }}
{% endset %}
{% set close_html %}
{{ "portfolios.applications.team_settings.environments" | translate }} ({{ user_info['environments'] | length }}) {{ Icon('caret_up') }}
{% endset %}
{{
ToggleButton(
open_html=open_html,
close_html=close_html,
section_name="environments"
)
}}
</div>
</div>
{% call ToggleSection(section_name="environments") %}
<ul>
{% for environment in user_info["environments"] %}
<li class="accordion-table__item__expanded">
{{ environment.name }}
</li>
{% endfor %}
</ul>
{% endcall %}
</li>
</toggler>
{% endfor %}
</ul> </ul>
</div> </div>

View File

@ -0,0 +1,16 @@
from atst.domain.environment_roles import EnvironmentRoles
from tests.factories import *
def test_get_for_application_and_user():
user = UserFactory.create()
application = ApplicationFactory.create()
env1 = EnvironmentFactory.create(application=application)
EnvironmentFactory.create(application=application)
EnvironmentRoleFactory.create(user=user, environment=env1)
roles = EnvironmentRoles.get_for_application_and_user(user.id, application.id)
assert len(roles) == 1
assert roles[0].environment == env1
assert roles[0].user == user