diff options
author | zsloan | 2020-06-05 16:52:56 -0500 |
---|---|---|
committer | zsloan | 2020-06-05 16:52:56 -0500 |
commit | a302a2b0ac0e7c0f26a0d063c3f2b057f61d47f1 (patch) | |
tree | a9f5c88f7d2818bf4e0481b85872c7580a8d577c | |
parent | 218576a04f90cc0bc9e53685323e1caa8cffe986 (diff) | |
download | genenetwork2-a302a2b0ac0e7c0f26a0d063c3f2b057f61d47f1.tar.gz |
Commiting other current group/resource management code, plus the new files
-rw-r--r-- | wqflask/base/trait.py | 2 | ||||
-rw-r--r-- | wqflask/maintenance/set_resource_defaults.py | 155 | ||||
-rw-r--r-- | wqflask/utility/authentication_tools.py | 46 | ||||
-rw-r--r-- | wqflask/utility/redis_tools.py | 37 | ||||
-rw-r--r-- | wqflask/wqflask/group_manager.py | 77 | ||||
-rw-r--r-- | wqflask/wqflask/resource_manager.py | 72 | ||||
-rw-r--r-- | wqflask/wqflask/static/new/javascript/group_manager.js | 38 | ||||
-rw-r--r-- | wqflask/wqflask/templates/admin/create_group.html | 89 | ||||
-rw-r--r-- | wqflask/wqflask/templates/admin/group_manager.html | 68 | ||||
-rw-r--r-- | wqflask/wqflask/templates/admin/manage_resource.html | 92 | ||||
-rw-r--r-- | wqflask/wqflask/templates/admin/search_for_groups.html | 64 | ||||
-rw-r--r-- | wqflask/wqflask/templates/admin/select_group_to_add.html | 54 | ||||
-rw-r--r-- | wqflask/wqflask/templates/new_security/not_authenticated.html | 11 | ||||
-rw-r--r-- | wqflask/wqflask/templates/show_trait_details.html | 5 | ||||
-rw-r--r-- | wqflask/wqflask/views.py | 3 |
15 files changed, 764 insertions, 49 deletions
diff --git a/wqflask/base/trait.py b/wqflask/base/trait.py index 405c4ebf..2a945588 100644 --- a/wqflask/base/trait.py +++ b/wqflask/base/trait.py @@ -391,6 +391,8 @@ def retrieve_trait_info(trait, dataset, get_qtl_info=False): if response.strip() == "no-access": trait.view = False return trait + else: + trait_info = json.loads(response) except: resource_info = get_resource_info(resource_id) default_permissions = resource_info['default_mask']['data'] diff --git a/wqflask/maintenance/set_resource_defaults.py b/wqflask/maintenance/set_resource_defaults.py new file mode 100644 index 00000000..ba102d9c --- /dev/null +++ b/wqflask/maintenance/set_resource_defaults.py @@ -0,0 +1,155 @@ +""" + +Script that sets default resource access masks for use with the DB proxy + +Defaults will be: +Owner - omni_gn +Mask - Public/non-confidential: { data: "view", + metadata: "view", + admin: "not-admin" } + Private/confidentia: { data: "no-access", + metadata: "no-access", + admin: "not-admin" } + +To run: +./bin/genenetwork2 ~/my_settings.py -c ./wqflask/maintenance/gen_select_dataset.py + +""" + +from __future__ import print_function, division + +import sys +import json + +# NEW: Note we prepend the current path - otherwise a guix instance of GN2 may be used instead +sys.path.insert(0,'./') + +# NEW: import app to avoid a circular dependency on utility.tools +from wqflask import app + +from utility.tools import SQL_URI +from utility.redis_tools import get_redis_conn, get_user_id, add_resource, get_resources +Redis = get_redis_conn() + +import MySQLdb + +import urlparse + +from utility.logger import getLogger +logger = getLogger(__name__) + +def parse_db_uri(): + """Converts a database URI to the db name, host name, user name, and password""" + + parsed_uri = urlparse.urlparse(SQL_URI) + + db_conn_info = dict( + db = parsed_uri.path[1:], + host = parsed_uri.hostname, + user = parsed_uri.username, + passwd = parsed_uri.password) + + print(db_conn_info) + return db_conn_info + +def insert_probeset_resources(default_owner_id): + current_resources = Redis.hgetall("resources") + Cursor.execute(""" SELECT + ProbeSetFreeze.Id, ProbeSetFreeze.Name, ProbeSetFreeze.confidentiality, ProbeSetFreeze.public + FROM + ProbeSetFreeze""") + + resource_results = Cursor.fetchall() + for i, resource in enumerate(resource_results): + if i % 20 == 0: + print(i) + resource_ob = {} + resource_ob['name'] = resource[1] + resource_ob['owner_id'] = default_owner_id + resource_ob['data'] = { "dataset" : str(resource[0])} + resource_ob['type'] = "dataset-probeset" + if resource[2] < 1 and resource[3] > 0: + resource_ob['default_mask'] = { "data": ["no-access", "view"] } + else: + resource_ob['default_mask'] = { "data": ["no-access"] } + resource_ob['group_masks'] = {} + + add_resource(resource_ob) + +def insert_publish_resources(default_owner_id): + current_resources = Redis.hgetall("resources") + Cursor.execute(""" SELECT + PublishXRef.Id, PublishFreeze.Id, InbredSet.InbredSetCode + FROM + PublishXRef, PublishFreeze, InbredSet, Publication + WHERE + PublishFreeze.InbredSetId = PublishXRef.InbredSetId AND + InbredSet.Id = PublishXRef.InbredSetId AND + Publication.Id = PublishXRef.PublicationId""") + + resource_results = Cursor.fetchall() + for resource in resource_results: + if resource[2]: + resource_ob = {} + if resource[2]: + resource_ob['name'] = resource[2] + "_" + str(resource[0]) + else: + resource_ob['name'] = str(resource[0]) + resource_ob['owner_id'] = default_owner_id + resource_ob['data'] = { "dataset" : str(resource[1]) , + "trait" : str(resource[0])} + resource_ob['type'] = "dataset-publish" + resource_ob['default_mask'] = { "data": "view" } + + resource_ob['group_masks'] = {} + + add_resource(resource_ob) + else: + continue + +def insert_geno_resources(default_owner_id): + current_resources = Redis.hgetall("resources") + Cursor.execute(""" SELECT + GenoFreeze.Id, GenoFreeze.ShortName, GenoFreeze.confidentiality + FROM + GenoFreeze""") + + resource_results = Cursor.fetchall() + for i, resource in enumerate(resource_results): + if i % 20 == 0: + print(i) + resource_ob = {} + resource_ob['name'] = resource[1] + resource_ob['owner_id'] = default_owner_id + resource_ob['data'] = { "dataset" : str(resource[0]) } + resource_ob['type'] = "dataset-geno" + if resource[2] < 1: + resource_ob['default_mask'] = { "data": "view" } + else: + resource_ob['default_mask'] = { "data": "no-access" } + resource_ob['group_masks'] = {} + + add_resource(resource_ob) + +def insert_resources(default_owner_id): + current_resources = get_resources() + print("START") + insert_publish_resources(default_owner_id) + print("AFTER PUBLISH") + insert_geno_resources(default_owner_id) + print("AFTER GENO") + insert_probeset_resources(default_owner_id) + print("AFTER PROBESET") + +def main(): + """Generates and outputs (as json file) the data for the main dropdown menus on the home page""" + + Redis.delete("resources") + + owner_id = get_user_id("email_address", "zachary.a.sloan@gmail.com") + insert_resources(owner_id) + +if __name__ == '__main__': + Conn = MySQLdb.Connect(**parse_db_uri()) + Cursor = Conn.cursor() + main() \ No newline at end of file diff --git a/wqflask/utility/authentication_tools.py b/wqflask/utility/authentication_tools.py new file mode 100644 index 00000000..537881a5 --- /dev/null +++ b/wqflask/utility/authentication_tools.py @@ -0,0 +1,46 @@ +from __future__ import absolute_import, print_function, division + +import json +import requests + +from base import data_set + +from utility import hmac +from utility.redis_tools import get_redis_conn, get_resource_info, get_resource_id + +from flask import Flask, g, redirect, url_for + +import logging +logger = logging.getLogger(__name__ ) + +def check_resource_availability(dataset, trait_id=None): + resource_id = get_resource_id(dataset, trait_id) + + if resource_id: + the_url = "http://localhost:8080/available?resource={}&user={}".format(resource_id, g.user_session.user_id) + try: + response = json.loads(requests.get(the_url).content)['data'] + except: + resource_info = get_resource_info(resource_id) + response = resource_info['default_mask']['data'] + + if 'view' in response: + return True + else: + return redirect(url_for("no_access_page")) + + return True + +def check_owner(dataset=None, trait_id=None, resource_id=None): + if resource_id: + resource_info = get_resource_info(resource_id) + if g.user_session.user_id == resource_info['owner_id']: + return resource_id + else: + resource_id = get_resource_id(dataset, trait_id) + if resource_id: + resource_info = get_resource_info(resource_id) + if g.user_session.user_id == resource_info['owner_id']: + return resource_id + + return False \ No newline at end of file diff --git a/wqflask/utility/redis_tools.py b/wqflask/utility/redis_tools.py index 0ad96879..bc30a0af 100644 --- a/wqflask/utility/redis_tools.py +++ b/wqflask/utility/redis_tools.py @@ -95,14 +95,17 @@ def get_user_groups(user_id): user_group_ids = [] #ZS: Group IDs where user is a regular user groups_list = Redis.hgetall("groups") for key in groups_list: - group_ob = json.loads(groups_list[key]) - group_admins = set(group_ob['admins']) - group_members = set(group_ob['members']) - if user_id in group_admins: - admin_group_ids.append(group_ob['id']) - elif user_id in group_members: - user_group_ids.append(group_ob['id']) - else: + try: + group_ob = json.loads(groups_list[key]) + group_admins = set(group_ob['admins']) + group_members = set(group_ob['members']) + if user_id in group_admins: + admin_group_ids.append(group_ob['id']) + elif user_id in group_members: + user_group_ids.append(group_ob['id']) + else: + continue + except: continue admin_groups = [] @@ -122,6 +125,24 @@ def get_group_info(group_id): return group_info +def get_group_by_unique_column(column_name, column_value): + """ Get group by column; not sure if there's a faster way to do this """ + + matched_groups = [] + + all_group_list = Redis.hgetall("groups") + for key in all_group_list: + group_info = json.loads(all_group_list[key]) + if column_name == "admins" or column_name == "members": #ZS: Since these fields are lists, search in the list + if column_value in group_info[column_name]: + matched_groups.append(group_info) + else: + if group_info[column_name] == column_value: + matched_groups.append(group_info) + + return matched_groups + + def create_group(admin_user_ids, member_user_ids = [], group_name = "Default Group Name"): group_id = str(uuid.uuid4()) new_group = { diff --git a/wqflask/wqflask/group_manager.py b/wqflask/wqflask/group_manager.py new file mode 100644 index 00000000..f41ae56d --- /dev/null +++ b/wqflask/wqflask/group_manager.py @@ -0,0 +1,77 @@ + +from __future__ import print_function, division, absolute_import + +from flask import (Flask, g, render_template, url_for, request, make_response, + redirect, flash) + +from wqflask import app +from wqflask.user_login import send_verification_email + +from utility.redis_tools import get_user_groups, get_group_info, create_group, delete_group, add_users_to_group, remove_users_from_group, \ + change_group_name, save_verification_code, check_verification_code, get_user_by_unique_column + +from utility.logger import getLogger +logger = getLogger(__name__) + +@app.route("/groups/manage", methods=('GET', 'POST')) +def manage_groups(): + params = request.form if request.form else request.args + if "add_new_group" in params: + return redirect(url_for('add_group')) + else: + admin_groups, user_groups = get_user_groups(g.user_session.user_id) + return render_template("admin/group_manager.html", admin_groups=admin_groups, user_groups=user_groups) + +@app.route("/groups/remove", methods=('POST',)) +def remove_groups(): + group_ids_to_remove = request.form['selected_group_ids'] + for group_id in group_ids_to_remove.split(":"): + delete_group(g.user_session.user_id, group_id) + + return redirect(url_for('manage_groups')) + +@app.route("/groups/create", methods=('GET', 'POST')) +def add_group(): + params = request.form if request.form else request.args + if "group_name" in params: + member_user_ids = set() + admin_user_ids = set() + admin_user_ids.add(g.user_session.user_id) #ZS: Always add the user creating the group as an admin + if "admin_emails" in params: + admin_emails = params['admin_emails_to_add'].split(",") + for email in admin_emails: + user_details = get_user_by_unique_column("email_address", email) + if user_details: + admin_user_ids.add(user_details['user_id']) + #send_group_invites(params['group_id'], user_email_list = admin_emails, user_type="admins") + if "user_emails" in params: + member_emails = params['member_emails_to_add'].split(",") + for email in member_emails: + user_details = get_user_by_unique_column("email_address", email) + if user_details: + member_user_ids.add(user_details['user_id']) + #send_group_invites(params['group_id'], user_email_list = user_emails, user_type="members") + + create_group(list(admin_user_ids), list(member_user_ids), params['group_name']) + return redirect(url_for('manage_groups')) + else: + return render_template("admin/create_group.html") + +#ZS: Will integrate this later, for now just letting users be added directly +def send_group_invites(group_id, user_email_list = [], user_type="members"): + for user_email in user_email_list: + user_details = get_user_by_unique_column("email_address", user_email) + if user_details: + group_info = get_group_info(group_id) + #ZS: Probably not necessary since the group should normally always exist if group_id is being passed here, + # but it's technically possible to hit it if Redis is cleared out before submitting the new users or something + if group_info: + #ZS: Don't add user if they're already an admin or if they're being added a regular user and are already a regular user, + # but do add them if they're a regular user and are added as an admin + if (user_details['user_id'] in group_info['admins']) or \ + ((user_type == "members") and (user_details['user_id'] in group_info['members'])): + continue + else: + send_verification_email(user_details, template_name = "email/group_verification.txt", key_prefix = "verification_code", subject = "You've been invited to join a GeneNetwork user group") + +#@app.route() \ No newline at end of file diff --git a/wqflask/wqflask/resource_manager.py b/wqflask/wqflask/resource_manager.py new file mode 100644 index 00000000..7d88b8ed --- /dev/null +++ b/wqflask/wqflask/resource_manager.py @@ -0,0 +1,72 @@ +from __future__ import print_function, division, absolute_import + +from flask import (Flask, g, render_template, url_for, request, make_response, + redirect, flash) + +from wqflask import app + +from utility.authentication_tools import check_owner +from utility.redis_tools import get_resource_info, get_group_info, get_group_by_unique_column, get_user_id + +from utility.logger import getLogger +logger = getLogger(__name__) + +@app.route("/resources/manage", methods=('GET', 'POST')) +def view_resource(): + params = request.form if request.form else request.args + if 'resource_id' in request.args: + resource_id = request.args['resource_id'] + if check_owner(resource_id=resource_id): + resource_info = get_resource_info(resource_id) + group_masks = resource_info['group_masks'] + group_masks_with_names = get_group_names(group_masks) + default_mask = resource_info['default_mask']['data'] + return render_template("admin/manage_resource.html", resource_id = resource_id, resource_info=resource_info, default_mask=default_mask, group_masks=group_masks_with_names) + else: + return redirect(url_for("no_access_page")) + +@app.route("/resources/add_group", methods=('POST',)) +def add_group_to_resource(): + resource_id = request.form['resource_id'] + if check_owner(resource_id=resource_id): + if all(key in request.form for key in ('group_id', 'group_name', 'user_name', 'user_email')): + group_list = [] + if request.form['group_id'] != "": + the_group = get_group_info(request.form['group_id']) + if the_group: + group_list.append(the_group) + if request.form['group_name'] != "": + matched_groups = get_group_by_unique_column("name", request.form['group_name']) + for group in matched_groups: + group_list.append(group) + if request.form['user_name'] != "": + user_id = get_user_id("user_name", request.form['user_name']) + if user_id: + matched_groups = get_group_by_unique_column("admins", user_id) + matched_groups += get_group_by_unique_column("members", user_id) + for group in matched_groups: + group_list.append(group) + if request.form['user_email'] != "": + user_id = get_user_id("email_address", request.form['user_email']) + if user_id: + matched_groups = get_group_by_unique_column("admins", user_id) + matched_groups += get_group_by_unique_column("members", user_id) + for group in matched_groups: + group_list.append(group) + return render_template("admin/select_group_to_add.html", group_list=group_list, resource_id = resource_id) + elif 'selected_group' in request.form: + group_id = request.form['selected_group'] + return render_template("admin/set_group_privileges.html", resource_id = resource_id, group_id = group_id) + else: + return render_template("admin/search_for_groups.html", resource_id = resource_id) + else: + return redirect(url_for("no_access_page")) + +def get_group_names(group_masks): + group_masks_with_names = {} + for group_id, group_mask in group_masks.iteritems(): + this_mask = group_mask + group_name = get_group_info(group_id)['name'] + this_mask['name'] = group_name + + return group_masks_with_names \ No newline at end of file diff --git a/wqflask/wqflask/static/new/javascript/group_manager.js b/wqflask/wqflask/static/new/javascript/group_manager.js new file mode 100644 index 00000000..5e82d104 --- /dev/null +++ b/wqflask/wqflask/static/new/javascript/group_manager.js @@ -0,0 +1,38 @@ +$('#add_to_admins').click(function() { + add_emails('admin') +}) + +$('#add_to_members').click(function() { + add_emails('member') +}) + +$('#clear_admins').click(function(){ + clear_emails('admin') +}) + +$('#clear_members').click(function(){ + clear_emails('member') +}) + + +function add_emails(user_type){ + var email_address = $('input[name=user_email]').val(); + var email_list_string = $('input[name=' + user_type + '_emails_to_add]').val() + console.log(email_list_string) + if (email_list_string == ""){ + var email_set = new Set(); + } else { + var email_set = new Set(email_list_string.split(",")) + } + email_set.add(email_address) + + $('input[name=' + user_type + '_emails_to_add]').val(Array.from(email_set).join(',')) + + var emails_display_string = Array.from(email_set).join('\n') + $('.added_' + user_type + 's').val(emails_display_string) +} + +function clear_emails(user_type){ + $('input[name=' + user_type + '_emails_to_add]').val("") + $('.added_' + user_type + 's').val("") +} \ No newline at end of file diff --git a/wqflask/wqflask/templates/admin/create_group.html b/wqflask/wqflask/templates/admin/create_group.html new file mode 100644 index 00000000..55c3fa0b --- /dev/null +++ b/wqflask/wqflask/templates/admin/create_group.html @@ -0,0 +1,89 @@ +{% extends "base.html" %} +{% block title %}Group Manager{% endblock %} +{% block content %} +<!-- Start of body --> + <div class="container"> + <div class="page-header"> + <h1>Create Group</h1> + </div> + <form action="/groups/create" method="POST"> + <input type="hidden" name="admin_emails_to_add" value=""> + <input type="hidden" name="member_emails_to_add" value=""> + <fieldset> + <div class="form-horizontal" style="width: 900px; margin-bottom: 50px;"> + <div class="form-group" style="padding-left: 20px;"> + <label for="group_name" class="col-xs-3" style="float: left; font-size: 18px;">Group Name:</label> + <div class="controls input-append col-xs-9" style="display: flex; padding-left: 20px; float: left;"> + <div class="col-xs-12"> + <input name="group_name" type="text" style="width:100%;"></input> + </div> + </div> + </div> + <div class="form-group" style="padding-left: 20px;"> + <label for="user_email" class="col-xs-3" style="float: left; font-size: 18px;">Add User Email:</label> + <div class="controls input-append col-xs-9" style="display: flex; padding-left: 20px; float: left;"> + <div class="col-xs-12"> + <input name="user_email" type="text" style="width:100%;"></input> + </div> + </div> + </div> + <div class="form-group" style="padding-left: 20px;"> + <label class="col-xs-3"></label> + <div class="controls input-append col-xs-9" style="display: flex; padding-left: 20px; float: left;"> + <div class="col-xs-6"> + <button type="button" id="add_to_admins" class="btn btn-default">Add to Admins</button> + </div> + <div class="col-xs-6"> + <button type="button" id="add_to_members" class="btn btn-default">Add to Members</button> + </div> + </div> + </div> + <div class="form-group" style="padding-left: 20px;"> + <label class="col-xs-3" style="font-size: 18px;">Members to be added:</label> + <div class="controls input-append col-xs-9" style="display: flex; padding-left: 20px; float: left;"> + <div class="col-xs-6"> + <textarea rows="8" cols="60" readonly placeholder="No users added" style="overflow-y: scroll; resize: none; width: 200px;" class="added_admins"></textarea> + </div> + <div class="col-xs-6"> + <textarea rows="8" cols="60" readonly placeholder="No users added" style="overflow-y: scroll; resize: none; width: 200px;" class="added_members"></textarea> + </div> + </div> + </div> + <div class="form-group" style="padding-left: 20px;"> + <label class="col-xs-3"></label> + <div class="controls input-append col-xs-9" style="display: flex; padding-left: 20px; float: left;"> + <div class="col-xs-6"> + <button type="button" id="clear_admins" class="btn btn-default">Clear</button> + </div> + <div class="col-xs-6"> + <button type="button" id="clear_members" class="btn btn-default">Clear</button> + </div> + </div> + </div> + <div class="form-group" style="padding-left: 20px;"> + <label for="create_group" class="col-xs-3" style="float: left; font-size: 18px;"></label> + <div class="controls input-append col-xs-9" style="display: flex; padding-left: 20px; float: left;"> + <div class="col-xs-6"> + <button type="button" id="create_group" class="btn btn-primary">Create Group</button> + </div> + </div> + </div> + </div> + </fieldset> + </form> + </div> + + + +<!-- End of body --> + +{% endblock %} + +{% block js %} + <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.js"></script> + <script language="javascript" type="text/javascript" src="/static/new/javascript/group_manager.js"></script> + <script language="javascript" type="text/javascript" src="/static/packages/underscore/underscore-min.js"></script> + + <script type="text/javascript" charset="utf-8"> + </script> +{% endblock %} diff --git a/wqflask/wqflask/templates/admin/group_manager.html b/wqflask/wqflask/templates/admin/group_manager.html index b7df1aad..23d8205a 100644 --- a/wqflask/wqflask/templates/admin/group_manager.html +++ b/wqflask/wqflask/templates/admin/group_manager.html @@ -1,15 +1,23 @@ {% extends "base.html" %} {% block title %}Group Manager{% endblock %} +{% block css %} + <link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='DataTables/css/jquery.dataTables.css') }}" /> + <link rel="stylesheet" type="text/css" href="/static/new/packages/DataTables/extensions/buttons.dataTables.css"> + <link rel="stylesheet" type="text/css" href="/static/new/css/show_trait.css" /> +{% endblock %} {% block content %} <!-- Start of body --> <div class="container"> <div class="page-header"> <h1>Manage Groups</h1> - <button type="button" id="remove_groups" class="btn btn-primary" data-url="/groups/remove">Remove Selected Groups</button> + <div style="display: inline;"> + <button type="button" id="create_group" class="btn btn-primary" data-url="/groups/create">Create Group</button> + <button type="button" id="remove_groups" class="btn btn-primary" data-url="/groups/remove">Remove Selected Groups</button> + </div> </div> <form id="groups_form" action="/groups/manage" method="POST"> <input type="hidden" name="selected_group_ids" value=""> - <div class="container" style="margin-bottom: 30px;"> + <div style="min-width: 800px; max-width: 1000px;"> {% if admin_groups|length == 0 and user_groups|length == 0 %} <h4>You currently aren't a member or admin of any groups.</h4> <br> @@ -20,7 +28,7 @@ {% if admin_groups|length == 0 %} <h4>You currently aren't the administrator of any groups.</h4> {% else %} - <table id="admin_groups" class="table table-hover" style="min-width: 800px; max-width: 1000px;"> + <table id="admin_groups" class="table-hover table-striped cell-border" style="float: left;"> <thead> <tr> <th></th> @@ -29,17 +37,19 @@ <th># Members</th> <th>Created</th> <th>Last Changed</th> + <th>Group ID</th> </tr> </thead> <tbody> {% for group in admin_groups %} <tr> <td><input type="checkbox" name="group_id" value="{{ group.id }}"></td> - <td>{{ loop.index }}</td> + <td align="right">{{ loop.index }}</td> <td>{{ group.name }}</td> - <td>{{ group.admins|length + group.users|length }}</td> + <td align="right">{{ group.admins|length + group.users|length }}</td> <td>{{ group.created_timestamp }}</td> <td>{{ group.changed_timestamp }}</td> + <td>{{ group.id }}</td> </tr> {% endfor %} </tbody> @@ -47,13 +57,13 @@ {% endif %} </div> <hr> - <div class="container"> + <div style="min-width: 800px; max-width: 1000px;"> <div><h3>User Groups</h3></div> <hr> {% if user_groups|length == 0 %} <h4>You currently aren't a member of any groups.</h4> {% else %} - <table id="user_groups" class="table table-hover" style="min-width: 800px; max-width: 1000px;"> + <table id="user_groups" class="table-hover table-striped cell-border" style="float: left;"> <thead> <tr> <th></th> @@ -88,48 +98,26 @@ {% endblock %} {% block js %} - <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.js"></script> <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTables/js/jquery.dataTables.min.js') }}"></script> - <script language="javascript" type="text/javascript" src="/static/packages/underscore/underscore-min.js"></script> - <script type="text/javascript" charset="utf-8"> $(document).ready( function () { - $('#admin_groups, #user_groups').dataTable( { - "drawCallback": function( settings ) { - $('#admin_groups tr').click(function(event) { - if (event.target.type !== 'checkbox') { - $(':checkbox', this).trigger('click'); - } - }); - }, - "columns": [ - { "type": "natural" }, - { "type": "natural" }, - { "type": "natural" }, - { "type": "natural" }, - { "type": "natural" }, - { "type": "natural" } - ], - "columnDefs": [ { - "targets": 0, - "orderable": false - } ], - "order": [[1, "asc" ]], - "sDom": "Ztr", - "iDisplayLength": -1, - "autoWidth": true, - "bDeferRender": true, - "bSortClasses": false, - "paging": false, - "orderClasses": true - } ); - + {% if admin_groups|length != 0 %} + $('#admin_groups').dataTable(); + {% endif %} + {% if user_groups|length != 0 %} + $('#user_groups').dataTable(); + {% endif %} submit_special = function(url) { $("#groups_form").attr("action", url); return $("#groups_form").submit(); }; + $("#create_group").on("click", function() { + url = $(this).data("url") + return submit_special(url) + }); + $("#remove_groups").on("click", function() { url = $(this).data("url") groups = [] diff --git a/wqflask/wqflask/templates/admin/manage_resource.html b/wqflask/wqflask/templates/admin/manage_resource.html new file mode 100644 index 00000000..a47f47ad --- /dev/null +++ b/wqflask/wqflask/templates/admin/manage_resource.html @@ -0,0 +1,92 @@ +{% extends "base.html" %} +{% block title %}Resource Manager{% endblock %} +{% block content %} +<!-- Start of body --> + <div class="container"> + <div class="page-header"> + <h1>Resource Manager</h1> + </div> + <form id="manage_resource" action="/resources/manage" method="POST"> + <input type="hidden" name="resource_id" value="{{ resource_id }}"> + <div class="col-xs-6" style="min-width: 600px; max-width: 800px;"> + <fieldset> + <div class="form-horizontal" style="width: 900px; margin-bottom: 50px;"> + <div class="form-group" style="padding-left: 20px;"> + <label for="group_name" class="col-xs-3" style="float: left; font-size: 18px;">Resource Name:</label> + <div class="controls input-append col-xs-9" style="display: flex; padding-left: 20px; float: left;"> + {{ resource_info.name }} + </div> + </div> + <div class="form-group" style="padding-left: 20px;"> + <label for="user_email" class="col-xs-3" style="float: left; font-size: 18px;">Open to Public:</label> + <div class="controls input-append col-xs-9" style="display: flex; padding-left: 20px; float: left;"> + <label class="radio-inline"> + <input type="radio" name="default_mask" value="True" checked=""> + Yes + </label> + <label class="radio-inline"> + <input type="radio" name="default_mask" value="False"> + No + </label> + </div> + </div> + <div class="form-group" style="padding-left: 20px;"> + <label class="col-xs-3" style="float: left; font-size: 18px;"></label> + <div class="controls input-append col-xs-9" style="display: flex; padding-left: 20px; float: left;"> + <button id="save_changes" class="btn btn-primary">Save Changes</button> + </div> + </div> + </div> + </fieldset> + </div> + <div class="col-xs-6" style="min-width: 600px; max-width: 800px;"> + <button id="add_group_to_resource" class="btn btn-primary" style="margin-bottom: 30px;" data-url="/resources/add_group">Add Group</button> + <br> + {% if group_masks|length > 0 %} + <h3>Current Group Permissions</h3> + <table> + <thead> + <tr> + <th>Name</th> + <th>Data</th> + <th>Metadata</th> + <th>Admin</th> + </tr> + </thead> + <tbody> + {% for key, value in group_masks.iteritems() %} + <tr> + <td>{{ value.name }}</td> + <td>{{ value.data }}</td> + <td>{{ value.metadata }}</td> + <td>{{ value.admin }}</td> + </tr> + {% endfor %} + </tbody> + </table> + {% else %} + <h3>No groups are currently added to this resource.</h3> + {% endif %} + </div> + </form> + </div> + + + +<!-- End of body --> + +{% endblock %} + +{% block js %} + <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.js"></script> + <script language="javascript" type="text/javascript" src="/static/new/javascript/group_manager.js"></script> + <script language="javascript" type="text/javascript" src="/static/packages/underscore/underscore-min.js"></script> + + <script type="text/javascript" charset="utf-8"> + $('#add_group_to_resource').click(function(){ + url = $(this).data("url"); + $('#manage_resource').attr("action", url) + $('#manage_resource').submit() + }) + </script> +{% endblock %} diff --git a/wqflask/wqflask/templates/admin/search_for_groups.html b/wqflask/wqflask/templates/admin/search_for_groups.html new file mode 100644 index 00000000..89eb11dd --- /dev/null +++ b/wqflask/wqflask/templates/admin/search_for_groups.html @@ -0,0 +1,64 @@ +{% extends "base.html" %} +{% block title %}Resource Manager{% endblock %} +{% block content %} +<!-- Start of body --> + <div class="container"> + <div class="page-header"> + <h1>Find Groups</h1> + </div> + <form id="find_groups" action="/resources/add_group" method="POST"> + <input type="hidden" name="resource_id" value="{{ resource_id }}"> + <div style="min-width: 600px; max-width: 800px;"> + <fieldset> + <div class="form-horizontal" style="width: 900px;"> + <div style="margin-bottom: 30px;"> + <h2>Search by:</h2> + </div> + <div class="form-group" style="padding-left: 20px;"> + <label for="group_name" class="col-xs-3" style="float: left; font-size: 18px;">Group ID:</label> + <div class="controls input-append col-xs-9" style="display: flex; padding-left: 20px; float: left;"> + <input name="group_id" type="text" value=""> + </div> + </div> + <div class="form-group" style="padding-left: 20px;"> + <label for="group_name" class="col-xs-3" style="float: left; font-size: 18px;">Group Name:</label> + <div class="controls input-append col-xs-9" style="display: flex; padding-left: 20px; float: left;"> + <input name="group_name" type="text" value=""> + </div> + </div> + <div class="form-group" style="padding-left: 20px;"> + <label for="user_name" class="col-xs-3" style="float: left; font-size: 18px;">User Name:</label> + <div class="controls input-append col-xs-9" style="display: flex; padding-left: 20px; float: left;"> + <input name="user_name" type="text" value=""> + </div> + </div> + <div class="form-group" style="padding-left: 20px;"> + <label for="user_email" class="col-xs-3" style="float: left; font-size: 18px;">User E-mail:</label> + <div class="controls input-append col-xs-9" style="display: flex; padding-left: 20px; float: left;"> + <input name="user_email" type="text" value=""> + </div> + </div> + <div class="form-group" style="padding-left: 20px;"> + <label class="col-xs-3" style="float: left; font-size: 18px;"></label> + <div class="controls input-append col-xs-9" style="display: flex; padding-left: 20px; float: left;"> + <button type="submit" id="find_groups" class="btn btn-primary">Search</button> + </div> + </div> + </div> + </fieldset> + </div> + </form> + </div> + +<!-- End of body --> + +{% endblock %} + +{% block js %} + <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.js"></script> + <script language="javascript" type="text/javascript" src="/static/new/javascript/group_manager.js"></script> + <script language="javascript" type="text/javascript" src="/static/packages/underscore/underscore-min.js"></script> + + <script type="text/javascript" charset="utf-8"> + </script> +{% endblock %} diff --git a/wqflask/wqflask/templates/admin/select_group_to_add.html b/wqflask/wqflask/templates/admin/select_group_to_add.html new file mode 100644 index 00000000..df70fb2f --- /dev/null +++ b/wqflask/wqflask/templates/admin/select_group_to_add.html @@ -0,0 +1,54 @@ +{% extends "base.html" %} +{% block title %}Matched Groups{% endblock %} +{% block css %} + <link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='DataTables/css/jquery.dataTables.css') }}" /> + <link rel="stylesheet" type="text/css" href="/static/new/packages/DataTables/extensions/buttons.dataTables.css"> + <link rel="stylesheet" type="text/css" href="/static/new/css/show_trait.css" /> +{% endblock %} +{% block content %} +<!-- Start of body --> + <div class="container"> + <h1>The following groups were found:</h1> + <br> + <form id="add_groups"> + <input type="hidden" name="resource_id" value="{{ resource_id }}"> + <div id="groups_list" style="min-width: 600px; max-width: 800px;"> + {% if group_list|length > 0 %} + <button type="submit" class="btn btn-primary" style="margin-bottom: 40px;">Add Selected Group</button> + <table id="groups_table" class="table-hover table-striped cell-border" style="float: left;"> + <thead> + <tr> + <th></th> + <th>Name</th> + <th>Created</th> + <th>Last Changed</th> + </tr> + </thead> + <tbody> + {% for group in group_list %} + <tr> + <td align="center" style="padding: 0px;"><input type="radio" name="selected_group" VALUE="{{ group.id }}"></td> + <td>{% if 'name' in group %}{{ group.name }}{% else %}N/A{% endif %}</td> + <td>{% if 'created_timestamp' in group %}{{ group.created_timestamp }}{% else %}N/A{% endif %}</td> + <td>{% if 'changed_timestamp' in group %}{{ group.changed_timestamp }}{% else %}N/A{% endif %}</td> + </tr> + {% endfor %} + </tbody> + </table> + {% else %} + <h2>No matching groups were found.</h2> + {% endif %} + </div> + </form> + </div> + +<!-- End of body --> + +{% endblock %} + +{% block js %} + <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTables/js/jquery.dataTables.min.js') }}"></script> + <script> + $('#groups_table').dataTable(); + </script> +{% endblock %} diff --git a/wqflask/wqflask/templates/new_security/not_authenticated.html b/wqflask/wqflask/templates/new_security/not_authenticated.html new file mode 100644 index 00000000..7d0d3060 --- /dev/null +++ b/wqflask/wqflask/templates/new_security/not_authenticated.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} +{% block title %}Authentication Needed{% endblock %} +{% block content %} + <div class="container"> + <div class="page-header"> + <h3>You lack the permissions to view this data.</h3> + </div> + <p>Please contact the data's owner or GN administrators if you believe you should have access to this data.</p> + </div> + +{% endblock %} \ No newline at end of file diff --git a/wqflask/wqflask/templates/show_trait_details.html b/wqflask/wqflask/templates/show_trait_details.html index 878b6ced..5c315878 100644 --- a/wqflask/wqflask/templates/show_trait_details.html +++ b/wqflask/wqflask/templates/show_trait_details.html @@ -248,6 +248,11 @@ <a target="_blank" href="http://gn1.genenetwork.org/webqtl/main.py?cmd=show&db={{ this_trait.dataset.name }}&probeset={{ this_trait.name }}"> <button type="button" id="view_in_gn1" class="btn btn-primary" title="View Trait in GN1">View in GN1</button> </a> + {% if resource_id %} + <a target="_blank" href="./resources/manage?resource_id={{ resource_id }}"> + <button type="button" id="edit_resource" class="btn btn-success" title="Edit Resource">Edit</button> + </a> + {% endif %} </div> </div> diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py index 24a4dcee..ee827ba3 100644 --- a/wqflask/wqflask/views.py +++ b/wqflask/wqflask/views.py @@ -30,6 +30,7 @@ import sqlalchemy from wqflask import app from flask import g, Response, request, make_response, render_template, send_from_directory, jsonify, redirect, url_for from wqflask import group_manager +from wqflask import resource_manager from wqflask import search_results from wqflask import export_traits from wqflask import gsearch @@ -89,13 +90,13 @@ def connect_db(): @app.before_request def check_access_permissions(): logger.debug("@app.before_request check_access_permissions") + available = True if "temp_trait" in request.args: if request.args['temp_trait'] == "True": pass else: if 'dataset' in request.args: dataset = create_dataset(request.args['dataset']) - logger.debug("USER:", Redis.hget("users")) if 'trait_id' in request.args: available = check_resource_availability(dataset, request.args['trait_id']) else: |