diff options
-rw-r--r-- | wqflask/wqflask/oauth2/client.py | 2 | ||||
-rw-r--r-- | wqflask/wqflask/oauth2/groups.py | 73 | ||||
-rw-r--r-- | wqflask/wqflask/oauth2/resources.py | 121 | ||||
-rw-r--r-- | wqflask/wqflask/oauth2/roles.py | 78 | ||||
-rw-r--r-- | wqflask/wqflask/templates/base.html | 49 | ||||
-rw-r--r-- | wqflask/wqflask/templates/gsearch_gene.html | 11 | ||||
-rw-r--r-- | wqflask/wqflask/templates/oauth2/create-role.html | 46 | ||||
-rw-r--r-- | wqflask/wqflask/templates/oauth2/list_roles.html | 58 | ||||
-rw-r--r-- | wqflask/wqflask/templates/oauth2/view-group-role.html | 96 | ||||
-rw-r--r-- | wqflask/wqflask/templates/oauth2/view-resource.html | 121 |
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> + + <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> + + <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> <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> + + <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> |