diff options
Diffstat (limited to 'wqflask')
22 files changed, 1516 insertions, 726 deletions
diff --git a/wqflask/base/data_set.py b/wqflask/base/data_set.py index 1457ba8d..92dc8615 100644 --- a/wqflask/base/data_set.py +++ b/wqflask/base/data_set.py @@ -486,25 +486,18 @@ class DatasetGroup(object): def datasets(group_name, this_group = None): key = "group_dataset_menu:v2:" + group_name - logger.debug("key is2:", key) dataset_menu = [] - logger.debug("[tape4] webqtlConfig.PUBLICTHRESH:", webqtlConfig.PUBLICTHRESH) - logger.debug("[tape4] type webqtlConfig.PUBLICTHRESH:", type(webqtlConfig.PUBLICTHRESH)) the_results = fetchall(''' (SELECT '#PublishFreeze',PublishFreeze.FullName,PublishFreeze.Name FROM PublishFreeze,InbredSet WHERE PublishFreeze.InbredSetId = InbredSet.Id and InbredSet.Name = '%s' - and PublishFreeze.public > %s - and PublishFreeze.confidentiality < 1 ORDER BY PublishFreeze.Id ASC) UNION (SELECT '#GenoFreeze',GenoFreeze.FullName,GenoFreeze.Name FROM GenoFreeze, InbredSet WHERE GenoFreeze.InbredSetId = InbredSet.Id - and InbredSet.Name = '%s' - and GenoFreeze.public > %s - and GenoFreeze.confidentiality < 1) + and InbredSet.Name = '%s') UNION (SELECT Tissue.Name, ProbeSetFreeze.FullName,ProbeSetFreeze.Name FROM ProbeSetFreeze, ProbeFreeze, InbredSet, Tissue @@ -512,12 +505,10 @@ def datasets(group_name, this_group = None): and ProbeFreeze.TissueId = Tissue.Id and ProbeFreeze.InbredSetId = InbredSet.Id and InbredSet.Name like %s - and ProbeSetFreeze.public > %s - and ProbeSetFreeze.confidentiality < 1 ORDER BY Tissue.Name, ProbeSetFreeze.OrderList DESC) - ''' % (group_name, webqtlConfig.PUBLICTHRESH, - group_name, webqtlConfig.PUBLICTHRESH, - "'" + group_name + "'", webqtlConfig.PUBLICTHRESH)) + ''' % (group_name, + group_name, + "'" + group_name + "'")) sorted_results = sorted(the_results, key=lambda kv: kv[0]) @@ -637,29 +628,25 @@ class DataSet(object): """ - try: if self.type == "ProbeSet": query_args = tuple(escape(x) for x in ( - str(webqtlConfig.PUBLICTHRESH), self.name, self.name, self.name)) self.id, self.name, self.fullname, self.shortname, self.data_scale, self.tissue = fetch1(""" -SELECT ProbeSetFreeze.Id, ProbeSetFreeze.Name, ProbeSetFreeze.FullName, ProbeSetFreeze.ShortName, ProbeSetFreeze.DataScale, Tissue.Name -FROM ProbeSetFreeze, ProbeFreeze, Tissue -WHERE ProbeSetFreeze.public > %s -AND ProbeSetFreeze.ProbeFreezeId = ProbeFreeze.Id -AND ProbeFreeze.TissueId = Tissue.Id -AND (ProbeSetFreeze.Name = '%s' OR ProbeSetFreeze.FullName = '%s' OR ProbeSetFreeze.ShortName = '%s') + SELECT ProbeSetFreeze.Id, ProbeSetFreeze.Name, ProbeSetFreeze.FullName, ProbeSetFreeze.ShortName, ProbeSetFreeze.DataScale, Tissue.Name + FROM ProbeSetFreeze, ProbeFreeze, Tissue + WHERE ProbeSetFreeze.ProbeFreezeId = ProbeFreeze.Id + AND ProbeFreeze.TissueId = Tissue.Id + AND (ProbeSetFreeze.Name = '%s' OR ProbeSetFreeze.FullName = '%s' OR ProbeSetFreeze.ShortName = '%s') """ % (query_args),"/dataset/"+self.name+".json", lambda r: (r["id"],r["name"],r["full_name"],r["short_name"],r["data_scale"],r["tissue"]) ) else: query_args = tuple(escape(x) for x in ( (self.type + "Freeze"), - str(webqtlConfig.PUBLICTHRESH), self.name, self.name, self.name)) @@ -668,9 +655,8 @@ AND (ProbeSetFreeze.Name = '%s' OR ProbeSetFreeze.FullName = '%s' OR ProbeSetFre self.id, self.name, self.fullname, self.shortname = fetchone(""" SELECT Id, Name, FullName, ShortName FROM %s - WHERE public > %s AND - (Name = '%s' OR FullName = '%s' OR ShortName = '%s') - """ % (query_args)) + WHERE (Name = '%s' OR FullName = '%s' OR ShortName = '%s') + """ % (query_args)) except TypeError: logger.debug("Dataset {} is not yet available in GeneNetwork.".format(self.name)) diff --git a/wqflask/base/trait.py b/wqflask/base/trait.py index 2a945588..7700ecd5 100644 --- a/wqflask/base/trait.py +++ b/wqflask/base/trait.py @@ -46,9 +46,10 @@ def create_trait(**kw): else: permitted = check_resource_availability(dataset) - if permitted: + if permitted != "no-access": the_trait = GeneralTrait(**kw) if the_trait.dataset.type != "Temp": + the_trait = retrieve_trait_info(the_trait, the_trait.dataset, get_qtl_info=kw.get('get_qtl_info')) return the_trait else: @@ -383,7 +384,6 @@ def retrieve_trait_info(trait, dataset, get_qtl_info=False): if dataset.type == 'Publish': the_url = "http://localhost:8080/run-action?resource={}&user={}&branch=data&action=view".format(resource_id, g.user_session.user_id) else: - the_url = "http://localhost:8080/run-action?resource={}&user={}&branch=data&action=view&trait={}".format(resource_id, g.user_session.user_id, trait.name) try: @@ -424,7 +424,6 @@ def retrieve_trait_info(trait, dataset, get_qtl_info=False): logger.sql(query) trait_info = g.db.execute(query).fetchone() - #XZ, 05/08/2009: Xiaodong add this block to use ProbeSet.Id to find the probeset instead of just using ProbeSet.Name #XZ, 05/08/2009: to avoid the problem of same probeset name from different platforms. elif dataset.type == 'ProbeSet': diff --git a/wqflask/maintenance/set_resource_defaults.py b/wqflask/maintenance/set_resource_defaults.py index ba102d9c..344e6a23 100644 --- a/wqflask/maintenance/set_resource_defaults.py +++ b/wqflask/maintenance/set_resource_defaults.py @@ -1,155 +1,154 @@ -""" - -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() +""" + +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): + 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": "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): + resource_ob = {} + resource_ob['name'] = resource[1] + if resource[1] == "HET3-ITPGeno": + resource_ob['owner_id'] = "73a3f093-ca13-4ae0-a179-9a446f709f6e" + else: + 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 index 537881a5..07ceacc0 100644 --- a/wqflask/utility/authentication_tools.py +++ b/wqflask/utility/authentication_tools.py @@ -1,46 +1,86 @@ -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 +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) + + response = None + if resource_id: + resource_info = get_resource_info(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: + response = resource_info['default_mask']['data'] + + if 'edit' in response: + return "edit" + elif 'view' in response: + return "view" + else: + return "no-access" + + return False + +def check_admin(resource_id=None): + + return "not-admin" + + # ZS: commented out until proxy can return this + # 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) + # except: + # response = resource_info['default_mask']['admin'] + + # if 'edit-admins' in response: + # return "edit-admins" + # elif 'edit-access' in response: + # return "edit-access" + # else: + # return "not-admin" + +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 + +def check_owner_or_admin(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, "owner"] + else: + return [resource_id, check_admin(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, "owner"] + else: + return [resource_id, check_admin(resource_id)] + + return [resource_id, "not-admin"] \ No newline at end of file diff --git a/wqflask/utility/redis_tools.py b/wqflask/utility/redis_tools.py index bc30a0af..c6d221ff 100644 --- a/wqflask/utility/redis_tools.py +++ b/wqflask/utility/redis_tools.py @@ -16,7 +16,7 @@ from utility.logger import getLogger logger = getLogger(__name__) def get_redis_conn(): - Redis = redis.StrictRedis(port=6380) + Redis = redis.StrictRedis(port=6379) return Redis Redis = get_redis_conn() @@ -51,6 +51,27 @@ def get_user_by_unique_column(column_name, column_value): return item_details +def get_users_like_unique_column(column_name, column_value): + """ + Like previous function, but this only checks if the input is a subset of a field and can return multiple results + """ + matched_users = [] + + if column_value != "": + user_list = Redis.hgetall("users") + if column_name != "user_id": + for key in user_list: + user_ob = json.loads(user_list[key]) + if column_name in user_ob: + if column_value in user_ob[column_name]: + matched_users.append(user_ob) + else: + matched_users.append(json.loads(user_list[column_value])) + + return matched_users + +# def search_users_by_unique_column(column_name, column_value): + def set_user_attribute(user_id, column_name, column_value): user_info = json.loads(Redis.hget("users", user_id)) user_info[column_name] = column_value @@ -142,6 +163,28 @@ def get_group_by_unique_column(column_name, column_value): return matched_groups +def get_groups_like_unique_column(column_name, column_value): + """ + Like previous function, but this only checks if the input is a subset of a field and can return multiple results + """ + matched_groups = [] + + if column_value != "": + group_list = Redis.hgetall("groups") + if column_name != "group_id": + for key in group_list: + group_info = json.loads(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 column_name in group_info: + if column_value in group_info[column_name]: + matched_groups.append(group_info) + else: + matched_groups.append(json.loads(group_list[column_value])) + + return matched_groups def create_group(admin_user_ids, member_user_ids = [], group_name = "Default Group Name"): group_id = str(uuid.uuid4()) @@ -192,9 +235,13 @@ def add_users_to_group(user_id, group_id, user_emails = [], admins = False): #ZS def remove_users_from_group(user_id, users_to_remove_ids, group_id, user_type = "members"): #ZS: User type is because I assume admins can remove other admins group_info = get_group_info(group_id) + if user_id in group_info["admins"]: + users_to_remove_set = set(users_to_remove_ids) + if user_type == "admins" and user_id in users_to_remove_set: #ZS: Make sure an admin can't remove themselves from a group, since I imagine we don't want groups to be able to become admin-less + users_to_remove_set.remove(user_id) group_users = set(group_info[user_type]) - group_users -= set(users_to_remove_ids) + group_users -= users_to_remove_set group_info[user_type] = list(group_users) group_info["changed_timestamp"] = datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p') Redis.hset("groups", group_id, json.dumps(group_info)) @@ -232,7 +279,6 @@ def get_resource_info(resource_id): return json.loads(resource_info) def add_resource(resource_info): - if 'trait' in resource_info['data']: resource_id = hmac.hmac_creation('{}:{}:{}'.format(str(resource_info['type']), str(resource_info['data']['dataset']), str(resource_info['data']['trait']))) else: @@ -241,3 +287,18 @@ def add_resource(resource_info): Redis.hset("resources", resource_id, json.dumps(resource_info)) return resource_info + +def add_access_mask(resource_id, group_id, access_mask): + the_resource = get_resource_info(resource_id) + the_resource['group_masks'][group_id] = access_mask + + Redis.hset("resources", resource_id, json.dumps(the_resource)) + + return the_resource + +def change_resource_owner(resource_id, new_owner_id): + the_resource= get_resource_info(resource_id) + the_resource['owner_id'] = new_owner_id + + Redis.delete("resource") + Redis.hset("resources", resource_id, json.dumps(the_resource)) \ No newline at end of file diff --git a/wqflask/wqflask/docs.py b/wqflask/wqflask/docs.py index 0187f32e..78407e22 100644 --- a/wqflask/wqflask/docs.py +++ b/wqflask/wqflask/docs.py @@ -1,5 +1,7 @@ from __future__ import absolute_import, print_function, division +import codecs + from flask import g from utility.logger import getLogger @@ -20,7 +22,7 @@ class Docs(object): self.content = "" else: self.title = result[0] - self.content = result[1] + self.content = result[1].encode("latin1") self.editable = "false" # ZS: Removing option to edit to see if text still gets vandalized diff --git a/wqflask/wqflask/group_manager.py b/wqflask/wqflask/group_manager.py index f41ae56d..9afc016b 100644 --- a/wqflask/wqflask/group_manager.py +++ b/wqflask/wqflask/group_manager.py @@ -1,77 +1,145 @@ - -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") - + +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, get_resources, get_resource_info + +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/view", methods=('GET', 'POST')) +def view_group(): + params = request.form if request.form else request.args + group_id = params['id'] + group_info = get_group_info(group_id) + admins_info = [] + user_is_admin = False + if g.user_session.user_id in group_info['admins']: + user_is_admin = True + for user_id in group_info['admins']: + if user_id: + user_info = get_user_by_unique_column("user_id", user_id) + admins_info.append(user_info) + members_info = [] + for user_id in group_info['members']: + if user_id: + user_info = get_user_by_unique_column("user_id", user_id) + members_info.append(user_info) + + #ZS: This whole part might not scale well with many resources + resources_info = [] + all_resources = get_resources() + for resource_id in all_resources: + resource_info = get_resource_info(resource_id) + group_masks = resource_info['group_masks'] + if group_id in group_masks: + this_resource = {} + privileges = group_masks[group_id] + this_resource['id'] = resource_id + this_resource['name'] = resource_info['name'] + this_resource['data'] = privileges['data'] + this_resource['metadata'] = privileges['metadata'] + this_resource['admin'] = privileges['admin'] + resources_info.append(this_resource) + + return render_template("admin/view_group.html", group_info=group_info, admins=admins_info, members=members_info, user_is_admin=user_is_admin, resources=resources_info) + +@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/remove_users", methods=('POST',)) +def remove_users(): + group_id = request.form['group_id'] + admin_ids_to_remove = request.form['selected_admin_ids'] + member_ids_to_remove = request.form['selected_member_ids'] + + remove_users_from_group(g.user_session.user_id, admin_ids_to_remove.split(":"), group_id, user_type="admins") + remove_users_from_group(g.user_session.user_id, member_ids_to_remove.split(":"), group_id, user_type="members") + + return redirect(url_for('view_group', id=group_id)) + +@app.route("/groups/add_<path:user_type>", methods=('POST',)) +def add_users(user_type='members'): + group_id = request.form['group_id'] + if user_type == "admins": + user_emails = request.form['admin_emails_to_add'].split(",") + add_users_to_group(g.user_session.user_id, group_id, user_emails, admins = True) + elif user_type == "members": + user_emails = request.form['member_emails_to_add'].split(",") + add_users_to_group(g.user_session.user_id, group_id, user_emails, admins = False) + + return redirect(url_for('view_group', id=group_id)) + +@app.route("/groups/change_name", methods=('POST',)) +def change_name(): + group_id = request.form['group_id'] + new_name = request.form['new_name'] + group_info = change_group_name(g.user_session.user_id, group_id, new_name) + + return new_name + +@app.route("/groups/create", methods=('GET', 'POST')) +def add_or_edit_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_to_add" 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 "member_emails_to_add" 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 index 7d88b8ed..0f9f5c9d 100644 --- a/wqflask/wqflask/resource_manager.py +++ b/wqflask/wqflask/resource_manager.py @@ -1,72 +1,134 @@ -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 - +from __future__ import print_function, division, absolute_import + +import json + +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_or_admin +from utility.redis_tools import get_resource_info, get_group_info, get_groups_like_unique_column, get_user_id, get_user_by_unique_column, get_users_like_unique_column, add_access_mask, add_resource, change_resource_owner + +from utility.logger import getLogger +logger = getLogger(__name__) + +@app.route("/resources/manage", methods=('GET', 'POST')) +def manage_resource(): + params = request.form if request.form else request.args + if 'resource_id' in request.args: + resource_id = request.args['resource_id'] + admin_status = check_owner_or_admin(resource_id=resource_id)[1] + + 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'] + owner_id = resource_info['owner_id'] + owner_info = get_user_by_unique_column("user_id", owner_id) + + if 'name' in owner_info: + owner_display_name = owner_info['full_name'] + elif 'user_name' in owner_info: + owner_display_name = owner_info['user_name'] + elif 'email_address' in owner_info: + owner_display_name = owner_info['email_address'] + else: + owner_display_name = None + + return render_template("admin/manage_resource.html", owner_name = owner_display_name, resource_id = resource_id, resource_info=resource_info, default_mask=default_mask, group_masks=group_masks_with_names, admin_status=admin_status) + +@app.route("/search_for_users", methods=('POST',)) +def search_for_user(): + params = request.form + user_list = [] + user_list += get_users_like_unique_column("full_name", params['user_name']) + user_list += get_users_like_unique_column("email_address", params['user_email']) + + return json.dumps(user_list) + +@app.route("/search_for_groups", methods=('POST',)) +def search_for_groups(): + params = request.form + group_list = [] + group_list += get_groups_like_unique_column("id", params['group_id']) + group_list += get_groups_like_unique_column("name", params['group_name']) + + user_list = [] + user_list += get_users_like_unique_column("full_name", params['user_name']) + user_list += get_users_like_unique_column("email_address", params['user_email']) + for user in user_list: + group_list += get_groups_like_unique_column("admins", user['user_id']) + group_list += get_groups_like_unique_column("members", user['user_id']) + + return json.dumps(group_list) + +@app.route("/resources/change_owner", methods=('POST',)) +def change_owner(): + resource_id = request.form['resource_id'] + if 'new_owner' in request.form: + admin_status = check_owner_or_admin(resource_id=resource_id)[1] + if admin_status == "owner": + new_owner_id = request.form['new_owner'] + change_resource_owner(resource_id, new_owner_id) + flash("The resource's owner has beeen changed.", "alert-info") + return redirect(url_for("manage_resource", resource_id=resource_id)) + else: + flash("You lack the permissions to make this change.", "error") + return redirect(url_for("manage_resource", resource_id=resource_id)) + else: + return render_template("admin/change_resource_owner.html", resource_id = resource_id) + +@app.route("/resources/change_default_privileges", methods=('POST',)) +def change_default_privileges(): + resource_id = request.form['resource_id'] + admin_status = check_owner_or_admin(resource_id=resource_id) + if admin_status == "owner" or admin_status == "edit-admins": + resource_info = get_resource_info(resource_id) + default_mask = resource_info['default_mask'] + if request.form['open_to_public'] == "True": + default_mask['data'] = 'view' + else: + default_mask['data'] = 'no-access' + resource_info['default_mask'] = default_mask + add_resource(resource_info) + flash("Your changes have been saved.", "alert-info") + return redirect(url_for("manage_resource", resource_id=resource_id)) + 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'] + admin_status = check_owner_or_admin(resource_id=resource_id)[1] + if admin_status == "owner" or admin_status == "edit-admins" or admin_status == "edit-access": + if 'selected_group' in request.form: + group_id = request.form['selected_group'] + resource_info = get_resource_info(resource_id) + default_privileges = resource_info['default_mask'] + return render_template("admin/set_group_privileges.html", resource_id = resource_id, group_id = group_id, default_privileges = default_privileges) + elif all(key in request.form for key in ('data_privilege', 'metadata_privilege', 'admin_privilege')): + group_id = request.form['group_id'] + group_name = get_group_info(group_id)['name'] + access_mask = { + 'data': request.form['data_privilege'], + 'metadata': request.form['metadata_privilege'], + 'admin': request.form['admin_privilege'] + } + add_access_mask(resource_id, group_id, access_mask) + flash("Privileges have been added for group {}.".format(group_name), "alert-info") + return redirect(url_for("manage_resource", resource_id=resource_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 + group_masks_with_names[group_id] = this_mask + 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 index 5e82d104..4c172cbf 100644 --- a/wqflask/wqflask/static/new/javascript/group_manager.js +++ b/wqflask/wqflask/static/new/javascript/group_manager.js @@ -1,38 +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("") +$('#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().trim() + 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/static/new/javascript/search_results.js b/wqflask/wqflask/static/new/javascript/search_results.js index 8fa698b4..115dac13 100644 --- a/wqflask/wqflask/static/new/javascript/search_results.js +++ b/wqflask/wqflask/static/new/javascript/search_results.js @@ -296,7 +296,6 @@ $(function() { $("#deselect_all").click(deselect_all); $("#invert").click(invert); $("#add").click(add); - $("#remove").click(remove); $("#submit_bnw").click(submit_bnw); $("#export_traits").click(export_traits); $('.trait_checkbox, .btn').click(change_buttons); diff --git a/wqflask/wqflask/templates/admin/change_resource_owner.html b/wqflask/wqflask/templates/admin/change_resource_owner.html new file mode 100644 index 00000000..ae9409b0 --- /dev/null +++ b/wqflask/wqflask/templates/admin/change_resource_owner.html @@ -0,0 +1,116 @@ +{% extends "base.html" %} +{% block title %}Resource 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/css/show_trait.css" /> +{% endblock %} +{% block content %} +<!-- Start of body --> + <div class="container"> + <div class="page-header"> + <h1>Search for user to assign ownership to:</h1> + </div> + <form id="change_owner_form" action="/resources/change_owner" 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 for user by either name or e-mail:</h2> + </div> + <div class="form-group" style="padding-left: 20px;"> + <label for="user_name" class="col-xs-3" style="float: left; font-size: 18px;">User's 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's 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="button" id="find_users" class="btn btn-primary">Search</button> + <button style="margin-left: 20px; display: none;" type="submit" id="submit_new_owner" class="btn btn-success">Assign Ownership to Selected User</button> + </div> + </div> + </div> + </fieldset> + <hr> + <div id="user_results"> + </div> + </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 language="javascript"> + $('#find_users').click(function() { + $.ajax({ + method: "POST", + url: "/search_for_users", + data: { + user_name: $('input[name=user_name]').val(), + user_email: $('input[name=user_email]').val() + }, + success: populate_users + }); + }) + + populate_users = function(json_user_list){ + var user_list = JSON.parse(json_user_list) + + var the_html = "" + if (user_list.length > 0){ + the_html += "<table id='users_table' style='padding-top: 10px; width: 100%;' class='table-hover table-striped cell-border'>"; + the_html += "<thead><tr><th></th><th>Index</th><th>Name</th><th>E-mail Address</th><th>Organization</th></tr></thead>"; + the_html += "<tbody>"; + for (_i = 0, _len = user_list.length; _i < _len; _i++) { + this_user = user_list[_i] + the_html += "<tr>"; + the_html += "<td align='center' class='select_user'><input type='radio' name='new_owner' value='" + this_user.user_id + "'></td>"; + the_html += "<td>" + (_i + 1).toString() + "</td>" + if ("full_name" in this_user) { + the_html += "<td>" + this_user.full_name + "</td>"; + } else { + the_html += "<td>N/A</td>" + } + if ("email_address" in this_user) { + the_html += "<td>" + this_user.email_address + "</td>"; + } else { + the_html += "<td>N/A</td>" + } + if ("organization" in this_user) { + the_html += "<td>" + this_user.organization + "</td>"; + } else { + the_html += "<td>N/A</td>" + } + the_html += "</tr>" + } + the_html += "</tbody>"; + the_html += "</table>"; + } else { + the_html = "<span>No users were found matching the entered criteria.</span>" + } + + $('#user_results').html(the_html) + if (user_list.length > 0){ + $('#users_table').dataTable({ + 'order': [[1, "asc" ]], + 'sDom': 'tr' + }); + $('input[name=select_user]:eq(0)').prop("checked", true) + $('#submit_new_owner').css("display", "inline-block") + } + } + </script> +{% endblock %} diff --git a/wqflask/wqflask/templates/admin/create_group.html b/wqflask/wqflask/templates/admin/create_group.html index 55c3fa0b..5a6929fb 100644 --- a/wqflask/wqflask/templates/admin/create_group.html +++ b/wqflask/wqflask/templates/admin/create_group.html @@ -1,89 +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 %} +{% 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="submit" 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 23d8205a..70d55684 100644 --- a/wqflask/wqflask/templates/admin/group_manager.html +++ b/wqflask/wqflask/templates/admin/group_manager.html @@ -23,7 +23,7 @@ <br> <button type="submit" name="add_new_group" class="btn btn-primary">Create a new group</button> {% else %} - <div><h3>Admin Groups</h3></div> + <div style="margin-top: 20px;"><h2>Admin Groups</h2></div> <hr> {% if admin_groups|length == 0 %} <h4>You currently aren't the administrator of any groups.</h4> @@ -45,8 +45,8 @@ <tr> <td><input type="checkbox" name="group_id" value="{{ group.id }}"></td> <td align="right">{{ loop.index }}</td> - <td>{{ group.name }}</td> - <td align="right">{{ group.admins|length + group.users|length }}</td> + <td><a href="/groups/view?id={{ group.id }}">{{ group.name }}</a></td> + <td align="right">{{ group.admins|length + group.members|length }}</td> <td>{{ group.created_timestamp }}</td> <td>{{ group.changed_timestamp }}</td> <td>{{ group.id }}</td> @@ -58,7 +58,7 @@ </div> <hr> <div style="min-width: 800px; max-width: 1000px;"> - <div><h3>User Groups</h3></div> + <div><h2>User Groups</h2></div> <hr> {% if user_groups|length == 0 %} <h4>You currently aren't a member of any groups.</h4> @@ -80,7 +80,7 @@ <td><input type="checkbox" name="read" value="{{ group.id }}"></td> <td>{{ loop.index }}</td> <td>{{ group.name }}</td> - <td>{{ group.admins|length + group.users|length }}</td> + <td>{{ group.admins|length + group.members|length }}</td> <td>{{ group.created_timestamp }}</td> <td>{{ group.changed_timestamp }}</td> </tr> @@ -103,10 +103,14 @@ <script type="text/javascript" charset="utf-8"> $(document).ready( function () { {% if admin_groups|length != 0 %} - $('#admin_groups').dataTable(); + $('#admin_groups').dataTable({ + 'sDom': 'tr' + }); {% endif %} {% if user_groups|length != 0 %} - $('#user_groups').dataTable(); + $('#user_groups').dataTable({ + 'sDom': 'tr' + }); {% endif %} submit_special = function(url) { $("#groups_form").attr("action", url); diff --git a/wqflask/wqflask/templates/admin/manage_resource.html b/wqflask/wqflask/templates/admin/manage_resource.html index a47f47ad..0b12eaae 100644 --- a/wqflask/wqflask/templates/admin/manage_resource.html +++ b/wqflask/wqflask/templates/admin/manage_resource.html @@ -1,92 +1,108 @@ -{% 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 %} +{% extends "base.html" %} +{% block title %}Resource 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/css/show_trait.css" /> +{% endblock %} +{% block content %} +<!-- Start of body --> + <div class="container"> + {{ flash_me() }} + <div class="page-header" style="display: inline-block;"> + <h1>Resource Manager</h1> + <h3>{% if owner_name is not none %}Current Owner: {{ owner_name }}{% endif %} {% if admin_status == "owner" %}<button id="change_owner" class="btn btn-danger" data-url="/resources/change_owner" style="margin-left: 20px;">Change Owner</button>{% endif %}</h3> + </div> + <form id="manage_resource" action="/resources/manage" 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; 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> + {% if admin_status == "owner" %} + <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="open_to_public" value="True" {% if default_mask != 'no-access' %}checked{% endif %}> + Yes + </label> + <label class="radio-inline"> + <input type="radio" name="open_to_public" value="False" {% if default_mask == 'no-access' %}checked{% endif %}> + 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" data-url="/resources/change_default_privileges">Save Changes</button> + </div> + </div> + {% endif %} + </div> + </fieldset> + </div> + {% if admin_status == "owner" or admin_status == "edit-admins" or admin_status == "edit-access" %} + <div style="min-width: 600px; max-width: 800px;"> + <hr> + <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 %} + <h2>Current Group Permissions</h2> + <hr> + <table id="groups_table" class="table-hover table-striped cell-border"> + <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> + {% endif %} + </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 type="text/javascript" charset="utf-8"> + $('#add_group_to_resource, #save_changes, #change_owner').click(function(){ + url = $(this).data("url"); + $('#manage_resource').attr("action", url) + $('#manage_resource').submit() + }) + + {% if group_masks|length > 0 %} + $('#groups_table').dataTable({ + 'sDom': 'tr', + }); + {% endif %} + </script> +{% endblock %} diff --git a/wqflask/wqflask/templates/admin/search_for_groups.html b/wqflask/wqflask/templates/admin/search_for_groups.html index 89eb11dd..f304a172 100644 --- a/wqflask/wqflask/templates/admin/search_for_groups.html +++ b/wqflask/wqflask/templates/admin/search_for_groups.html @@ -1,64 +1,134 @@ -{% 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 %} +{% extends "base.html" %} +{% block title %}Resource 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/css/show_trait.css" /> +{% endblock %} +{% block content %} +<!-- Start of body --> + <div class="container"> + <div class="page-header"> + <h1>Find Groups</h1> + </div> + <form id="add_group" 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="button" id="find_groups" class="btn btn-primary">Search</button> + <button style="margin-left: 20px; display: none;" type="submit" id="submit_group" class="btn btn-success">Add Privileges for Selected Group</button> + </div> + </div> + </div> + </fieldset> + <hr> + <div id="group_results"> + </div> + </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="{{ url_for('js', filename='DataTables/js/jquery.dataTables.min.js') }}"></script> + + <script type="text/javascript" charset="utf-8"> + + $('#find_groups').click(function() { + $.ajax({ + method: "POST", + url: "/search_for_groups", + data: { + group_id: $('input[name=group_id]').val(), + group_name: $('input[name=group_name]').val(), + user_name: $('input[name=user_name]').val(), + user_email: $('input[name=user_email]').val() + }, + success: populate_groups + }); + }) + + populate_groups = function(json_group_list){ + console.log(json_group_list) + var group_list = JSON.parse(json_group_list) + + var the_html = "" + if (group_list.length > 0){ + the_html += "<table id='groups_table' style='padding-top: 10px; width: 100%;' class='table-hover table-striped cell-border'>"; + the_html += "<thead><tr><th></th><th>Index</th><th>Name</th><th># Admins</th><th># Members</th></tr></thead>"; + the_html += "<tbody>"; + for (_i = 0, _len = group_list.length; _i < _len; _i++) { + this_group = group_list[_i] + the_html += "<tr>"; + the_html += "<td align='center' class='select_group'><input type='radio' name='selected_group' value='" + this_group.id + "'></td>"; + the_html += "<td>" + (_i + 1).toString() + "</td>" + if ("name" in this_group) { + the_html += "<td>" + this_group.name + "</td>"; + } else { + the_html += "<td>N/A</td>" + } + if ("admins" in this_group) { + the_html += "<td>" + this_group.admins.length + "</td>"; + } else { + the_html += "<td>0</td>" + } + if ("members" in this_group) { + the_html += "<td>" + this_group.members.length + "</td>"; + } else { + the_html += "<td>0</td>" + } + the_html += "</tr>" + } + the_html += "</tbody>"; + the_html += "</table>"; + } else { + the_html = "<span>No groups were found matching the entered criteria.</span>" + } + + $('#group_results').html(the_html) + if (group_list.length > 0){ + $('#groups_table').dataTable({ + 'order': [[1, "asc" ]], + 'sDom': 'tr' + }); + $('input[name=selected_group]:eq(0)').prop("checked", true) + $('#submit_group').css("display", "inline-block") + } + } + </script> +{% endblock %} diff --git a/wqflask/wqflask/templates/admin/select_group_to_add.html b/wqflask/wqflask/templates/admin/select_group_to_add.html deleted file mode 100644 index df70fb2f..00000000 --- a/wqflask/wqflask/templates/admin/select_group_to_add.html +++ /dev/null @@ -1,54 +0,0 @@ -{% 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/admin/set_group_privileges.html b/wqflask/wqflask/templates/admin/set_group_privileges.html new file mode 100644 index 00000000..bc52788f --- /dev/null +++ b/wqflask/wqflask/templates/admin/set_group_privileges.html @@ -0,0 +1,102 @@ +{% extends "base.html" %} +{% block title %}Set Group Privileges{% 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>Group Privileges</h1> + <br> + <form id="set_group_privileges" action="/resources/add_group" method="POST"> + <input type="hidden" name="resource_id" value="{{ resource_id }}"> + <input type="hidden" name="group_id" value="{{ group_id }}"> + <div style="min-width: 600px; max-width: 800px;"> + <button type="submit" class="btn btn-primary" style="margin-bottom: 10px;">Add Group</button> + <hr> + <h2>Data and Metadata Privileges</h2> + <table id="data_privileges_table" class="table-hover table-striped cell-border" style="float: left;"> + <thead> + <tr> + <th></th> + <th>No-Access</th> + <th>View</th> + <th>Edit</th> + </tr> + </thead> + <tbody> + <tr> + <td>Data:</td> + {% if 'data' in default_privileges %} + <td align="center" style="padding: 0px;"><input type="radio" name="data_privilege" VALUE="no-access" {% if default_privileges.data == "no-access" %}checked{% endif %}></td> + <td align="center" style="padding: 0px;"><input type="radio" name="data_privilege" VALUE="view" {% if default_privileges.data == "view" %}checked{% endif %}></td> + <td align="center" style="padding: 0px;"><input type="radio" name="data_privilege" VALUE="edit" {% if default_privileges.data == "edit" %}checked{% endif %}></td> + {% else %} + <td align="center" style="padding: 0px;"><input type="radio" name="data_privilege" VALUE="no-access" checked></td> + <td align="center" style="padding: 0px;"><input type="radio" name="data_privilege" VALUE="view"></td> + <td align="center" style="padding: 0px;"><input type="radio" name="data_privilege" VALUE="edit"></td> + {% endif %} + </tr> + <tr> + <td>Metadata:</td> + {% if 'metadata' in default_privileges %} + <td align="center" style="padding: 0px;"><input type="radio" name="metadata_privilege" VALUE="no-access" {% if default_privileges.metadata == "no-access" %}checked{% endif %}></td> + <td align="center" style="padding: 0px;"><input type="radio" name="metadata_privilege" VALUE="view" {% if default_privileges.metadata == "view" %}checked{% endif %}></td> + <td align="center" style="padding: 0px;"><input type="radio" name="metadata_privilege" VALUE="edit" {% if default_privileges.metadata[-1] == "edit" %}checked{% endif %}></td> + {% else %} + <td align="center" style="padding: 0px;"><input type="radio" name="metadata_privilege" VALUE="no-access" checked></td> + <td align="center" style="padding: 0px;"><input type="radio" name="metadata_privilege" VALUE="view"></td> + <td align="center" style="padding: 0px;"><input type="radio" name="metadata_privilege" VALUE="edit"></td> + {% endif %} + </tr> + </tbody> + </table> + <hr> + <h2>Admin Privileges</h2> + <table id="admin_privileges_table" class="table-hover table-striped cell-border" style="float: left;"> + <thead> + <tr> + <th></th> + <th>Not Admin</th> + <th>Edit Access</th> + <th>Edit Admins</th> + </tr> + </thead> + <tbody> + <tr> + <td>Admin:</td> + {% if 'admin' in default_privileges %} + <td align="center" style="padding: 0px;"><input type="radio" name="admin_privilege" VALUE="not-admin" {% if default_privileges.admin == "not-admin" %}checked{% endif %}></td> + <td align="center" style="padding: 0px;"><input type="radio" name="admin_privilege" VALUE="edit-access" {% if default_privileges.admin == "edit-access" %}checked{% endif %}></td> + <td align="center" style="padding: 0px;"><input type="radio" name="admin_privilege" VALUE="edit-admins" {% if default_privileges.admin == "edit-admins" %}checked{% endif %}></td> + {% else %} + <td align="center" style="padding: 0px;"><input type="radio" name="admin_privilege" VALUE="not-admin" checked></td> + <td align="center" style="padding: 0px;"><input type="radio" name="admin_privilege" VALUE="edit-access"></td> + <td align="center" style="padding: 0px;"><input type="radio" name="admin_privilege" VALUE="edit-admins"></td> + {% endif %} + </tr> + </tbody> + </table> + </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> + $('#data_privileges_table').dataTable({ + 'sDom': 'tr', + 'bSort': false + }); + $('#admin_privileges_table').dataTable({ + 'sDom': 'tr', + 'bSort': false + }); + </script> +{% endblock %} diff --git a/wqflask/wqflask/templates/admin/view_group.html b/wqflask/wqflask/templates/admin/view_group.html new file mode 100644 index 00000000..b797cd70 --- /dev/null +++ b/wqflask/wqflask/templates/admin/view_group.html @@ -0,0 +1,238 @@ +{% extends "base.html" %} +{% block title %}View and Edit Group{% 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> + <span id="group_name">{{ group_info.name }}</span> + <input type="text" name="new_group_name" style="font-size: 20px; display: none; width: 500px;" class="form-control" placeholder="{{ group_info.name }}"> + <button class="btn btn-default" style="display: inline;" id="change_group_name">Change Group Name</button> + </h1> + {% if user_is_admin == true %} + <div style="display: inline;"> + <button type="button" id="remove_users" class="btn btn-danger" data-url="/groups/remove_users">Remove Selected Users from Group</button> + </div> + {% endif %} + </div> + <form id="group_form" action="/groups/view" method="POST"> + <input type="hidden" name="group_id" value="{{ group_info.id }}"> + <input type="hidden" name="selected_admin_ids" value=""> + <input type="hidden" name="selected_member_ids" value=""> + <div class="row"> + <div id="groups_div" class="col-xs-6" style="margin-right: 30px; min-width: 600px; max-width: 800px;"> + <div> + <div style="margin-top: 20px;"><h2>Admins</h2></div> + <hr> + <table id="group_admins" class="table-hover table-striped cell-border" style="float: left;"> + <thead> + <tr> + <th></th> + <th>Index</th> + <th>Name</th> + <th>Email Address</th> + <th>Organization</th> + </tr> + </thead> + <tbody> + {% for admin in admins %} + <tr> + <td style="text-align: center; padding: 0px 10px 2px 10px;"><input type="checkbox" name="admin_id" value="{{ admin.user_id }}"></td> + <td align="right">{{ loop.index }}</td> + <td>{% if 'full_name' in admin %}{{ admin.full_name }}{% else %}N/A{% endif %}</td> + <td>{% if 'email_address' in admin %}{{ admin.email_address }}{% else %}N/A{% endif %}</td> + <td>{% if 'organization' in admin %}{{ admin.organization }}{% else %}N/A{% endif %}</td> + </tr> + {% endfor %} + </tbody> + </table> + {% if user_is_admin == true %} + <div style="margin-top: 20px;"> + <span>E-mail of user to add to admins (multiple e-mails can be added separated by commas):</span> + <input type="text" size="60" name="admin_emails_to_add" placeholder="Enter E-mail(s)" value=""> + </div> + <div style="margin-bottom: 30px; margin-top: 20px;"> + <button type="button" id="add_admins" class="btn btn-primary" data-usertype="admin" data-url="/groups/add_admins">Add Admin(s)</button> + </div> + {% endif %} + </div> + <hr> + <div> + {% if members|length > 0 %} + <div><h2>Members</h2></div> + <hr> + <table id="group_members" class="table-hover table-striped cell-border" style="float: left;"> + <thead> + <tr> + <th></th> + <th>Index</th> + <th>Name</th> + <th>Email Address</th> + <th>Organization</th> + </tr> + </thead> + <tbody> + {% for member in members %} + <tr> + <td style="text-align: center; padding: 0px 10px 2px 10px;"><input type="checkbox" name="member_id" value="{{ member.user_id }}"></td> + <td align="right">{{ loop.index }}</td> + <td>{% if 'full_name' in member %}{{ member.full_name }}{% else %}N/A{% endif %}</td> + <td>{% if 'email_address' in member %}{{ member.email_address }}{% else %}N/A{% endif %}</td> + <td>{% if 'organization' in member %}{{ member.organization }}{% else %}N/A{% endif %}</td> + </tr> + {% endfor %} + </tbody> + </table> + {% if user_is_admin == true %} + <div style="margin-top: 20px;"> + <span>E-mail of user to add to members (multiple e-mails can be added separated by commas):</span> + <input type="text" size="60" name="member_emails_to_add" placeholder="Enter E-mail(s)" value=""> + </div> + <div style="margin-bottom: 30px; margin-top: 20px;"> + <button type="button" id="add_members" class="btn btn-primary" data-usertype="member" data-url="/groups/add_members">Add Member(s)</button> + </div> + {% endif %} + {% else %} + There are currently no members in this group. + {% endif %} + </div> + </div> + <div id="resources_div" class="col-xs-6" style="border-left: 1px solid #eee; margin-right: 30px; min-width: 600px; max-width: 800px;"> + <div style="margin-top: 20px;"><h2>Resources</h2></div> + <hr> + {% if resources|length > 0 %} + <table id="resources" class="table-hover table-striped cell-border" style="float: left;"> + <thead> + <tr> + <th>Index</th> + <th>Name</th> + <th>Data</th> + <th>Metadata</th> + <th>Admin</th> + </tr> + </thead> + <tbody> + {% for resource in resources %} + <tr> + <td align="right">{{ loop.index }}</td> + <td>{% if 'name' in resource %}<a href="/resources/manage?resource_id={{ resource.id }}">{{ resource.name }}</a>{% else %}N/A{% endif %}</td> + <td>{% if 'data' in resource %}{{ resource.data }}{% else %}N/A{% endif %}</td> + <td>{% if 'metadata' in resource %}{{ resource.metadata }}{% else %}N/A{% endif %}</td> + <td>{% if 'admin' in resource %}{{ resource.admin }}{% else %}N/A{% endif %}</td> + </tr> + {% endfor %} + </tbody> + </table> + {% else %} + There are currently no resources associated with this group. + {% endif %} + </div> + </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 type="text/javascript" charset="utf-8"> + $(document).ready( function () { + $('#group_admins').dataTable({ + 'order': [[1, "asc" ]], + 'columns': [ + { "type": "natural", "width": "25px"}, + { "type": "natural", "width": "30px" }, + { "type": "natural", "width": "150px" }, + { "type": "natural" }, + { "type": "natural" } + ], + 'sDom': 'tr' + }); + {% if members|length > 0 %} + $('#group_members').dataTable({ + 'order': [[1, "asc" ]], + 'columns': [ + { "type": "natural", "width": "25px"}, + { "type": "natural", "width": "30px" }, + { "type": "natural", "width": "150px" }, + { "type": "natural" }, + { "type": "natural" } + ], + 'sDom': 'tr' + }); + {% endif %} + {% if resources|length > 0 %} + $('#resources').dataTable({ + 'order': [[0, "asc" ]], + 'columns': [ + { "type": "natural", "width": "30px" }, + { "type": "natural", "width": "150px" }, + { "type": "natural" }, + { "type": "natural" }, + { "type": "natural" } + ], + 'sDom': 'tr' + }); + {% endif %} + + $('#resources_div').css('height', $('#groups_div').css('height')) + + submit_special = function(url) { + $("#group_form").attr("action", url); + return $("#group_form").submit(); + }; + + $("#remove_users").on("click", function() { + url = $(this).data("url"); + admins = []; + $("input[name=admin_id]:checked").each(function() { + admins.push($(this).val()); + }); + admins_string = admins.join(":") + $("input[name=selected_admin_ids]").val(admins_string) + + members = []; + $("input[name=member_id]:checked").each(function() { + members.push($(this).val()); + }); + members_string = members.join(":") + $("input[name=selected_member_ids]").val(members_string) + return submit_special(url) + }); + + $("#add_admins, #add_members").on("click", function() { + url = $(this).data("url"); + return submit_special(url) + }); + + $("#change_group_name").on("click", function() { + if ($('input[name=new_group_name]').css('display') == 'none') { + $('input[name=new_group_name]').css('display', 'inline'); + $('#group_name').css('display', 'none'); + } else { + new_name = $('input[name=new_group_name]').val() + $.ajax({ + type: "POST", + url: "/groups/change_name", + data: { + group_id: $('input[name=group_id]').val(), + new_name: new_name + } + }); + $('input[name=new_group_name]').css('display', 'none'); + $('input[name=group_name]').val(new_name); + $('#group_name').text(new_name) + $('#group_name').css('display', 'inline'); + } + }); + }); + </script> +{% endblock %} diff --git a/wqflask/wqflask/templates/base.html b/wqflask/wqflask/templates/base.html index 07c1b48e..262d9ee5 100644 --- a/wqflask/wqflask/templates/base.html +++ b/wqflask/wqflask/templates/base.html @@ -94,6 +94,11 @@ <a id="login_in" href="/n/login">Sign in</a> {% endif %} </li> + {% if g.user_session.logged_in %} + <li class=""> + <a id="manage_groups" title="Manage Groups" href="/groups/manage">Manage Groups</a> + </li> + {% endif %} {% endif %} <!-- <li style="margin-left: 20px;"> diff --git a/wqflask/wqflask/templates/set_group_privileges.html b/wqflask/wqflask/templates/set_group_privileges.html new file mode 100644 index 00000000..98b0cc12 --- /dev/null +++ b/wqflask/wqflask/templates/set_group_privileges.html @@ -0,0 +1,77 @@ +{% extends "base.html" %} +{% block title %}Set Group Privileges{% 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>Group Privileges</h1> + <br> + <form id="set_group_privileges"> + <input type="hidden" name="resource_id" value="{{ resource_id }}"> + <div style="min-width: 600px; max-width: 800px;"> + <button type="submit" class="btn btn-primary" style="margin-bottom: 40px;">Add Group</button> + <hr> + <h2>Data and Metadata Privileges</h2> + <table id="data_privileges_table" class="table-hover table-striped cell-border" style="float: left;"> + <thead> + <tr> + <th></th> + <th>No-Access</th> + <th>View</th> + <th>Edit</th> + </tr> + </thead> + <tbody> + <tr> + <td>Data:</td> + <td align="center" style="padding: 0px;"><input type="radio" name="data_privilege" VALUE="no-access" checked></td> + <td align="center" style="padding: 0px;"><input type="radio" name="data_privilege" VALUE="view"></td> + <td align="center" style="padding: 0px;"><input type="radio" name="data_privilege" VALUE="edit"></td> + </tr> + <tr> + <td>Metadata:</td> + <td align="center" style="padding: 0px;"><input type="radio" name="metadata_privilege" VALUE="no-access" checked></td> + <td align="center" style="padding: 0px;"><input type="radio" name="metadata_privilege" VALUE="view"></td> + <td align="center" style="padding: 0px;"><input type="radio" name="metadata_privilege" VALUE="edit"></td> + </tr> + </tbody> + </table> + <hr> + <h2>Admin Privileges</h2> + <table id="admin_privileges_table" class="table-hover table-striped cell-border" style="float: left;"> + <thead> + <tr> + <th></th> + <th>Not Admin</th> + <th>Edit Access</th> + <th>Edit Admins</th> + </tr> + </thead> + <tbody> + <tr> + <td>Admin:</td> + <td align="center" style="padding: 0px;"><input type="radio" name="admin_privilege" VALUE="not-admin" checked></td> + <td align="center" style="padding: 0px;"><input type="radio" name="admin_privilege" VALUE="edit-access"></td> + <td align="center" style="padding: 0px;"><input type="radio" name="admin_privilege" VALUE="edit-admins"></td> + </tr> + </tbody> + </table> + </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> + $('#data_privileges_table').dataTable(); + $('#admin_privileges_table').dataTable(); + </script> +{% endblock %} diff --git a/wqflask/wqflask/templates/show_trait_details.html b/wqflask/wqflask/templates/show_trait_details.html index 5c315878..5e0bae79 100644 --- a/wqflask/wqflask/templates/show_trait_details.html +++ b/wqflask/wqflask/templates/show_trait_details.html @@ -248,8 +248,8 @@ <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 }}"> + {% if admin_status[1] == "owner" or admin_status[1] == "edit-admins" or admin_status[1] == "edit-access" %} + <a target="_blank" href="./resources/manage?resource_id={{ admin_status[0] }}"> <button type="button" id="edit_resource" class="btn btn-success" title="Edit Resource">Edit</button> </a> {% endif %} diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py index ee827ba3..dc431aa9 100644 --- a/wqflask/wqflask/views.py +++ b/wqflask/wqflask/views.py @@ -102,7 +102,7 @@ def check_access_permissions(): else: available = check_resource_availability(dataset) - if not available: + if available == "no-access": return redirect(url_for("no_access_page")) @app.teardown_appcontext |