Merge pull request #716 from dod-ccpo/portfolio-admin-users-table
Portfolio admin users table
This commit is contained in:
commit
7ab5e0ba58
@ -7,6 +7,7 @@ from atst.models import Base, mixins
|
||||
from .types import Id
|
||||
|
||||
from atst.database import db
|
||||
from atst.utils import first_or_none
|
||||
from atst.models.environment_role import EnvironmentRole
|
||||
from atst.models.application import Application
|
||||
from atst.models.environment import Environment
|
||||
@ -111,6 +112,11 @@ class PortfolioRole(Base, mixins.TimestampsMixin, mixins.AuditableMixin):
|
||||
else:
|
||||
return MEMBER_STATUSES["unknown"]
|
||||
|
||||
def has_permission_set(self, perm_set_name):
|
||||
return first_or_none(
|
||||
lambda prms: prms.name == perm_set_name, self.permission_sets
|
||||
)
|
||||
|
||||
@property
|
||||
def has_dod_id_error(self):
|
||||
return self.latest_invitation and self.latest_invitation.is_rejected_wrong_user
|
||||
|
@ -10,6 +10,7 @@ from atst.domain.authz import Authorization
|
||||
from atst.domain.common import Paginator
|
||||
from atst.forms.portfolio import PortfolioForm
|
||||
from atst.models.permissions import Permissions
|
||||
from atst.domain.permission_sets import PermissionSets
|
||||
|
||||
|
||||
@portfolios_bp.route("/portfolios")
|
||||
@ -22,6 +23,20 @@ def portfolios():
|
||||
return render_template("portfolios/blank_slate.html")
|
||||
|
||||
|
||||
def serialize_member(member):
|
||||
return {
|
||||
"member": member,
|
||||
"app_mgmt": member.has_permission_set(
|
||||
PermissionSets.EDIT_PORTFOLIO_APPLICATION_MANAGEMENT
|
||||
),
|
||||
"funding": member.has_permission_set(PermissionSets.EDIT_PORTFOLIO_FUNDING),
|
||||
"reporting": member.has_permission_set(PermissionSets.EDIT_PORTFOLIO_REPORTS),
|
||||
"portfolio_mgmt": member.has_permission_set(
|
||||
PermissionSets.EDIT_PORTFOLIO_ADMIN
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@portfolios_bp.route("/portfolios/<portfolio_id>/admin")
|
||||
def portfolio_admin(portfolio_id):
|
||||
portfolio = Portfolios.get_for_update_information(g.current_user, portfolio_id)
|
||||
@ -30,11 +45,14 @@ def portfolio_admin(portfolio_id):
|
||||
audit_events = AuditLog.get_portfolio_events(
|
||||
g.current_user, portfolio, pagination_opts
|
||||
)
|
||||
members_data = [serialize_member(member) for member in portfolio.members]
|
||||
return render_template(
|
||||
"portfolios/admin.html",
|
||||
form=form,
|
||||
portfolio=portfolio,
|
||||
audit_events=audit_events,
|
||||
user=g.current_user,
|
||||
members_data=members_data,
|
||||
)
|
||||
|
||||
|
||||
|
@ -168,14 +168,51 @@
|
||||
.member-list {
|
||||
.panel {
|
||||
@include shadow-panel;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.member-list-header {
|
||||
margin: 2 * $gap 5 * $gap;
|
||||
padding: inherit;
|
||||
overflow: auto;
|
||||
|
||||
.left {
|
||||
float: left;
|
||||
padding-bottom: 0.8rem;
|
||||
}
|
||||
|
||||
.icon-link {
|
||||
float: right;
|
||||
margin-top: 0.8rem;
|
||||
}
|
||||
|
||||
.icon {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.subheading {
|
||||
font-size: 1.4rem;
|
||||
color: $color-gray;
|
||||
}
|
||||
|
||||
table {
|
||||
box-shadow: 0 6px 18px 0 rgba(144,164,183,0.3);
|
||||
|
||||
thead {
|
||||
th:first-child {
|
||||
padding-left: 3 * $gap;
|
||||
}
|
||||
|
||||
tr:first-child {
|
||||
padding: 0 2 * $gap 0 5 * $gap;
|
||||
}
|
||||
|
||||
td {
|
||||
font-weight: bold;
|
||||
font-size: 1.4rem;
|
||||
border-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
th {
|
||||
@ -186,8 +223,29 @@
|
||||
color: $color-gray;
|
||||
}
|
||||
|
||||
td {
|
||||
border-bottom: 1px solid $color-gray-lightest;
|
||||
td:first-child {
|
||||
padding: 2 * $gap 2 * $gap 2 * $gap 5 * $gap;
|
||||
}
|
||||
|
||||
tbody {
|
||||
td {
|
||||
border-bottom: 1px solid $color-gray-lightest;
|
||||
font-size: 1.6rem;
|
||||
border-top: 0;
|
||||
padding: 3 * $gap 2 * $gap;
|
||||
}
|
||||
|
||||
.green {
|
||||
color: $color-green;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-weight: bold;
|
||||
|
||||
.you {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.add-member-link {
|
||||
|
64
templates/fragments/admin/portfolio_members.html
Normal file
64
templates/fragments/admin/portfolio_members.html
Normal file
@ -0,0 +1,64 @@
|
||||
{% from "components/icon.html" import Icon %}
|
||||
|
||||
<section class="member-list">
|
||||
<div class='responsive-table-wrapper panel'>
|
||||
<div class='member-list-header'>
|
||||
<div class='left'>
|
||||
<div class='h3'>{{ "portfolios.admin.portfolio_members_title" | translate }}</div>
|
||||
<div class='subheading'>
|
||||
{{ "portfolios.admin.portfolio_members_subheading" | translate }}
|
||||
</div>
|
||||
</div>
|
||||
<a class='icon-link'>
|
||||
<span class='icon'>{{ Icon('info') }}</span>
|
||||
{{ "portfolios.admin.settings_info" | translate }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% if not portfolio.members %}
|
||||
|
||||
<p>There are currently no members in this Portfolio.</p>
|
||||
|
||||
{% else %}
|
||||
|
||||
<table>
|
||||
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{{ "portfolios.members.permissions.name" | translate }}</td>
|
||||
<td>{{ "portfolios.members.permissions.app_mgmt" | translate }}</td>
|
||||
<td>{{ "portfolios.members.permissions.funding" | translate }}</td>
|
||||
<td>{{ "portfolios.members.permissions.reporting" | translate }}</td>
|
||||
<td>{{ "portfolios.members.permissions.portfolio_mgmt" | translate }}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% for member_data in members_data %}
|
||||
<tr>
|
||||
<td class='name'>{{ member_data.member.user_name }}
|
||||
{% if member_data.member.user == user %}
|
||||
<span class='you'>(<span class='green'>you</span>)</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% set heading_perms = [member_data.app_mgmt, member_data.funding, member_data.reporting, member_data.portfolio_mgmt] %}
|
||||
|
||||
{% for has_perm in heading_perms %}
|
||||
{% if has_perm %}
|
||||
<td class='green'>Edit Access</td>
|
||||
{% else %}
|
||||
<td>View Only</td>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
</section>
|
@ -1,5 +1,3 @@
|
||||
{% from "components/pagination.html" import Pagination %}
|
||||
|
||||
<section class="block-list activity-log">
|
||||
<div class='subheading'>{{ "portfolios.admin.activity_log_title" | translate }}</div>
|
||||
<ul>
|
||||
|
@ -41,6 +41,7 @@
|
||||
|
||||
{% include "fragments/primary_point_of_contact.html" %}
|
||||
|
||||
{% include "fragments/admin/portfolio_members.html" %}
|
||||
{% include "fragments/audit_events_log.html" %}
|
||||
|
||||
{{ Pagination(audit_events, 'portfolios.portfolio_admin', portfolio_id=portfolio.id) }}
|
||||
|
@ -48,7 +48,7 @@
|
||||
<div class='separator'></div>
|
||||
{% endif %}
|
||||
{% if user_can(permissions.VIEW_PORTFOLIO_USERS) %}
|
||||
<a class='icon-link' href='{{ url_for("portfolios.application_members", portfolio_id=portfolio.id, application_id=application.id) }}'>
|
||||
<a class='icon-link'>
|
||||
<span>{{ "portfolios.applications.team_text" | translate }}</span>
|
||||
<span class='counter'>{{ application.num_users }}</span>
|
||||
</a>
|
||||
|
@ -307,3 +307,23 @@ def test_can_list_all_permissions():
|
||||
port_role = PortfolioRoleFactory.create(permission_sets=[role_one, role_two])
|
||||
expected_perms = role_one.permissions + role_two.permissions
|
||||
assert expected_perms == expected_perms
|
||||
|
||||
|
||||
def test_has_permission_set():
|
||||
perm_sets = PermissionSets.get_many(
|
||||
[PermissionSets.VIEW_PORTFOLIO_FUNDING, PermissionSets.VIEW_PORTFOLIO_REPORTS]
|
||||
)
|
||||
port_role = PortfolioRoleFactory.create(permission_sets=perm_sets)
|
||||
|
||||
assert port_role.has_permission_set(PermissionSets.VIEW_PORTFOLIO_REPORTS)
|
||||
|
||||
|
||||
def test_does_not_have_permission_set():
|
||||
perm_sets = PermissionSets.get_many(
|
||||
[PermissionSets.VIEW_PORTFOLIO_FUNDING, PermissionSets.VIEW_PORTFOLIO_REPORTS]
|
||||
)
|
||||
port_role = PortfolioRoleFactory.create(permission_sets=perm_sets)
|
||||
|
||||
assert not port_role.has_permission_set(
|
||||
PermissionSets.EDIT_PORTFOLIO_APPLICATION_MANAGEMENT
|
||||
)
|
||||
|
@ -563,9 +563,13 @@ portfolios:
|
||||
title: '{application_name} Team Management'
|
||||
subheading: Team Management
|
||||
admin:
|
||||
portfolio_members_title: Portfolio Members
|
||||
portfolio_members_subheading: These members have different levels of access to the portfolio.
|
||||
settings_info: Learn more about these settings
|
||||
activity_log_title: Activity Log
|
||||
members:
|
||||
permissions:
|
||||
name: Name
|
||||
app_mgmt: App Mgmt
|
||||
funding: Funding
|
||||
reporting: Reporting
|
||||
|
Loading…
x
Reference in New Issue
Block a user