aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--wqflask/wqflask/oauth2/client.py2
-rw-r--r--wqflask/wqflask/oauth2/groups.py73
-rw-r--r--wqflask/wqflask/oauth2/resources.py121
-rw-r--r--wqflask/wqflask/oauth2/roles.py78
-rw-r--r--wqflask/wqflask/templates/base.html49
-rw-r--r--wqflask/wqflask/templates/gsearch_gene.html11
-rw-r--r--wqflask/wqflask/templates/oauth2/create-role.html46
-rw-r--r--wqflask/wqflask/templates/oauth2/list_roles.html58
-rw-r--r--wqflask/wqflask/templates/oauth2/view-group-role.html96
-rw-r--r--wqflask/wqflask/templates/oauth2/view-resource.html121
10 files changed, 636 insertions, 19 deletions
diff --git a/wqflask/wqflask/oauth2/client.py b/wqflask/wqflask/oauth2/client.py
index 2bf3f94d..f712e54d 100644
--- a/wqflask/wqflask/oauth2/client.py
+++ b/wqflask/wqflask/oauth2/client.py
@@ -6,7 +6,7 @@ from pymonad.maybe import Just, Maybe, Nothing
from pymonad.either import Left, Right, Either
from authlib.integrations.requests_client import OAuth2Session
-SCOPE = "profile group role resource register-client"
+SCOPE = "profile group role resource register-client user"
def oauth2_client():
config = app.config
diff --git a/wqflask/wqflask/oauth2/groups.py b/wqflask/wqflask/oauth2/groups.py
index f9e9bffe..551c0640 100644
--- a/wqflask/wqflask/oauth2/groups.py
+++ b/wqflask/wqflask/oauth2/groups.py
@@ -1,3 +1,4 @@
+import uuid
import datetime
from functools import partial
@@ -131,3 +132,75 @@ def reject_join_request():
data=request.form).either(
handle_error("oauth2.group.list_join_requests"),
__success__)
+
+@groups.route("/role/<uuid:group_role_id>", methods=["GET"])
+@require_oauth2
+def group_role(group_role_id: uuid.UUID):
+ """View the details of a particular role."""
+ def __render_error(**kwargs):
+ return render_template("oauth2/view-group-role.html", **kwargs)
+
+ def __gprivs_success__(role, group_privileges):
+ return render_template(
+ "oauth2/view-group-role.html", group_role=role,
+ group_privileges=tuple(
+ priv for priv in group_privileges
+ if priv not in role["role"]["privileges"]))
+
+ def __role_success__(role):
+ return oauth2_get("oauth2/group/privileges").either(
+ lambda err: __render_error__(
+ group_role=group_role,
+ group_privileges_error=process_error(err)),
+ lambda privileges: __gprivs_success__(role, privileges))
+
+ return oauth2_get(f"oauth2/group/role/{group_role_id}").either(
+ lambda err: __render_error__(group_role_error=process_error(err)),
+ __role_success__)
+
+def add_delete_privilege_to_role(
+ group_role_id: uuid.UUID, direction: str) -> Response:
+ """Add/delete a privilege to/from a role depending on `direction`."""
+ assert direction in ("ADD", "DELETE")
+ def __render__():
+ return redirect(url_for(
+ "oauth2.group.group_role", group_role_id=group_role_id))
+
+ def __error__(error):
+ err = process_error(error)
+ flash(f"{err['error']}: {err['error_description']}", "alert-danger")
+ return __render__()
+
+ def __success__(success):
+ flash(success["description"], "alert-success")
+ return __render__()
+ try:
+ form = request.form
+ privilege_id = form.get("privilege_id")
+ assert bool(privilege_id), "Privilege to add must be provided"
+ uris = {
+ "ADD": f"oauth2/group/role/{group_role_id}/privilege/add",
+ "DELETE": f"oauth2/group/role/{group_role_id}/privilege/delete"
+ }
+ return oauth2_post(
+ uris[direction],
+ data={
+ "group_role_id": group_role_id,
+ "privilege_id": privilege_id
+ }).either(__error__, __success__)
+ except AssertionError as aerr:
+ flash(aerr.args[0], "alert-danger")
+ return redirect(url_for(
+ "oauth2.group.group_role", group_role_id=group_role_id))
+
+@groups.route("/role/<uuid:group_role_id>/privilege/add", methods=["POST"])
+@require_oauth2
+def add_privilege_to_role(group_role_id: uuid.UUID):
+ """Add a privilege to a group role."""
+ return add_delete_privilege_to_role(group_role_id, "ADD")
+
+@groups.route("/role/<uuid:group_role_id>/privilege/delete", methods=["POST"])
+@require_oauth2
+def delete_privilege_from_role(group_role_id: uuid.UUID):
+ """Delete a privilege from a group role."""
+ return add_delete_privilege_to_role(group_role_id, "DELETE")
diff --git a/wqflask/wqflask/oauth2/resources.py b/wqflask/wqflask/oauth2/resources.py
index 872a29c6..8f31f7c9 100644
--- a/wqflask/wqflask/oauth2/resources.py
+++ b/wqflask/wqflask/oauth2/resources.py
@@ -1,6 +1,7 @@
import uuid
-from flask import flash, request, url_for, redirect, Blueprint, render_template
+from flask import (
+ flash, request, url_for, redirect, Response, Blueprint, render_template)
from .checks import require_oauth2
from .client import oauth2_get, oauth2_post
@@ -51,18 +52,62 @@ def create_resource():
@require_oauth2
def view_resource(resource_id: uuid.UUID):
"""View the given resource."""
- # Display the resource's details
- # Provide edit/delete options
- # Metadata edit maybe?
+ def __users_success__(
+ resource, unlinked_data, users_n_roles, this_user, group_roles,
+ users):
+ return render_template(
+ "oauth2/view-resource.html", resource=resource,
+ unlinked_data=unlinked_data, users_n_roles=users_n_roles,
+ this_user=this_user, group_roles=group_roles, users=users)
+
+ def __group_roles_success__(
+ resource, unlinked_data, users_n_roles, this_user, group_roles):
+ return oauth2_get("oauth2/user/list").either(
+ lambda err: render_template(
+ "oauth2/view-resource.html", resource=resource,
+ unlinked_data=unlinked_data, users_n_roles=users_n_roles,
+ this_user=this_user, group_roles=group_roles,
+ users_error=process_error(err)),
+ lambda users: __users_success__(
+ resource, unlinked_data, users_n_roles, this_user, group_roles,
+ users))
+
+ def __this_user_success__(resource, unlinked_data, users_n_roles, this_user):
+ return oauth2_get("oauth2/group/roles").either(
+ lambda err: render_template(
+ "oauth2/view-resources.html", resource=resource,
+ unlinked_data=unlinked_data, users_n_roles=users_n_roles,
+ this_user=this_user, group_roles_error=process_error(err)),
+ lambda groles: __group_roles_success__(
+ resource, unlinked_data, users_n_roles, this_user, groles))
+
+ def __users_n_roles_success__(resource, unlinked_data, users_n_roles):
+ return oauth2_get("oauth2/user").either(
+ lambda err: render_template(
+ "oauth2/view-resources.html",
+ this_user_error=process_error(err)),
+ lambda usr_dets: __this_user_success__(
+ resource, unlinked_data, users_n_roles, usr_dets))
+
+ def __unlinked_success__(resource, unlinked_data):
+ return oauth2_get(f"oauth2/resource/{resource_id}/user/list").either(
+ lambda err: render_template(
+ "oauth2/view-resource.html", resource=resource,
+ unlinked_data=unlinked_data,
+ users_n_roles_error=process_error(err)),
+ lambda users_n_roles: __users_n_roles_success__(
+ resource, unlinked_data, users_n_roles))
+ return render_template(
+ "oauth2/view-resource.html", resource=resource, error=None,
+ unlinked_data=unlinked)
+
def __resource_success__(resource):
dataset_type = resource["resource_category"]["resource_category_key"]
return oauth2_get(f"oauth2/group/{dataset_type}/unlinked-data").either(
lambda err: render_template(
"oauth2/view-resource.html", resource=resource,
unlinked_error=process_error(err)),
- lambda unlinked: render_template(
- "oauth2/view-resource.html", resource=resource, error=None,
- unlinked_data=unlinked))
+ lambda unlinked: __unlinked_success__(resource, unlinked))
return oauth2_get(f"oauth2/resource/view/{resource_id}").either(
lambda err: render_template("oauth2/view-resource.html",
@@ -128,6 +173,68 @@ def unlink_data_from_resource():
return redirect(url_for(
"oauth2.resource.view_resource", resource_id=form["resource_id"]))
+@resources.route("<uuid:resource_id>/user/assign", methods=["POST"])
+@require_oauth2
+def assign_role(resource_id: uuid.UUID) -> Response:
+ form = request.form
+ group_role_id = form.get("group_role_id", "")
+ user_email = form.get("user_email", "")
+ try:
+ assert bool(group_role_id), "The role must be provided."
+ assert bool(user_email), "The user email must be provided."
+
+ def __assign_error__(error):
+ err = process_error(error)
+ flash(f"{err['error']}: {err['error_description']}", "alert-danger")
+ return redirect(url_for(
+ "oauth2.resource.view_resource", resource_id=resource_id))
+
+ def __assign_success__(success):
+ flash(success["description"], "alert-success")
+ return redirect(url_for(
+ "oauth2.resource.view_resource", resource_id=resource_id))
+
+ return oauth2_post(
+ f"oauth2/resource/{resource_id}/user/assign",
+ data={
+ "group_role_id": group_role_id,
+ "user_email": user_email
+ }).either(__assign_error__, __assign_success__)
+ except AssertionError as aserr:
+ flash(aserr.args[0], "alert-danger")
+ return redirect(url_for("oauth2.resources.view_resource", resource_id=resource_id))
+
+@resources.route("<uuid:resource_id>/user/unassign", methods=["POST"])
+@require_oauth2
+def unassign_role(resource_id: uuid.UUID) -> Response:
+ form = request.form
+ group_role_id = form.get("group_role_id", "")
+ user_id = form.get("user_id", "")
+ try:
+ assert bool(group_role_id), "The role must be provided."
+ assert bool(user_id), "The user id must be provided."
+
+ def __unassign_error__(error):
+ err = process_error(error)
+ flash(f"{err['error']}: {err['error_description']}", "alert-danger")
+ return redirect(url_for(
+ "oauth2.resource.view_resource", resource_id=resource_id))
+
+ def __unassign_success__(success):
+ flash(success["description"], "alert-success")
+ return redirect(url_for(
+ "oauth2.resource.view_resource", resource_id=resource_id))
+
+ return oauth2_post(
+ f"oauth2/resource/{resource_id}/user/unassign",
+ data={
+ "group_role_id": group_role_id,
+ "user_id": user_id
+ }).either(__unassign_error__, __unassign_success__)
+ except AssertionError as aserr:
+ flash(aserr.args[0], "alert-danger")
+ return redirect(url_for("oauth2.resources.view_resource", resource_id=resource_id))
+
@resources.route("/edit/<uuid:resource_id>", methods=["GET"])
@require_oauth2
def edit_resource(resource_id: uuid.UUID):
diff --git a/wqflask/wqflask/oauth2/roles.py b/wqflask/wqflask/oauth2/roles.py
index 0b181264..cabfdfac 100644
--- a/wqflask/wqflask/oauth2/roles.py
+++ b/wqflask/wqflask/oauth2/roles.py
@@ -1,22 +1,38 @@
"""Handle role endpoints"""
import uuid
-from flask import Blueprint, render_template
+from flask import flash, request, url_for, redirect, Blueprint, render_template
from .checks import require_oauth2
from .client import oauth2_get, oauth2_post
-from .request_utils import request_error
+from .request_utils import request_error, process_error
roles = Blueprint("role", __name__)
@roles.route("/user", methods=["GET"])
@require_oauth2
def user_roles():
- def __success__(roles):
- return render_template("oauth2/list_roles.html", roles=roles)
+ def __grerror__(roles, user_privileges, error):
+ return render_template(
+ "oauth2/list_roles.html", roles=roles,
+ user_privileges=user_privileges,
+ group_roles_error=process_error(error))
+
+ def __grsuccess__(roles, user_privileges, group_roles):
+ return render_template(
+ "oauth2/list_roles.html", roles=roles,
+ user_privileges=user_privileges, group_roles=group_roles)
+
+ def __role_success__(roles):
+ uprivs = tuple(
+ privilege["privilege_id"] for role in roles
+ for privilege in role["privileges"])
+ return oauth2_get("oauth2/group/roles").either(
+ lambda err: __grerror__(roles, uprivs, err),
+ lambda groles: __grsuccess__(roles, uprivs, groles))
return oauth2_get("oauth2/user/roles").either(
- request_error, __success__)
+ request_error, __role_success__)
@roles.route("/role/<uuid:role_id>", methods=["GET"])
@require_oauth2
@@ -26,3 +42,55 @@ def role(role_id: uuid.UUID):
return oauth2_get(f"oauth2/role/view/{role_id}").either(
request_error, __success__)
+
+@roles.route("/create", methods=["GET", "POST"])
+@require_oauth2
+def create_role():
+ """Create a new role."""
+ def __roles_error__(error):
+ return render_template(
+ "oauth2/create-role.html", roles_error=process_error(error))
+
+ def __gprivs_error__(roles, error):
+ return render_template(
+ "oauth2/create-role.html", roles=roles,
+ group_privileges_error=process_error(error))
+
+ def __success__(roles, gprivs):
+ uprivs = tuple(
+ privilege["privilege_id"] for role in roles
+ for privilege in role["privileges"])
+ return render_template(
+ "oauth2/create-role.html", roles=roles, user_privileges=uprivs,
+ group_privileges=gprivs,
+ prev_role_name=request.args.get("role_name"))
+
+ def __fetch_gprivs__(roles):
+ return oauth2_get("oauth2/group/privileges").either(
+ lambda err: __gprivs_error__(roles, err),
+ lambda gprivs: __success__(roles, gprivs))
+
+ if request.method == "GET":
+ return oauth2_get("oauth2/user/roles").either(
+ __roles_error__, __fetch_gprivs__)
+
+ form = request.form
+ role_name = form.get("role_name")
+ privileges = form.getlist("privileges[]")
+ if len(privileges) == 0:
+ flash("You must assign at least one privilege to the role",
+ "alert-danger")
+ return redirect(url_for(
+ "oauth2.role.create_role", role_name=role_name))
+ def __create_error__(error):
+ err = process_error(error)
+ flash(f"{err['error']}: {err['error_description']}",
+ "alert-danger")
+ return redirect(url_for("oauth2.role.create_role"))
+ def __create_success__(*args):
+ flash("Role created successfully.", "alert-success")
+ return redirect(url_for("oauth2.role.user_roles"))
+ return oauth2_post(
+ "oauth2/group/role/create",data={
+ "role_name": role_name, "privileges[]": privileges}).either(
+ __create_error__,__create_success__)
diff --git a/wqflask/wqflask/templates/base.html b/wqflask/wqflask/templates/base.html
index 7145cd7a..4b1237f5 100644
--- a/wqflask/wqflask/templates/base.html
+++ b/wqflask/wqflask/templates/base.html
@@ -28,6 +28,10 @@
{% endblock %}
<style>
+
+ .form-rounded {
+ border-radius: 1rem;
+ }
table.dataTable thead .sorting_asc {
background-image: url({{ url_for("js", filename="DataTables/images/sort_asc_disabled.png") }});
}
@@ -135,14 +139,19 @@
<div class="container-fluid" style="width: 100%; min-width: 650px; position: relative; background-color: #d5d5d5; height: 84px;">
- <form method="get" action="/gsearch">
+ <form method="get" action="/gsearch" id="searchform">
<div class="row" style="width: 100%; position: absolute; bottom: 0; top: 30px;">
+
+ <!--
<button id="btsearch" class="btn btn-primary" style="margin-left: 20px;"><span class="glyphicon glyphicon-search"></span> Search All</button>
+
+ use enter key to submit fomr -->
<select style="width: 160px; margin-top: 15px; margin-left: 10px;" name="type">
<option value="gene">Genes / Molecules</option>
<option value="phenotype" {% if type=="phenotype" %}selected{% endif %}>Phenotypes</option>
</select>
- <input style="width: 50%; margin-top: 15px; margin-left: 10px;" type="text" name="terms" required>
+
+ <input id="term" class="form-rounded" style="width: 40vw; margin-top: 15px; margin-left: 10px;" type="text" name="terms" required placeholder="enter you search term here">
</div>
</form>
</div>
@@ -247,6 +256,7 @@
<!--</div>-->
</div>
+
<script src="{{ url_for('js', filename='jquery/jquery.min.js') }}" type="text/javascript"></script>
<script src="{{ url_for('js', filename='bootstrap/js/bootstrap.min.js') }}" type="text/javascript"></script>
<script>
@@ -259,6 +269,41 @@
}
})
</script>
+
+
+ <script type="text/javascript">
+
+
+
+$(document).ready(function() {
+
+
+ const urlParams = new URLSearchParams(window.location.search)
+
+ let term = "cytochrome NOT P450"
+
+ if (urlParams.get("search_terms_or")){
+ term = urlParams.get("search_terms_or")
+ }
+
+ else if (urlParams.get("terms")){
+ term = urlParams.get("terms")
+ }
+
+ $("#term").val(term);
+ $("#term").keyup(function(event) {
+ if (event.keyCode === 13) {
+ event.preventDefault();
+ $('#searchform').attr('action', "/gsearch").submit();
+ }
+ });
+
+
+});
+
+
+ </script>
+
<script src="{{ url_for('js', filename='jquery-cookie/jquery.cookie.js') }}" type="text/javascript"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<!-- <script src="{{ url_for('js', filename='jquery-ui/jquery-ui.min.js') }}" type="text/javascript"></script> -->
diff --git a/wqflask/wqflask/templates/gsearch_gene.html b/wqflask/wqflask/templates/gsearch_gene.html
index 03e5019c..6bc92377 100644
--- a/wqflask/wqflask/templates/gsearch_gene.html
+++ b/wqflask/wqflask/templates/gsearch_gene.html
@@ -175,8 +175,15 @@
'orderSequence': [ "desc", "asc"],
'width': "30px",
'targets': 10,
- 'data': "mean",
- 'defaultContent': "N/A"
+ 'data': null,
+ 'defaultContent': "N/A",
+ 'render': function(data) {
+ if (data.mean > 100) {
+ return Math.log2(data.mean).toFixed(3)
+ } else {
+ return data.mean
+ }
+ }
},
{
'title': "<div style='text-align: right; padding-right: 10px;'>Peak</div> <div style='text-align: right;'>-logP <a href=\"{{ url_for('glossary_blueprint.glossary') }}#LRS\" target=\"_blank\" style=\"color: white;\"><sup>?</sup></a></div>",
diff --git a/wqflask/wqflask/templates/oauth2/create-role.html b/wqflask/wqflask/templates/oauth2/create-role.html
new file mode 100644
index 00000000..f2bff7b4
--- /dev/null
+++ b/wqflask/wqflask/templates/oauth2/create-role.html
@@ -0,0 +1,46 @@
+{%extends "base.html"%}
+{%from "oauth2/profile_nav.html" import profile_nav%}
+{%from "oauth2/display_error.html" import display_error%}
+{%block title%}View User{%endblock%}
+{%block content%}
+<div class="container" style="min-width: 1250px;">
+ {{profile_nav("roles", user_privileges)}}
+ <h3>Create Role</h3>
+
+ {{flash_me()}}
+
+ {%if group_privileges_error is defined%}
+ {{display_error("Group Privileges", group_privileges_error)}}
+ {%else%}
+ {%if "group:role:create-role" in user_privileges%}
+ <form method="POST" action="{{url_for('oauth2.role.create_role')}}">
+ <legend>Create Group Role</legend>
+ <div class="form-group">
+ <label for="role_name" class="form-label">Name</label>
+ <input type="text" id="role_name" name="role_name" required="required"
+ class="form-control"
+ {%if prev_role_name is defined and prev_role_name is not none%}
+ value="{{prev_role_name}}"
+ {%endif%} />
+ </div>
+ <label class="form-label">Privileges</label>
+ {%for priv in group_privileges%}
+ <div class="checkbox">
+ <label for="chk:{{priv.privilege_id}}">
+ <input type="checkbox" id="chk:{{priv.privilege_id}}"
+ name="privileges[]" value={{priv.privilege_id}} />
+ <span style="text-transform: capitalize;">
+ {{priv.privilege_description}}
+ </span> ({{priv.privilege_id}})
+ </label>
+ </div>
+ {%endfor%}
+
+ <input type="submit" class="btn btn-primary" value="Create" />
+ </form>
+ {%else%}
+ {{display_error("Privilege", {"error":"PrivilegeError", "error_description": "You do not have sufficient privileges to create a new role."})}}
+ {%endif%}
+ {%endif%}
+</div>
+{%endblock%}
diff --git a/wqflask/wqflask/templates/oauth2/list_roles.html b/wqflask/wqflask/templates/oauth2/list_roles.html
index 028d0a17..6feccb6f 100644
--- a/wqflask/wqflask/templates/oauth2/list_roles.html
+++ b/wqflask/wqflask/templates/oauth2/list_roles.html
@@ -1,15 +1,17 @@
{%extends "base.html"%}
{%from "oauth2/profile_nav.html" import profile_nav%}
+{%from "oauth2/display_error.html" import display_error%}
{%block title%}View User{%endblock%}
{%block content%}
<div class="container" style="min-width: 1250px;">
- {{profile_nav("roles")}}
+ {{profile_nav("roles", user_privileges)}}
<h3>Roles</h3>
{{flash_me()}}
<div class="container-fluid">
<div class="row">
+ <h3>Your System-Level Roles</h3>
<ul>
{%for role in roles %}
<li>
@@ -25,6 +27,60 @@
</ul>
</div>
+ <div class="row">
+ <h3>Group-Wide Roles</h3>
+
+ {%if "group:role:create-role" in user_privileges%}
+ <a href="{{url_for('oauth2.role.create_role')}}"
+ title="Link to create a new group role"
+ class="btn btn-info">New Group Role</a>
+ {%endif%}
+
+ {%if group_roles_error is defined%}
+ {{display_error("Group Roles", group_role_error)}}
+ {%else%}
+ <table class="table">
+ <caption>Group Roles</caption>
+ <thead>
+ <tr>
+ <th>Role Name</th>
+ <th colspan="2">Actions</th>
+ </tr>
+ </thead>
+ <tbody>
+ {%for grole in group_roles%}
+ <tr>
+ <td>{{grole.role.role_name}}</td>
+ <td>
+ <a href="{{url_for('oauth2.group.group_role', group_role_id=grole.group_role_id)}}"
+ title="Link to role {{grole.role.role_name}}"
+ class="btn btn-info">
+ View
+ </a>
+ </td>
+ <td>
+ <a href="#/edit/role"
+ title="Edit role {{grole.role.role_name}}"
+ class="btn btn-warning">
+ Edit
+ </a>
+ </td>
+ </tr>
+ {%else%}
+ <tr>
+ <td colspan="3">
+ <span class="glyphicon glyphicon-exclamation-sign text-info">
+ </span>
+ &nbsp;
+ <span class="text-info">No group roles found</span>
+ </td>
+ </tr>
+ {%endfor%}
+ </tbody>
+ </table>
+ {%endif%}
+ </div>
+
</div>
</div>
diff --git a/wqflask/wqflask/templates/oauth2/view-group-role.html b/wqflask/wqflask/templates/oauth2/view-group-role.html
new file mode 100644
index 00000000..873eb0ee
--- /dev/null
+++ b/wqflask/wqflask/templates/oauth2/view-group-role.html
@@ -0,0 +1,96 @@
+{%extends "base.html"%}
+{%from "oauth2/profile_nav.html" import profile_nav%}
+{%from "oauth2/display_error.html" import display_error%}
+{%block title%}View User{%endblock%}
+{%block content%}
+<div class="container" style="min-width: 1250px;">
+ {{profile_nav("roles")}}
+ <h3>View Group Role</h3>
+
+ {{flash_me()}}
+
+ <div class="container-fluid">
+ <div class="row">
+ <h3>Role Details</h3>
+ {%if group_role_error is defined%}
+ {{display_error("Group Role", group_role_error)}}
+ {%else%}
+ <table class="table">
+ <caption>Details for '{{group_role.role.role_name}}' Role</caption>
+ <thead>
+ <tr>
+ <th>Privilege</th>
+ <th>Description</th>
+ <th>Action</th>
+ </tr>
+ </thead>
+ <tbody>
+ {%for privilege in group_role.role.privileges%}
+ <tr>
+ <td>{{privilege.privilege_id}}</td>
+ <td>{{privilege.privilege_description}}</td>
+ <td>
+ <form action="{{url_for(
+ 'oauth2.group.delete_privilege_from_role',
+ group_role_id=group_role.group_role_id)}}"
+ method="POST">
+ <input type="hidden" name="privilege_id"
+ value="{{privilege.privilege_id}}" />
+ <input type="submit" class="btn btn-danger"
+ value="Remove" />
+ </form>
+ </td>
+ </tr>
+ {%endfor%}
+ </tbody>
+ </table>
+ {%endif%}
+ </div>
+
+ <div class="row">
+ <h3>Other Privileges</h3>
+ <table class="table">
+ <caption>Other Privileges not Assigned to this Role</caption>
+ <thead>
+ <tr>
+ <th>Privilege</th>
+ <th>Description</th>
+ <th>Action</th>
+ </tr>
+ </thead>
+
+ <tbody>
+ {%for priv in group_privileges%}
+ <tr>
+ <td>{{priv.privilege_id}}</td>
+ <td>{{priv.privilege_description}}</td>
+ <td>
+ <form action="{{url_for(
+ 'oauth2.group.add_privilege_to_role',
+ group_role_id=group_role.group_role_id)}}"
+ method="POST">
+ <input type="hidden" name="privilege_id"
+ value="{{priv.privilege_id}}" />
+ <input type="submit" class="btn btn-warning"
+ value="Add to Role" />
+ </form>
+ </td>
+ </tr>
+ {%else%}
+ <tr>
+ <td colspan="3">
+ <span class="glyphicon glyphicon-info-sign text-info">
+ </span>
+ &nbsp;
+ <span class="text-info">All privileges assigned!</span>
+ </td>
+ </tr>
+ {%endfor%}
+ </tbody>
+ </table>
+ </div>
+
+ </div>
+
+</div>
+{%endblock%}
diff --git a/wqflask/wqflask/templates/oauth2/view-resource.html b/wqflask/wqflask/templates/oauth2/view-resource.html
index fb44560b..14e7872b 100644
--- a/wqflask/wqflask/templates/oauth2/view-resource.html
+++ b/wqflask/wqflask/templates/oauth2/view-resource.html
@@ -12,6 +12,7 @@
<div class="container-fluid">
<div class="row">
+ <h3>Resource Details</h3>
{%if error %}
<span class="glyphicon glyphicon-exclamation-sign text-danger">
</span>
@@ -41,6 +42,7 @@
</div>
<div class="row">
+ <h3>Resource Data</h3>
<table class="table">
<caption>Resource Data</caption>
<thead>
@@ -88,6 +90,7 @@
</div>
<div class="row">
+ <h3>Unlinked Data</h3>
<table class="table">
<caption>Link Data</caption>
<thead>
@@ -125,7 +128,7 @@
</td>
</tr>
{%else%}
- <span class="glyphicon glyphicon-info-sign text-danger">
+ <span class="glyphicon glyphicon-info-sign text-info">
</span>
&nbsp;
<strong class="text-info">No data to link.</strong>
@@ -135,6 +138,122 @@
</table>
</div>
+ <div class="row">
+ <h3>User Roles</h3>
+ {%if users_n_roles_error is defined%}
+ {{display_error("Users and Roles", users_n_roles_error)}}
+ {%else%}
+ <table class="table">
+ <caption>User Roles</caption>
+ <thead>
+ <tr>
+ <th>User Email</th>
+ <th>User Name</th>
+ <th>User Group</th>
+ <th colspan="2">Assigned Roles</th>
+ </tr>
+ </thead>
+ <tbody>
+ {%for user_row in users_n_roles%}
+ <tr>
+ <td rowspan="{{user_row.roles | length + 1}}">{{user_row.user.email}}</td>
+ <td rowspan="{{user_row.roles | length + 1}}">{{user_row.user.name}}</td>
+ <td rowspan="{{user_row.roles | length + 1}}">
+ {{user_row.user_group.group_name}}</td>
+ <th>Role</th>
+ <th>Action</th>
+ </tr>
+ {%for grole in user_row.roles%}
+ <tr>
+ <td>
+ <a href="{{url_for(
+ 'oauth2.group.group_role',
+ group_role_id=grole.group_role_id)}}"
+ title="Details for '{{grole.role.role_name}}' role">
+ {{grole.role.role_name}}
+ </a>
+ </td>
+ <td>
+ <form action="{{url_for('oauth2.resource.unassign_role',
+ resource_id=resource.resource_id)}}"
+ method="POST">
+ <input type="hidden" name="user_id"
+ value="{{user_row.user.user_id}}" />
+ <input type="hidden" name="group_role_id"
+ value="{{grole.group_role_id}}">
+ <input type="submit"
+ value="Unassign"
+ class="btn btn-danger"
+ {%if user_row.user.user_id==this_user.user_id%}
+ disabled="disabled"
+ {%endif%}>
+ </form>
+ </td>
+ </tr>
+ {%endfor%}
+ {%else%}
+ <tr>
+ <td colspan="5">
+ <span class="glyphicon glyphicon-info-sign text-info">
+ </span>
+ &nbsp;
+ <span class="text-info">
+ There are no users assigned any role for this resource.
+ </span>
+ </td>
+ </tr>
+ {%endfor%}
+ </tbody>
+ </table>
+ {%endif%}
+ </div>
+
+ <div class="row">
+ <h3>Assign</h3>
+ {%if group_roles_error is defined%}
+ {{display_error("Group Roles", group_roles_error)}}
+ {%elif users_error is defined%}
+ {{display_error("Users", users_error)}}
+ {%else%}
+ <form action="{{url_for(
+ 'oauth2.resource.assign_role',
+ resource_id=resource.resource_id)}}"
+ method="POST" autocomplete="off">
+ <input type="hidden" name="resource_id" value="{{resource_id}}" />
+ <div class="form-group">
+ <label for="group_role_id" class="form-label">Role</label>
+ <select class="form-control" name="group_role_id"
+ id="group_role_id" required="required">
+ <option value="">Select role</option>
+ {%for grole in group_roles%}
+ <option value="{{grole.group_role_id}}">
+ {{grole.role.role_name}}
+ </option>
+ {%endfor%}
+ </select>
+ </div>
+ <div class="form-group">
+ <label for="user-email" class="form-label">User Email</label>
+ <input list="users-list" name="user_email" class="form-control"
+ {%if users | length == 0%}
+ disabled="disabled"
+ {%endif%}
+ required="required" />
+ <datalist id="users-list">
+ {%for user in users%}
+ <option value="{{user.email}}">{{user.email}} - {{user.name}}</option>
+ {%endfor%}
+ </datalist>
+ </div>
+
+ <input type="submit" class="btn btn-primary" value="Assign"
+ {%if users | length == 0%}
+ disabled="disabled"
+ {%endif%} />
+ </form>
+ {%endif%}
+ </div>
+
</div>
</div>