From 61c13a09dba95958f183dc55f3d59c8856b5f753 Mon Sep 17 00:00:00 2001 From: Pjotr Prins Date: Wed, 13 Feb 2019 12:41:45 +0000 Subject: Removed pylmm references and related functions --- wqflask/utility/tools.py | 4 ---- 1 file changed, 4 deletions(-) (limited to 'wqflask/utility/tools.py') diff --git a/wqflask/utility/tools.py b/wqflask/utility/tools.py index ea216a35..86ef2e1e 100644 --- a/wqflask/utility/tools.py +++ b/wqflask/utility/tools.py @@ -107,9 +107,6 @@ def js_path(module=None): return try_guix raise "No JS path found for "+module+" (if not in Guix check JS_GN_PATH)" -def pylmm_command(guess=None): - return assert_bin(get_setting("PYLMM_COMMAND",guess)) - def gemma_command(guess=None): return assert_bin(get_setting("GEMMA_COMMAND",guess)) @@ -276,7 +273,6 @@ SMTP_CONNECT = get_setting('SMTP_CONNECT') SMTP_USERNAME = get_setting('SMTP_USERNAME') SMTP_PASSWORD = get_setting('SMTP_PASSWORD') -PYLMM_COMMAND = app_set("PYLMM_COMMAND",pylmm_command()) GEMMA_COMMAND = app_set("GEMMA_COMMAND",gemma_command()) assert(GEMMA_COMMAND is not None) PLINK_COMMAND = app_set("PLINK_COMMAND",plink_command()) -- cgit v1.2.3 From 496759ad08efb02b4268ea7f3bbb7905974237e9 Mon Sep 17 00:00:00 2001 From: Pjotr Prins Date: Mon, 18 Feb 2019 09:39:41 +0000 Subject: Updated installation instructions and SERVER_PORT for single flask server --- doc/README.org | 71 ++++++++++++++++++++++++++++++++++-------------- wqflask/runserver.py | 8 ++++-- wqflask/utility/tools.py | 1 + 3 files changed, 57 insertions(+), 23 deletions(-) (limited to 'wqflask/utility/tools.py') diff --git a/doc/README.org b/doc/README.org index 5dc9e994..620c946c 100644 --- a/doc/README.org +++ b/doc/README.org @@ -12,13 +12,15 @@ - [[#load-the-small-database-in-mysql][Load the small database in MySQL]] - [[#gn2-dependency-graph][GN2 Dependency Graph]] - [[#working-with-the-gn2-source-code][Working with the GN2 source code]] + - [[#running-elasticsearch][Running ElasticSearch]] + - [[#systemd][SystemD]] + - [[#read-more][Read more]] - [[#trouble-shooting][Trouble shooting]] - [[#importerror-no-module-named-jinja2][ImportError: No module named jinja2]] - - [[#error-can-not-find-directory-homegn2_data][ERROR: can not find directory $HOME/gn2_data]] + - [[#error-can-not-find-directory-homegn2_data-or-can-not-find-directory-homegenotype_filesgenotype][ERROR: 'can not find directory $HOME/gn2_data' or 'can not find directory $HOME/genotype_files/genotype']] - [[#cant-run-a-module][Can't run a module]] - [[#rpy2-error-show-now-found][Rpy2 error 'show' now found]] - [[#mysql-cant-connect-server-through-socket-error][Mysql can't connect server through socket ERROR]] - - [[#read-more][Read more]] - [[#irc-session][IRC session]] * Introduction @@ -100,11 +102,13 @@ mysql (which comes as part of the GNU Guix genenetwork2 install). As root configure and run -: adduser mysql && addgroup mysql -: mysqld --datadir=/var/mysql --initialize-insecure -: mkdir -p /var/run/mysqld -: chown mysql.mysql ~/mysql /var/run/mysqld -: mysqld -u mysql --datadir=/var/mysql --explicit_defaults_for_timestamp -P 12048" +#+BEGIN_SRC bash +adduser mysql && addgroup mysql +mysqld --datadir=/var/mysql --initialize-insecure +mkdir -p /var/run/mysqld +chown mysql.mysql ~/mysql /var/run/mysqld +mysqld -u mysql --datadir=/var/mysql --explicit_defaults_for_timestamp -P 12048" +#+END_SRC If you want to run as root you may have to set @@ -192,6 +196,41 @@ http://biogems.info/contrib/genenetwork/gn2.svg See [[development.org]]. +* Running ElasticSearch + +In order to start up elasticsearch: +Penguin - change user to "elasticsearch" and use the following command: "env JAVA_HOME=/opt/jdk-9.0.4 /opt/elasticsearch-6.2.1/bin/elasticsearch" + + +** SystemD + +New server - as root run "systemctl restart elasticsearch" + +#+BEGIN_SRC +tux01:/etc/systemd/system# cat elasticsearch.service +[Unit] +Description=Run Elasticsearch + +[Service] +ExecStart=/opt/elasticsearch-6.2.1/bin/elasticsearch +Environment=JAVA_HOME=/opt/jdk-9.0.4 +Environment="ES_JAVA_OPTS=-Xms1g -Xmx8g" +Environment="PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/opt/jdk-9.0.4/bin" +LimitNOFILE=65536 +StandardOutput=syslog +StandardError=syslog +User=elasticsearch + +[Install] +WantedBy=multi-user.target +#+END_SRC + +* Read more + +If you want to understand the architecture of GN2 read +[[Architecture.org]]. The rest of this document is mostly on deployment +of GN2. + * Trouble shooting ** ImportError: No module named jinja2 @@ -210,13 +249,17 @@ On one system: : export GEM_PATH="$HOME/.guix-profile/lib/ruby/gems/2.2.0" and perhaps a few more. -** ERROR: can not find directory $HOME/gn2_data +** ERROR: 'can not find directory $HOME/gn2_data' or 'can not find directory $HOME/genotype_files/genotype' The default settings file looks in your $HOME/gn2_data. Since these files come with a Guix installation you should take a hint from the values in the installed version of default_settings.py (see above in this document). +You can use the GENENETWORK_FILES switch to set the datadir, for example + +: env GN2_PROFILE=~/opt/gn-latest GENENETWORK_FILES=/gnu/data/gn2_data ./bin/genenetwork2 + ** Can't run a module In rare cases, development modules are not brought in with Guix @@ -257,18 +300,6 @@ if that works run genenetwork after setting SQL_URI to something like : export SQL_URI=mysql://gn2:mysql_password@127.0.0.1/db_webqtl_s -* Running ElasticSearch - -In order to start up elasticsearch: -Penguin - change user to "elasticsearch" and use the following command: "env JAVA_HOME=/opt/jdk-9.0.4 /opt/elasticsearch-6.2.1/bin/elasticsearch" - -New server - as root run "systemctl restart elasticsearch" - -* Read more - -If you want to understand the architecture of GN2 read -[[Architecture.org]]. The rest of this document is mostly on deployment -of GN2. * IRC session diff --git a/wqflask/runserver.py b/wqflask/runserver.py index 5f41d04d..7c06356b 100644 --- a/wqflask/runserver.py +++ b/wqflask/runserver.py @@ -27,9 +27,11 @@ app_config() werkzeug_logger = logging.getLogger('werkzeug') +from utility.tools import WEBSERVER_MODE, SERVER_PORT + if WEBSERVER_MODE == 'DEBUG': app.run(host='0.0.0.0', - port=port, + port=SERVER_PORT, debug=True, use_debugger=False, threaded=False, @@ -38,7 +40,7 @@ if WEBSERVER_MODE == 'DEBUG': elif WEBSERVER_MODE == 'DEV': werkzeug_logger.setLevel(logging.WARNING) app.run(host='0.0.0.0', - port=port, + port=SERVER_PORT, debug=False, use_debugger=False, threaded=False, @@ -46,7 +48,7 @@ elif WEBSERVER_MODE == 'DEV': use_reloader=True) else: # staging/production modes app.run(host='0.0.0.0', - port=port, + port=SERVER_PORT, debug=False, use_debugger=False, threaded=True, diff --git a/wqflask/utility/tools.py b/wqflask/utility/tools.py index 86ef2e1e..8b2260f5 100644 --- a/wqflask/utility/tools.py +++ b/wqflask/utility/tools.py @@ -232,6 +232,7 @@ GN_VERSION = get_setting('GN_VERSION') HOME = get_setting('HOME') WEBSERVER_MODE = get_setting('WEBSERVER_MODE') GN_SERVER_URL = get_setting('GN_SERVER_URL') +SERVER_PORT = get_setting_int('SERVER_PORT') SQL_URI = get_setting('SQL_URI') LOG_LEVEL = get_setting('LOG_LEVEL') LOG_LEVEL_DEBUG = get_setting_int('LOG_LEVEL_DEBUG') -- cgit v1.2.3 From 5f5adb62bf13ace887c03522b0b8e83181cd6503 Mon Sep 17 00:00:00 2001 From: zsloan Date: Tue, 23 Jul 2019 11:24:56 -0500 Subject: Added change to automatically update datasets list using rest api instead of json file Removed option to edit certain html pages, like news, policies, etc --- etc/default_settings.py | 1 + wqflask/base/data_set.py | 4 +- wqflask/utility/tools.py | 4 ++ .../marker_regression/display_mapping_results.py | 1 - wqflask/wqflask/marker_regression/run_mapping.py | 17 +++++++- .../new/javascript/dataset_menu_structure.json | 51 ++++++++++++---------- wqflask/wqflask/templates/docs.html | 4 +- 7 files changed, 53 insertions(+), 29 deletions(-) (limited to 'wqflask/utility/tools.py') diff --git a/etc/default_settings.py b/etc/default_settings.py index a1fe81e5..a16ac3ad 100644 --- a/etc/default_settings.py +++ b/etc/default_settings.py @@ -91,4 +91,5 @@ JS_GN_PATH = os.environ['HOME']+"/genenetwork/javascript" # ---- GN2 Executables (overwrite for testing only) # PLINK_COMMAND = str.strip(os.popen("which plink2").read()) # GEMMA_COMMAND = str.strip(os.popen("which gemma").read()) +REAPER_COMMAND = HOME + "/gn2-zach/rust-qtlreaper/target/release/qtlreaper" # GEMMA_WRAPPER_COMMAND = str.strip(os.popen("which gemma-wrapper").read()) diff --git a/wqflask/base/data_set.py b/wqflask/base/data_set.py index d766e284..41de8492 100644 --- a/wqflask/base/data_set.py +++ b/wqflask/base/data_set.py @@ -46,6 +46,8 @@ from utility import chunks from utility import gen_geno_ob from utility.tools import locate, locate_ignore_error, flat_files +from wqflask.api import gen_menu + from maintenance import get_group_samplelists from MySQLdb import escape_string as escape @@ -92,7 +94,7 @@ Publish or ProbeSet. E.g. """ self.datasets = {} if USE_GN_SERVER: - data = menu_main() + data = gen_menu.gen_dropdown_json() else: file_name = "wqflask/static/new/javascript/dataset_menu_structure.json" with open(file_name, 'r') as fh: diff --git a/wqflask/utility/tools.py b/wqflask/utility/tools.py index 8b2260f5..31ab2046 100644 --- a/wqflask/utility/tools.py +++ b/wqflask/utility/tools.py @@ -107,6 +107,9 @@ def js_path(module=None): return try_guix raise "No JS path found for "+module+" (if not in Guix check JS_GN_PATH)" +def reaper_command(guess=None): + return get_setting("REAPER_COMMAND",guess) + def gemma_command(guess=None): return assert_bin(get_setting("GEMMA_COMMAND",guess)) @@ -274,6 +277,7 @@ SMTP_CONNECT = get_setting('SMTP_CONNECT') SMTP_USERNAME = get_setting('SMTP_USERNAME') SMTP_PASSWORD = get_setting('SMTP_PASSWORD') +REAPER_COMMAND = app_set("REAPER_COMMAND",reaper_command()) GEMMA_COMMAND = app_set("GEMMA_COMMAND",gemma_command()) assert(GEMMA_COMMAND is not None) PLINK_COMMAND = app_set("PLINK_COMMAND",plink_command()) diff --git a/wqflask/wqflask/marker_regression/display_mapping_results.py b/wqflask/wqflask/marker_regression/display_mapping_results.py index 3bcd613f..d9601405 100644 --- a/wqflask/wqflask/marker_regression/display_mapping_results.py +++ b/wqflask/wqflask/marker_regression/display_mapping_results.py @@ -1790,7 +1790,6 @@ class DisplayMappingResults(object): m = 0 thisLRSColor = self.colorCollection[0] if qtlresult['chr'] != previous_chr and self.selectedChr == -1: - if self.manhattan_plot != True: canvas.drawPolygon(LRSCoordXY,edgeColor=thisLRSColor,closed=0, edgeWidth=lrsEdgeWidth, clipX=(xLeftOffset, xLeftOffset + plotWidth)) diff --git a/wqflask/wqflask/marker_regression/run_mapping.py b/wqflask/wqflask/marker_regression/run_mapping.py index 2bde2b53..6e9fe85c 100644 --- a/wqflask/wqflask/marker_regression/run_mapping.py +++ b/wqflask/wqflask/marker_regression/run_mapping.py @@ -36,7 +36,7 @@ from utility import helper_functions from utility import Plot, Bunch from utility import temp_data from utility.benchmark import Bench -from wqflask.marker_regression import gemma_mapping, rqtl_mapping, qtlreaper_mapping, plink_mapping +from wqflask.marker_regression import gemma_mapping, rqtl_mapping, qtlreaper_mapping, plink_mapping, rust_reaper_mapping from utility.tools import locate, locate_ignore_error, GEMMA_COMMAND, PLINK_COMMAND, TEMPDIR from utility.external import shell @@ -242,7 +242,8 @@ class RunMapping(object): self.control_marker = start_vars['control_marker'] self.do_control = start_vars['do_control'] logger.info("Running qtlreaper") - results, self.json_data, self.perm_output, self.suggestive, self.significant, self.bootstrap_results = qtlreaper_mapping.gen_reaper_results(self.this_trait, + + results, self.perm_output, self.suggestive, self.significant, self.bootstrap_results = rust_reaper_mapping.run_reaper(self.this_trait, self.dataset, self.samples, self.vals, @@ -253,6 +254,18 @@ class RunMapping(object): self.do_control, self.control_marker, self.manhattan_plot) + + # results, self.json_data, self.perm_output, self.suggestive, self.significant, self.bootstrap_results = qtlreaper_mapping.gen_reaper_results(self.this_trait, + # self.dataset, + # self.samples, + # self.vals, + # self.json_data, + # self.num_perm, + # self.bootCheck, + # self.num_bootstrap, + # self.do_control, + # self.control_marker, + # self.manhattan_plot) elif self.mapping_method == "plink": self.score_type = "-log(p)" self.manhattan_plot = True diff --git a/wqflask/wqflask/static/new/javascript/dataset_menu_structure.json b/wqflask/wqflask/static/new/javascript/dataset_menu_structure.json index 0d73213d..6531f5a0 100644 --- a/wqflask/wqflask/static/new/javascript/dataset_menu_structure.json +++ b/wqflask/wqflask/static/new/javascript/dataset_menu_structure.json @@ -1440,7 +1440,7 @@ [ "None", "HSBPublish", - "HSB Phenotypes" + "HSB Published Phenotypes" ] ], "Posterior Inferior Parietal Cortex mRNA": [ @@ -1721,7 +1721,7 @@ [ "None", "B6D2Publish", - "B6D2 Phenotypes" + "UTHSC-Glaucoma-Aged-Retina Phenotypes" ] ] }, @@ -2247,6 +2247,11 @@ "Eye_M2_0908_R_ND", "Eye M430v2 WT Gpnmb (Sep08) RMA" ], + [ + "382", + "Eye_M2_0908_WTWT", + "Eye M430v2 WT WT (Sep08) RMA" + ], [ "279", "Eye_M2_0908_R_WT", @@ -2257,11 +2262,6 @@ "Eye_M2_0908_R_MT", "Eye M430v2 Mutant Tyrp1 (Sep08) RMA" ], - [ - "382", - "Eye_M2_0908_WTWT", - "Eye M430v2 WT WT (Sep08) RMA" - ], [ "400", "DBA2J-ONH-1212", @@ -2500,6 +2500,11 @@ "245", "UT_ILM_BXD_hipp_RSE_0909", "UTHSC Hippocampus Illumina v6.1 RSE (Sep09) RankInv" + ], + [ + "711", + "UTHSC_BXD_AgeHipp0515", + "UTHSC BXD Aged Hippocampus Affy MoGene1.0 ST (May15) RMA Gene Level" ] ], "Hypothalamus mRNA": [ @@ -3028,16 +3033,6 @@ ] ], "Striatum mRNA": [ - [ - "376", - "DevStriatum_ILM6.2P3RInv_1111", - "BIDMC/UTHSC Dev Striatum P3 ILMv6.2 (Nov11) RankInv" - ], - [ - "377", - "DevStriatum_ILM6.2P14RInv_1111", - "BIDMC/UTHSC Dev Striatum P14 ILMv6.2 (Nov11) RankInv" - ], [ "399", "Striatum_Exon_1212", @@ -3048,6 +3043,16 @@ "Striatum_Exon_0209", "HQF Striatum Affy Mouse Exon 1.0ST Exon Level (Dec09) RMA" ], + [ + "376", + "DevStriatum_ILM6.2P3RInv_1111", + "BIDMC/UTHSC Dev Striatum P3 ILMv6.2 (Nov11) RankInv" + ], + [ + "377", + "DevStriatum_ILM6.2P14RInv_1111", + "BIDMC/UTHSC Dev Striatum P14 ILMv6.2 (Nov11) RankInv" + ], [ "285", "UTHSC_Striatum_RankInv_1210", @@ -3554,6 +3559,11 @@ ] ], "Hippocampus mRNA": [ + [ + "211", + "Illum_LXS_Hipp_RSS_1008", + "Hippocampus Illumina RSS (Oct08) RankInv beta" + ], [ "213", "Illum_LXS_Hipp_NOS_1008", @@ -3574,11 +3584,6 @@ "Illum_LXS_Hipp_NOE_1008", "Hippocampus Illumina NOE (Oct08) RankInv beta" ], - [ - "211", - "Illum_LXS_Hipp_RSS_1008", - "Hippocampus Illumina RSS (Oct08) RankInv beta" - ], [ "143", "Illum_LXS_Hipp_loess0807", @@ -3835,7 +3840,7 @@ [ "None", "HSNIH-RGSMCPublish", - "HSNIH-RGSMC Phenotypes" + "HSNIH Published Phenotypes" ] ] }, diff --git a/wqflask/wqflask/templates/docs.html b/wqflask/wqflask/templates/docs.html index c485f757..1a241ce7 100644 --- a/wqflask/wqflask/templates/docs.html +++ b/wqflask/wqflask/templates/docs.html @@ -6,9 +6,9 @@

{{title}}

- + - +
{{content|safe}}
-- cgit v1.2.3 From 4bd1db34b109bff3b9abdcc161472885e9ae700d Mon Sep 17 00:00:00 2001 From: Pjotr Prins Date: Fri, 6 Sep 2019 03:29:12 -0500 Subject: Fix name of javascript-twitter-post-fetcher --- wqflask/utility/tools.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'wqflask/utility/tools.py') diff --git a/wqflask/utility/tools.py b/wqflask/utility/tools.py index 31ab2046..ec9f01bd 100644 --- a/wqflask/utility/tools.py +++ b/wqflask/utility/tools.py @@ -289,11 +289,14 @@ assert_dir(TEMPDIR) JS_GUIX_PATH = get_setting("JS_GUIX_PATH") assert_dir(JS_GUIX_PATH) assert_dir(JS_GUIX_PATH+'/cytoscape-panzoom') + CSS_PATH = "UNKNOWN" # assert_dir(JS_PATH) -JS_TWITTER_POST_FETCHER_PATH = get_setting("JS_TWITTER_POST_FETCHER_PATH",js_path("Twitter-Post-Fetcher")) + +JS_TWITTER_POST_FETCHER_PATH = get_setting("JS_TWITTER_POST_FETCHER_PATH",js_path("javascript-twitter-post-fetcher")) assert_dir(JS_TWITTER_POST_FETCHER_PATH) assert_file(JS_TWITTER_POST_FETCHER_PATH+"/js/twitterFetcher_min.js") + JS_CYTOSCAPE_PATH = get_setting("JS_CYTOSCAPE_PATH",js_path("cytoscape")) assert_dir(JS_CYTOSCAPE_PATH) assert_file(JS_CYTOSCAPE_PATH+'/cytoscape.min.js') -- cgit v1.2.3 From f9849394e3a252b5a1ac59c78a06728d20ca69ed Mon Sep 17 00:00:00 2001 From: zsloan Date: Tue, 3 Mar 2020 15:08:48 -0600 Subject: Refactored all the anonymous (not logged-in) user stuff so that both logged-in and anonymous users share the same code --- wqflask/utility/tools.py | 3 +- wqflask/wqflask/static/new/images/CITGLogo.png | Bin 0 -> 11962 bytes wqflask/wqflask/user_login.py | 467 +++++++++++++++++++++++++ wqflask/wqflask/user_session.py | 272 ++++++++++++++ wqflask/wqflask/views.py | 7 +- 5 files changed, 744 insertions(+), 5 deletions(-) create mode 100644 wqflask/wqflask/static/new/images/CITGLogo.png create mode 100644 wqflask/wqflask/user_login.py create mode 100644 wqflask/wqflask/user_session.py (limited to 'wqflask/utility/tools.py') diff --git a/wqflask/utility/tools.py b/wqflask/utility/tools.py index ec9f01bd..75bddb24 100644 --- a/wqflask/utility/tools.py +++ b/wqflask/utility/tools.py @@ -254,7 +254,6 @@ JS_GN_PATH = get_setting('JS_GN_PATH') GITHUB_CLIENT_ID = get_setting('GITHUB_CLIENT_ID') GITHUB_CLIENT_SECRET = get_setting('GITHUB_CLIENT_SECRET') -GITHUB_AUTH_URL = None if GITHUB_CLIENT_ID != 'UNKNOWN' and GITHUB_CLIENT_SECRET: GITHUB_AUTH_URL = "https://github.com/login/oauth/authorize?client_id=" + \ GITHUB_CLIENT_ID+"&client_secret="+GITHUB_CLIENT_SECRET @@ -264,7 +263,7 @@ ORCID_CLIENT_ID = get_setting('ORCID_CLIENT_ID') ORCID_CLIENT_SECRET = get_setting('ORCID_CLIENT_SECRET') ORCID_AUTH_URL = None if ORCID_CLIENT_ID != 'UNKNOWN' and ORCID_CLIENT_SECRET: - ORCID_AUTH_URL = "https://sandbox.orcid.org/oauth/authorize?response_type=code&scope=/authenticate&show_login=true&client_id=" + \ + ORCID_AUTH_URL = "https://orcid.org/oauth/authorize?response_type=code&scope=/authenticate&show_login=true&client_id=" + \ ORCID_CLIENT_ID+"&client_secret="+ORCID_CLIENT_SECRET ORCID_TOKEN_URL = get_setting('ORCID_TOKEN_URL') diff --git a/wqflask/wqflask/static/new/images/CITGLogo.png b/wqflask/wqflask/static/new/images/CITGLogo.png new file mode 100644 index 00000000..ae99fedb Binary files /dev/null and b/wqflask/wqflask/static/new/images/CITGLogo.png differ diff --git a/wqflask/wqflask/user_login.py b/wqflask/wqflask/user_login.py new file mode 100644 index 00000000..05885e2c --- /dev/null +++ b/wqflask/wqflask/user_login.py @@ -0,0 +1,467 @@ +from __future__ import print_function, division, absolute_import + +import os +import hashlib +import datetime +import time +import logging +import uuid +import hashlib +import hmac +import base64 +import requests + +import simplejson as json + +import redis # used for collections +Redis = redis.StrictRedis() + +from flask import (Flask, g, render_template, url_for, request, make_response, + redirect, flash, abort) + +from wqflask import app +from wqflask import pbkdf2 +from wqflask.hmac_func import hmac_creation +from wqflask.user_session import UserSession + +from utility.redis_tools import is_redis_available, get_user_id, get_user_by_unique_column, set_user_attribute, save_user, save_verification_code, check_verification_code, get_user_collections, save_collections + +from utility.logger import getLogger +logger = getLogger(__name__) + +from smtplib import SMTP +from utility.tools import SMTP_CONNECT, SMTP_USERNAME, SMTP_PASSWORD, LOG_SQL_ALCHEMY + +THREE_DAYS = 60 * 60 * 24 * 3 + +def timestamp(): + return datetime.datetime.utcnow().isoformat() + +def basic_info(): + return dict(timestamp = timestamp(), + ip_address = request.remote_addr, + user_agent = request.headers.get('User-Agent')) + +def encode_password(pass_gen_fields): + hashfunc = getattr(hashlib, pass_gen_fields['hashfunc']) + + salt = base64.b64decode(pass_gen_fields['salt']) + password = pbkdf2.pbkdf2_hex(str(pass_gen_fields['unencrypted_password']), + pass_gen_fields['salt'], + pass_gen_fields['iterations'], + pass_gen_fields['keylength'], + hashfunc) + + return password + +def set_password(password): + pass_gen_fields = { + "unencrypted_password": password, + "algorithm": "pbkdf2", + "hashfunc": "sha256", + "salt": base64.b64encode(os.urandom(32)), + "iterations": 100000, + "keylength": 32, + "created_timestamp": timestamp() + } + + assert len(password) >= 6, "Password shouldn't be shorter than 6 characters" + + encoded_password = encode_password(pass_gen_fields) + + return encoded_password + +def encrypt_password(unencrypted_password, pwfields): + hashfunc = getattr(hashlib, pwfields['hashfunc']) + salt = base64.b64decode(pwfields['salt']) + iterations = pwfields['iterations'] + keylength = pwfields['keylength'] + encrypted_password = pbkdf2.pbkdf2_hex(str(unencrypted_password), + salt, iterations, keylength, hashfunc) + return encrypted_password + +def get_signed_session_id(user): + session_id = str(uuid.uuid4()) + + session_id_signature = hmac_creation(session_id) + session_id_signed = session_id + ":" + session_id_signature + + #ZS: Need to check if this is ever actually used or exists + if 'user_id' not in user: + user['user_id'] = str(uuid.uuid4()) + save_user(user, user['user_id']) + + if 'github_id' in user: + session = dict(login_time = time.time(), + user_type = "github", + user_id = user['user_id'], + github_id = user['github_id'], + user_name = user['name'], + user_url = user['user_url']) + elif 'orcid' in user: + session = dict(login_time = time.time(), + user_type = "orcid", + user_id = user['user_id'], + github_id = user['orcid'], + user_name = user['name'], + user_url = user['user_url']) + else: + session = dict(login_time = time.time(), + user_type = "gn2", + user_id = user['user_id'], + user_name = user['full_name'], + user_email_address = user['email_address']) + + key = UserSession.user_cookie_name + ":" + session_id + Redis.hmset(key, session) + Redis.expire(key, THREE_DAYS) + + return session_id_signed + +def send_email(toaddr, msg, fromaddr="no-reply@genenetwork.org"): + """Send an E-mail through SMTP_CONNECT host. If SMTP_USERNAME is not + 'UNKNOWN' TLS is used + + """ + if SMTP_USERNAME == 'UNKNOWN': + server = SMTP(SMTP_CONNECT) + server.sendmail(fromaddr, toaddr, msg) + else: + server = SMTP(SMTP_CONNECT) + server.starttls() + server.login(SMTP_USERNAME, SMTP_PASSWORD) + server.sendmail(fromaddr, toaddr, msg) + server.quit() + logger.info("Successfully sent email to "+toaddr) + +def send_verification_email(user_details, template_name = "email/verification.txt", key_prefix = "verification_code", subject = "GeneNetwork email verification"): + verification_code = str(uuid.uuid4()) + key = key_prefix + ":" + verification_code + + data = json.dumps(dict(id=user_details['user_id'], timestamp = timestamp())) + + Redis.set(key, data) + Redis.expire(key, THREE_DAYS) + + recipient = user_details['email_address'] + body = render_template(template_name, verification_code = verification_code) + send_email(recipient, subject, body) + return {"recipient": recipient, "subject": subject, "body": body} + +@app.route("/n/login", methods=('GET', 'POST')) +def login(): + params = request.form if request.form else request.args + logger.debug("in login params are:", params) + + if not params: #ZS: If coming to page for first time + from utility.tools import GITHUB_AUTH_URL, GITHUB_CLIENT_ID, ORCID_AUTH_URL, ORCID_CLIENT_ID + external_login = {} + if GITHUB_AUTH_URL and GITHUB_CLIENT_ID != 'UNKNOWN': + external_login["github"] = GITHUB_AUTH_URL + if ORCID_AUTH_URL and ORCID_CLIENT_ID != 'UNKNOWN': + external_login["orcid"] = ORCID_AUTH_URL + return render_template("new_security/login_user.html", external_login = external_login, redis_is_available=is_redis_available()) + else: #ZS: After clicking sign-in + if 'type' in params and 'uid' in params: + user_details = get_user_by_unique_column("user_id", params['uid']) + if user_details: + session_id_signed = get_signed_session_id(user_details) + if 'name' in user_details and user_details['name'] != "None": + display_id = user_details['name'] + elif 'github_id' in user_details: + display_id = user_details['github_id'] + elif 'orcid' in user_details: + display_id = user_details['orcid'] + else: + display_id = "" + flash("Thank you for logging in {}.".format(display_id), "alert-success") + response = make_response(redirect(url_for('index_page'))) + response.set_cookie(UserSession.user_cookie_name, session_id_signed, max_age=None) + else: + flash("Something went unexpectedly wrong.", "alert-danger") + response = make_response(redirect(url_for('index_page'))) + return response + else: + user_details = get_user_by_unique_column("email_address", params['email_address']) + password_match = False + if user_details: + submitted_password = params['password'] + pwfields = json.loads(user_details['password']) + encrypted_pass = encrypt_password(submitted_password, pwfields) + password_match = pbkdf2.safe_str_cmp(encrypted_pass, pwfields['password']) + else: # Invalid e-mail + flash("Invalid e-mail address. Please try again.", "alert-danger") + response = make_response(redirect(url_for('login'))) + + return response + if password_match: # If password correct + if user_details['confirmed']: # If account confirmed + import_col = "false" + if 'import_collections' in params: + import_col = "true" + + session_id_signed = get_signed_session_id(user_details) + flash("Thank you for logging in {}.".format(user_details['full_name']), "alert-success") + response = make_response(redirect(url_for('index_page', import_collections = import_col))) + response.set_cookie(UserSession.user_cookie_name, session_id_signed, max_age=None) + return response + else: + email_ob = send_verification_email(user_details) + return render_template("newsecurity/verification_still_needed.html", subject=email_ob['subject']) + else: # Incorrect password + #ZS: It previously seemed to store that there was an incorrect log-in attempt here, but it did so in the MySQL DB so this might need to be reproduced with Redis + flash("Invalid password. Please try again.", "alert-danger") + response = make_response(redirect(url_for('login'))) + + return response + +@app.route("/n/login/github_oauth2", methods=('GET', 'POST')) +def github_oauth2(): + from utility.tools import GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, GITHUB_AUTH_URL + code = request.args.get("code") + data = { + "client_id": GITHUB_CLIENT_ID, + "client_secret": GITHUB_CLIENT_SECRET, + "code": code + } + logger.debug("LOGIN DATA:", data) + result = requests.post("https://github.com/login/oauth/access_token", json=data) + result_dict = {arr[0]:arr[1] for arr in [tok.split("=") for tok in [token.encode("utf-8") for token in result.text.split("&")]]} + + github_user = get_github_user_details(result_dict["access_token"]) + + user_details = get_user_by_unique_column("github_id", github_user["id"]) + if user_details == None: + user_details = { + "user_id": str(uuid.uuid4()), + "name": github_user["name"].encode("utf-8") if github_user["name"] else "None", + "github_id": github_user["id"], + "user_url": github_user["html_url"].encode("utf-8"), + "login_type": "github", + "organization": "", + "active": 1, + "confirmed": 1 + } + save_user(user_details, user_details["user_id"]) + + url = "/n/login?type=github&uid="+user_details["user_id"] + return redirect(url) + +def get_github_user_details(access_token): + from utility.tools import GITHUB_API_URL + result = requests.get(GITHUB_API_URL, headers = {'Authorization':'token ' + access_token }).content + + return json.loads(result) + +@app.route("/n/login/orcid_oauth2", methods=('GET', 'POST')) +def orcid_oauth2(): + from uuid import uuid4 + from utility.tools import ORCID_CLIENT_ID, ORCID_CLIENT_SECRET, ORCID_TOKEN_URL, ORCID_AUTH_URL + code = request.args.get("code") + error = request.args.get("error") + url = "/n/login" + if code: + data = { + "client_id": ORCID_CLIENT_ID, + "client_secret": ORCID_CLIENT_SECRET, + "grant_type": "authorization_code", + "code": code + } + result = requests.post(ORCID_TOKEN_URL, data=data) + result_dict = json.loads(result.text.encode("utf-8")) + + user_details = get_user_by_unique_column("orcid", result_dict["orcid"]) + if user_details == None: + user_details = { + "user_id": str(uuid4()), + "name": result_dict["name"], + "orcid": result_dict["orcid"], + "user_url": "%s/%s" % ("/".join(ORCID_AUTH_URL.split("/")[:-2]), result_dict["orcid"]), + "login_type": "orcid", + "organization": "", + "active": 1, + "confirmed": 1 + } + save_user(user_details, user_details["user_id"]) + + url = "/n/login?type=orcid&uid="+user_details["user_id"] + else: + flash("There was an error getting code from ORCID") + return redirect(url) + +def get_github_user_details(access_token): + from utility.tools import GITHUB_API_URL + result = requests.get(GITHUB_API_URL, headers = {'Authorization':'token ' + access_token }).content + + return json.loads(result) + + +@app.route("/n/logout") +def logout(): + logger.debug("Logging out...") + UserSession().delete_session() + flash("You are now logged out. We hope you come back soon!") + response = make_response(redirect(url_for('index_page'))) + # Delete the cookie + response.set_cookie(UserSession.user_cookie_name, '', expires=0) + return response + +@app.route("/n/forgot_password", methods=['GET']) +def forgot_password(): + """Entry point for forgotten password""" + print("ARGS: ", request.args) + errors = {"no-email": request.args.get("no-email")} + print("ERRORS: ", errors) + return render_template("new_security/forgot_password.html", errors=errors) + +def send_forgot_password_email(verification_email): + from email.MIMEMultipart import MIMEMultipart + from email.MIMEText import MIMEText + + template_name = "email/forgot_password.txt" + key_prefix = "forgot_password_code" + subject = "GeneNetwork password reset" + fromaddr = "no-reply@genenetwork.org" + + verification_code = str(uuid.uuid4()) + key = key_prefix + ":" + verification_code + + data = { + "verification_code": verification_code, + "email_address": verification_email, + "timestamp": timestamp() + } + + save_verification_code(verification_email, verification_code) + + body = render_template(template_name, verification_code = verification_code) + + msg = MIMEMultipart() + msg["To"] = verification_email + msg["Subject"] = subject + msg["From"] = fromaddr + msg.attach(MIMEText(body, "plain")) + + send_email(verification_email, msg.as_string()) + + return subject + +@app.route("/n/forgot_password_submit", methods=('POST',)) +def forgot_password_submit(): + """When a forgotten password form is submitted we get here""" + params = request.form + email_address = params['email_address'] + next_page = None + if email_address != "": + logger.debug("Wants to send password E-mail to ", email_address) + user_details = get_user_by_unique_column("email_address", email_address) + if user_details: + email_subject = send_forgot_password_email(user_details["email_address"]) + return render_template("new_security/forgot_password_step2.html", + subject=email_subject) + else: + flash("The e-mail entered is not associated with an account.", "alert-danger") + return redirect(url_for("forgot_password")) + + else: + flash("You MUST provide an email", "alert-danger") + return redirect(url_for("forgot_password")) + +@app.route("/n/password_reset", methods=['GET']) +def password_reset(): + """Entry point after user clicks link in E-mail""" + logger.debug("in password_reset request.url is:", request.url) + + verification_code = request.args.get('code') + hmac = request.args.get('hm') + + if verification_code: + user_email = check_verification_code(verification_code) + if user_email: + user_details = get_user_by_unique_column('email_address', user_email) + if user_details: + return render_template( + "new_security/password_reset.html", user_encode=user_details["email_address"]) + else: + flash("Invalid code: User no longer exists!", "error") + else: + flash("Invalid code: Password reset code does not exist or might have expired!", "error") + else: + return redirect(url_for("login")) + +@app.route("/n/password_reset_step2", methods=('POST',)) +def password_reset_step2(): + """Handle confirmation E-mail for password reset""" + logger.debug("in password_reset request.url is:", request.url) + + errors = [] + user_email = request.form['user_encode'] + + password = request.form['password'] + encoded_password = set_password(password) + + set_user_attribute(user_id, "password", encoded_password) + + flash("Password changed successfully. You can now sign in.", "alert-info") + response = make_response(redirect(url_for('login'))) + + return response + +def register_user(params): + thank_you_mode = False + errors = [] + user_details = {} + + user_details['email_address'] = params.get('email_address', '').encode("utf-8").strip() + if not (5 <= len(user_details['email_address']) <= 50): + errors.append('Email Address needs to be between 5 and 50 characters.') + else: + email_exists = get_user_by_unique_column("email_address", user_details['email_address']) + if email_exists: + errors.append('User already exists with that email') + + user_details['full_name'] = params.get('full_name', '').encode("utf-8").strip() + if not (5 <= len(user_details['full_name']) <= 50): + errors.append('Full Name needs to be between 5 and 50 characters.') + + user_details['organization'] = params.get('organization', '').encode("utf-8").strip() + if user_details['organization'] and not (5 <= len(user_details['organization']) <= 50): + errors.append('Organization needs to be empty or between 5 and 50 characters.') + + password = str(params.get('password', '')) + if not (6 <= len(password)): + errors.append('Password needs to be at least 6 characters.') + + if params.get('password_confirm') != password: + errors.append("Passwords don't match.") + + if errors: + return errors + + user_details['password'] = set_password(password) + user_details['user_id'] = str(uuid.uuid4()) + user_details['confirmed'] = 1 + + user_details['registration_info'] = json.dumps(basic_info(), sort_keys=True) + save_user(user_details, user_details['user_id']) + +@app.route("/n/register", methods=('GET', 'POST')) +def register(): + errors = None + + params = request.form if request.form else request.args + params = params.to_dict(flat=True) + + if params: + logger.debug("Attempting to register the user...") + errors = register_user(params) + + if len(errors) == 0: + flash("Registration successful. You may login with your new account", "alert-info") + return redirect(url_for("login")) + + return render_template("new_security/register_user.html", values=params, errors=errors) + +@app.errorhandler(401) +def unauthorized(error): + return redirect(url_for('login')) \ No newline at end of file diff --git a/wqflask/wqflask/user_session.py b/wqflask/wqflask/user_session.py new file mode 100644 index 00000000..1f3e6558 --- /dev/null +++ b/wqflask/wqflask/user_session.py @@ -0,0 +1,272 @@ +from __future__ import print_function, division, absolute_import + +import datetime +import time +import uuid + +import simplejson as json + +import redis # used for collections +Redis = redis.StrictRedis() + +from flask import (Flask, g, render_template, url_for, request, make_response, + redirect, flash, abort) + +from wqflask import app +from wqflask.hmac_func import hmac_creation + +#from utility.elasticsearch_tools import get_elasticsearch_connection +from utility.redis_tools import get_user_id, get_user_by_unique_column, get_user_collections, save_collections + +from utility.logger import getLogger +logger = getLogger(__name__) + +THREE_DAYS = 60 * 60 * 24 * 3 +THIRTY_DAYS = 60 * 60 * 24 * 30 + +def verify_cookie(cookie): + the_uuid, separator, the_signature = cookie.partition(':') + assert len(the_uuid) == 36, "Is session_id a uuid?" + assert separator == ":", "Expected a : here" + assert the_signature == hmac_creation(the_uuid), "Uh-oh, someone tampering with the cookie?" + return the_uuid + +def create_signed_cookie(): + the_uuid = str(uuid.uuid4()) + signature = hmac_creation(the_uuid) + uuid_signed = the_uuid + ":" + signature + logger.debug("uuid_signed:", uuid_signed) + return the_uuid, uuid_signed + +class UserSession(object): + """Logged in user handling""" + + user_cookie_name = 'session_id_v1' + anon_cookie_name = 'anon_user_v1' + + def __init__(self): + user_cookie = request.cookies.get(self.user_cookie_name) + if not user_cookie: + self.logged_in = False + anon_cookie = request.cookies.get(self.anon_cookie_name) + self.cookie_name = self.anon_cookie_name + if anon_cookie: + self.cookie = anon_cookie + session_id = verify_cookie(self.cookie) + else: + session_id, self.cookie = create_signed_cookie() + else: + self.cookie_name = self.user_cookie_name + self.cookie = user_cookie + session_id = verify_cookie(self.cookie) + + self.redis_key = self.cookie_name + ":" + session_id + self.session_id = session_id + self.record = Redis.hgetall(self.redis_key) + + #ZS: If user correctled logged in but their session expired + #ZS: Need to test this by setting the time-out to be really short or something + if not self.record: + if user_cookie: + self.logged_in = False + + ########### Grrr...this won't work because of the way flask handles cookies + # Delete the cookie + response = make_response(redirect(url_for('login'))) + #response.set_cookie(self.cookie_name, '', expires=0) + flash("Due to inactivity your session has expired. If you'd like please login again.") + return response + #return + else: + self.record = dict(login_time = time.time(), + user_type = "anon", + user_id = str(uuid.uuid4())) + + Redis.hmset(self.redis_key, self.record) + Redis.expire(self.redis_key, THIRTY_DAYS) + else: + if user_cookie: + self.logged_in = True + + if user_cookie: + session_time = THREE_DAYS + else: + session_time = THIRTY_DAYS + + if Redis.ttl(self.redis_key) < session_time: + # (Almost) everytime the user does something we extend the session_id in Redis... + logger.debug("Extending ttl...") + Redis.expire(self.redis_key, session_time) + + @property + def user_id(self): + """Shortcut to the user_id""" + if 'user_id' in self.record: + return self.record['user_id'] + else: + return '' + + @property + def redis_user_id(self): + """User id from Redis (need to check if this is the same as the id stored in self.records)""" + + #ZS: This part is a bit weird. Some accounts used to not have saved user ids, and in the process of testing I think I created some duplicate accounts for myself. + #ZS: Accounts should automatically generate user_ids if they don't already have one now, so this might not be necessary for anything other than my account's collections + + if 'user_email_address' in self.record: + user_email = self.record['user_email_address'] + + #ZS: Get user's collections if they exist + user_id = None + user_id = get_user_id("email_address", user_email) + elif 'user_id' in self.record: + user_id = self.record['user_id'] + elif 'github_id' in self.record: + user_github_id = self.record['github_id'] + user_id = None + user_id = get_user_id("github_id", user_github_id) + else: #ZS: Anonymous user + return None + + return user_id + + @property + def user_name(self): + """Shortcut to the user_name""" + if 'user_name' in self.record: + return self.record['user_name'] + else: + return '' + + @property + def user_collections(self): + """List of user's collections""" + + #ZS: Get user's collections if they exist + collections = get_user_collections(self.redis_user_id) + return collections + + @property + def num_collections(self): + """Number of user's collections""" + + return len(self.user_collections) + + def add_collection(self, collection_name, traits): + """Add collection into ElasticSearch""" + + collection_dict = {'id': unicode(uuid.uuid4()), + 'name': collection_name, + 'created_timestamp': datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p'), + 'changed_timestamp': datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p'), + 'num_members': len(traits), + 'members': list(traits) } + + current_collections = self.user_collections + current_collections.append(collection_dict) + self.update_collections(current_collections) + + return collection_dict['id'] + + def change_collection_name(self, collection_id, new_name): + for collection in self.user_collections: + if collection['id'] == collection_id: + collection['name'] = new_name + break + + return new_name + + def delete_collection(self, collection_id): + """Remove collection with given ID""" + + updated_collections = [] + for collection in self.user_collections: + if collection['id'] == collection_id: + continue + else: + updated_collections.append(collection) + + self.update_collections(updated_collections) + + return collection['name'] + + def add_traits_to_collection(self, collection_id, traits_to_add): + """Add specified traits to a collection""" + + this_collection = self.get_collection_by_id(collection_id) + + updated_collection = this_collection + updated_traits = this_collection['members'] + traits_to_add + + updated_collection['members'] = updated_traits + updated_collection['num_members'] = len(updated_traits) + updated_collection['changed_timestamp'] = datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p') + + updated_collections = [] + for collection in self.user_collections: + if collection['id'] == collection_id: + updated_collections.append(updated_collection) + else: + updated_collections.append(collection) + + self.update_collections(updated_collections) + + def remove_traits_from_collection(self, collection_id, traits_to_remove): + """Remove specified traits from a collection""" + + this_collection = self.get_collection_by_id(collection_id) + + updated_collection = this_collection + updated_traits = [] + for trait in this_collection['members']: + if trait in traits_to_remove: + continue + else: + updated_traits.append(trait) + + updated_collection['members'] = updated_traits + updated_collection['num_members'] = len(updated_traits) + updated_collection['changed_timestamp'] = datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p') + + updated_collections = [] + for collection in self.user_collections: + if collection['id'] == collection_id: + updated_collections.append(updated_collection) + else: + updated_collections.append(collection) + + self.update_collections(updated_collections) + + return updated_traits + + def get_collection_by_id(self, collection_id): + for collection in self.user_collections: + if collection['id'] == collection_id: + return collection + + def get_collection_by_name(self, collection_name): + for collection in self.user_collections: + if collection['name'] == collection_name: + return collection + + return None + + def update_collections(self, updated_collections): + collection_body = json.dumps(updated_collections) + + save_collections(self.redis_user_id, collection_body) + + def delete_session(self): + # And more importantly delete the redis record + Redis.delete(self.redis_key) + self.logged_in = False + +@app.before_request +def before_request(): + g.user_session = UserSession() + +@app.after_request +def set_cookie(response): + if not request.cookies.get(g.user_session.cookie_name): + response.set_cookie(g.user_session.cookie_name, g.user_session.cookie) + return response \ No newline at end of file diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py index a84a7480..436ebc91 100644 --- a/wqflask/wqflask/views.py +++ b/wqflask/wqflask/views.py @@ -65,9 +65,8 @@ from utility.benchmark import Bench from pprint import pformat as pf -#from wqflask import user_login -#from wqflask import user_session -from wqflask import user_manager +from wqflask import user_login +from wqflask import user_session from wqflask import collect from wqflask.database import db_session @@ -839,6 +838,8 @@ def browser_inputs(): return flask.jsonify(file_contents) + + ########################################################################## def json_default_handler(obj): -- cgit v1.2.3 From 6178a48d29cd83fd3beb70854721070826e230e3 Mon Sep 17 00:00:00 2001 From: zsloan Date: Wed, 22 Apr 2020 16:03:07 -0500 Subject: Fixed a variety of issues related to users registering and logging in GN2 should now work when Redis is empty --- wqflask/utility/startup_config.py | 4 +- wqflask/utility/tools.py | 8 +-- wqflask/wqflask/collect.py | 2 +- wqflask/wqflask/show_trait/SampleList.py | 84 ++++++++++++++++---------------- wqflask/wqflask/show_trait/show_trait.py | 4 +- wqflask/wqflask/user_login.py | 44 ++++++++--------- wqflask/wqflask/user_session.py | 13 +++-- 7 files changed, 80 insertions(+), 79 deletions(-) (limited to 'wqflask/utility/tools.py') diff --git a/wqflask/utility/startup_config.py b/wqflask/utility/startup_config.py index 5a62cc50..817284dd 100644 --- a/wqflask/utility/startup_config.py +++ b/wqflask/utility/startup_config.py @@ -33,7 +33,7 @@ def app_config(): if page.status_code != 200: raise Exception("API server not found!") - import utility.elasticsearch_tools as es - es.test_elasticsearch_connection() + # import utility.elasticsearch_tools as es + # es.test_elasticsearch_connection() print("GN2 is running. Visit %s[http://localhost:%s/%s](%s)" % (BLUE,str(port),ENDC,get_setting("WEBSERVER_URL"))) diff --git a/wqflask/utility/tools.py b/wqflask/utility/tools.py index 75bddb24..0fbedccb 100644 --- a/wqflask/utility/tools.py +++ b/wqflask/utility/tools.py @@ -267,10 +267,10 @@ if ORCID_CLIENT_ID != 'UNKNOWN' and ORCID_CLIENT_SECRET: ORCID_CLIENT_ID+"&client_secret="+ORCID_CLIENT_SECRET ORCID_TOKEN_URL = get_setting('ORCID_TOKEN_URL') -ELASTICSEARCH_HOST = get_setting('ELASTICSEARCH_HOST') -ELASTICSEARCH_PORT = get_setting('ELASTICSEARCH_PORT') -import utility.elasticsearch_tools as es -es.test_elasticsearch_connection() +# ELASTICSEARCH_HOST = get_setting('ELASTICSEARCH_HOST') +# ELASTICSEARCH_PORT = get_setting('ELASTICSEARCH_PORT') +# import utility.elasticsearch_tools as es +# es.test_elasticsearch_connection() SMTP_CONNECT = get_setting('SMTP_CONNECT') SMTP_USERNAME = get_setting('SMTP_USERNAME') diff --git a/wqflask/wqflask/collect.py b/wqflask/wqflask/collect.py index fa6e03b4..1d74b699 100644 --- a/wqflask/wqflask/collect.py +++ b/wqflask/wqflask/collect.py @@ -108,7 +108,7 @@ def collections_new(): if 'existing_collection' not in params: collections = g.user_session.user_collections for collection in collections: - if collection["name"] == "Default Collection": + if collection["name"] == "Your Default Collection": collection_id = collection["id"] collection_name = collection["name"] default_collection_exists = True diff --git a/wqflask/wqflask/show_trait/SampleList.py b/wqflask/wqflask/show_trait/SampleList.py index 7e126a36..ad78ebcc 100644 --- a/wqflask/wqflask/show_trait/SampleList.py +++ b/wqflask/wqflask/show_trait/SampleList.py @@ -14,8 +14,6 @@ import simplejson as json import itertools -from utility.elasticsearch_tools import get_elasticsearch_connection - import utility.logger logger = utility.logger.getLogger(__name__ ) @@ -158,47 +156,47 @@ class SampleList(object): return any(sample.variance for sample in self.sample_list) -def get_transform_vals(dataset, trait): - es = get_elasticsearch_connection(for_user=False) - - logger.info("DATASET NAME:", dataset.name) - - query = '{"bool": {"must": [{"match": {"name": "%s"}}, {"match": {"dataset": "%s"}}]}}' % (trait.name, dataset.name) - - es_body = { - "query": { - "bool": { - "must": [ - { - "match": { - "name": "%s" % (trait.name) - } - }, - { - "match": { - "dataset": "%s" % (dataset.name) - } - } - ] - } - } - } - - response = es.search( index = "traits", doc_type = "trait", body = es_body ) - logger.info("THE RESPONSE:", response) - results = response['hits']['hits'] - - if len(results) > 0: - samples = results[0]['_source']['samples'] - - sample_dict = {} - for sample in samples: - sample_dict[sample['name']] = sample['qnorm'] - - #logger.info("SAMPLE DICT:", sample_dict) - return sample_dict - else: - return None +# def get_transform_vals(dataset, trait): +# es = get_elasticsearch_connection(for_user=False) + +# logger.info("DATASET NAME:", dataset.name) + +# query = '{"bool": {"must": [{"match": {"name": "%s"}}, {"match": {"dataset": "%s"}}]}}' % (trait.name, dataset.name) + +# es_body = { +# "query": { +# "bool": { +# "must": [ +# { +# "match": { +# "name": "%s" % (trait.name) +# } +# }, +# { +# "match": { +# "dataset": "%s" % (dataset.name) +# } +# } +# ] +# } +# } +# } + +# response = es.search( index = "traits", doc_type = "trait", body = es_body ) +# logger.info("THE RESPONSE:", response) +# results = response['hits']['hits'] + +# if len(results) > 0: +# samples = results[0]['_source']['samples'] + +# sample_dict = {} +# for sample in samples: +# sample_dict[sample['name']] = sample['qnorm'] + +# #logger.info("SAMPLE DICT:", sample_dict) +# return sample_dict +# else: +# return None def natural_sort_key(x): """Get expected results when using as a key for sort - ints or strings are sorted properly""" diff --git a/wqflask/wqflask/show_trait/show_trait.py b/wqflask/wqflask/show_trait/show_trait.py index d35ba749..8883e627 100644 --- a/wqflask/wqflask/show_trait/show_trait.py +++ b/wqflask/wqflask/show_trait/show_trait.py @@ -364,8 +364,8 @@ class ShowTrait(object): if self.dataset: dataset_menu_selected = self.dataset.name - return_results_menu = (100, 200, 500, 1000, 2000, 5000, 10000, 15000, 20000) - return_results_menu_selected = 500 + return_results_menu = (100, 200, 500, 1000, 2000, 5000, 10000, 15000, 20000) + return_results_menu_selected = 500 self.corr_tools = dict(dataset_menu = dataset_menu, dataset_menu_selected = dataset_menu_selected, diff --git a/wqflask/wqflask/user_login.py b/wqflask/wqflask/user_login.py index da3cc504..40d9925c 100644 --- a/wqflask/wqflask/user_login.py +++ b/wqflask/wqflask/user_login.py @@ -6,7 +6,6 @@ import datetime import time import logging import uuid -import hashlib import hmac import base64 import requests @@ -42,17 +41,23 @@ def basic_info(): ip_address = request.remote_addr, user_agent = request.headers.get('User-Agent')) -def encode_password(pass_gen_fields): +def encode_password(pass_gen_fields, unencrypted_password): + logger.debug("THE TYPE:", type(pass_gen_fields)) + logger.debug("pass_gen_fields:", pass_gen_fields) + logger.debug("hashfunc:", pass_gen_fields['hashfunc']) hashfunc = getattr(hashlib, pass_gen_fields['hashfunc']) salt = base64.b64decode(pass_gen_fields['salt']) - password = pbkdf2.pbkdf2_hex(str(pass_gen_fields['unencrypted_password']), + encrypted_password = pbkdf2.pbkdf2_hex(str(unencrypted_password), pass_gen_fields['salt'], pass_gen_fields['iterations'], pass_gen_fields['keylength'], hashfunc) - return password + pass_gen_fields.pop("unencrypted_password", None) + pass_gen_fields["password"] = encrypted_password + + return pass_gen_fields def set_password(password): pass_gen_fields = { @@ -67,19 +72,10 @@ def set_password(password): assert len(password) >= 6, "Password shouldn't be shorter than 6 characters" - encoded_password = encode_password(pass_gen_fields) + encoded_password = encode_password(pass_gen_fields, pass_gen_fields['unencrypted_password']) return encoded_password -def encrypt_password(unencrypted_password, pwfields): - hashfunc = getattr(hashlib, pwfields['hashfunc']) - salt = base64.b64decode(pwfields['salt']) - iterations = pwfields['iterations'] - keylength = pwfields['keylength'] - encrypted_password = pbkdf2.pbkdf2_hex(str(unencrypted_password), - salt, iterations, keylength, hashfunc) - return encrypted_password - def get_signed_session_id(user): session_id = str(uuid.uuid4()) @@ -186,9 +182,12 @@ def login(): password_match = False if user_details: submitted_password = params['password'] - pwfields = json.loads(user_details['password']) - encrypted_pass = encrypt_password(submitted_password, pwfields) - password_match = pbkdf2.safe_str_cmp(encrypted_pass, pwfields['password']) + pwfields = user_details['password'] + if type(pwfields) is str: + pwfields = json.loads(pwfields) + encrypted_pass_fields = encode_password(pwfields, submitted_password) + password_match = pbkdf2.safe_str_cmp(encrypted_pass_fields['password'], pwfields['password']) + else: # Invalid e-mail flash("Invalid e-mail address. Please try again.", "alert-danger") response = make_response(redirect(url_for('login'))) @@ -226,7 +225,7 @@ def github_oauth2(): "client_secret": GITHUB_CLIENT_SECRET, "code": code } - logger.debug("LOGIN DATA:", data) + result = requests.post("https://github.com/login/oauth/access_token", json=data) result_dict = {arr[0]:arr[1] for arr in [tok.split("=") for tok in [token.encode("utf-8") for token in result.text.split("&")]]} @@ -437,19 +436,18 @@ def register_user(params): if params.get('password_confirm') != password: errors.append("Passwords don't match.") - if errors: - return errors - user_details['password'] = set_password(password) user_details['user_id'] = str(uuid.uuid4()) user_details['confirmed'] = 1 - user_details['registration_info'] = json.dumps(basic_info(), sort_keys=True) + user_details['registration_info'] = basic_info() save_user(user_details, user_details['user_id']) + return errors + @app.route("/n/register", methods=('GET', 'POST')) def register(): - errors = None + errors = [] params = request.form if request.form else request.args params = params.to_dict(flat=True) diff --git a/wqflask/wqflask/user_session.py b/wqflask/wqflask/user_session.py index d75a03df..fd1779fb 100644 --- a/wqflask/wqflask/user_session.py +++ b/wqflask/wqflask/user_session.py @@ -9,6 +9,7 @@ import simplejson as json import redis # used for collections Redis = redis.StrictRedis() + from flask import (Flask, g, render_template, url_for, request, make_response, redirect, flash, abort) @@ -69,19 +70,23 @@ class UserSession(object): if not self.record or self.record == []: if user_cookie: self.logged_in = False + self.record = dict(login_time = time.time(), + user_type = "anon", + user_id = str(uuid.uuid4())) + Redis.hmset(self.redis_key, self.record) + Redis.expire(self.redis_key, THIRTY_DAYS) + response = make_response(redirect(url_for('login'))) + response.set_cookie(self.user_cookie_name, '', expires=0) ########### Grrr...this won't work because of the way flask handles cookies # Delete the cookie - response = make_response(redirect(url_for('login'))) - #response.set_cookie(self.cookie_name, '', expires=0) flash("Due to inactivity your session has expired. If you'd like please login again.") - #return response + return response #return else: self.record = dict(login_time = time.time(), user_type = "anon", user_id = str(uuid.uuid4())) - Redis.hmset(self.redis_key, self.record) Redis.expire(self.redis_key, THIRTY_DAYS) else: -- cgit v1.2.3 From be09d207ee4e2705e358102f8bdbcd1da7f70ca2 Mon Sep 17 00:00:00 2001 From: zsloan Date: Fri, 24 Apr 2020 16:06:36 -0500 Subject: Replaced hard-coded instances of GN2 urls with ones pulled from settings file --- doc/API_readme.md | 42 +++++++++++----------- wqflask/base/data_set.py | 4 +-- wqflask/base/trait.py | 7 ++-- wqflask/utility/tools.py | 2 ++ wqflask/wqflask/ctl/ctl_analysis.py | 4 ++- wqflask/wqflask/do_search.py | 3 +- wqflask/wqflask/network_graph/network_graph.py | 2 ++ wqflask/wqflask/search_results.py | 3 +- wqflask/wqflask/static/new/javascript/ctl_graph.js | 8 +---- .../new/javascript/dataset_select_menu_orig.js | 1 - .../wqflask/static/new/javascript/network_graph.js | 4 +-- wqflask/wqflask/templates/ctl_results.html | 1 + wqflask/wqflask/templates/index_page.html | 4 +-- wqflask/wqflask/templates/index_page_orig.html | 4 +-- wqflask/wqflask/templates/network_graph.html | 1 + 15 files changed, 47 insertions(+), 43 deletions(-) (limited to 'wqflask/utility/tools.py') diff --git a/doc/API_readme.md b/doc/API_readme.md index 652376a0..be6668dc 100644 --- a/doc/API_readme.md +++ b/doc/API_readme.md @@ -6,17 +6,17 @@ To get a list of species with data available in GN (and their associated names and ids): ``` -curl http://gn2.genenetwork.org/api/v_pre1/species +curl http://genenetwork.org/api/v_pre1/species [ { "FullName": "Mus musculus", "Id": 1, "Name": "mouse", "TaxonomyId": 10090 }, ... { "FullName": "Populus trichocarpa", "Id": 10, "Name": "poplar", "TaxonomyId": 3689 } ] ``` Or to get a single species info: ``` -curl http://gn2.genenetwork.org/api/v_pre1/species/mouse +curl http://genenetwork.org/api/v_pre1/species/mouse ``` OR ``` -curl http://gn2.genenetwork.org/api/v_pre1/species/mouse.json +curl http://genenetwork.org/api/v_pre1/species/mouse.json ``` *For all queries where the last field is a user-specified name/ID, there will be the option to append a file format type. Currently there is only JSON (and it will default to JSON if none is provided), but other formats will be added later* @@ -26,33 +26,33 @@ curl http://gn2.genenetwork.org/api/v_pre1/species/mouse.json This query can optionally filter by species: ``` -curl http://gn2.genenetwork.org/api/v_pre1/groups (for all species) +curl http://genenetwork.org/api/v_pre1/groups (for all species) ``` OR ``` -curl http://gn2.genenetwork.org/api/v_pre1/groups/mouse (for just mouse groups/RISets) +curl http://genenetwork.org/api/v_pre1/groups/mouse (for just mouse groups/RISets) [ { "DisplayName": "BXD", "FullName": "BXD RI Family", "GeneticType": "riset", "Id": 1, "MappingMethodId": "1", "Name": "BXD", "SpeciesId": 1, "public": 2 }, ... { "DisplayName": "AIL LGSM F34 and F39-43 (GBS)", "FullName": "AIL LGSM F34 and F39-43 (GBS)", "GeneticType": "intercross", "Id": 72, "MappingMethodId": "2", "Name": "AIL-LGSM-F34-F39-43-GBS", "SpeciesId": 1, "public": 2 } ] ``` ## Fetch Genotypes for Group/RISet ## ``` -curl http://gn2.genenetwork.org/api/v_pre1/genotypes/bimbam/BXD -curl http://gn2.genenetwork.org/api/v_pre1/genotypes/BXD.bimbam +curl http://genenetwork.org/api/v_pre1/genotypes/bimbam/BXD +curl http://genenetwork.org/api/v_pre1/genotypes/BXD.bimbam ``` Returns a group's genotypes in one of several formats - bimbam, rqtl2, or geno (a format used by qtlreaper which is just a CSV file consisting of marker positions and genotypes) Rqtl2 genotype queries can also include the dataset name and will return a zip of the genotypes, phenotypes, and gene map (marker names/positions). For example: ``` -curl http://gn2.genenetwork.org/api/v_pre1/genotypes/rqtl2/BXD/HC_M2_0606_P.zip +curl http://genenetwork.org/api/v_pre1/genotypes/rqtl2/BXD/HC_M2_0606_P.zip ``` ## Fetch Datasets ## ``` -curl http://gn2.genenetwork.org/api/v_pre1/datasets/bxd +curl http://genenetwork.org/api/v_pre1/datasets/bxd ``` OR ``` -curl http://gn2.genenetwork.org/api/v_pre1/datasets/mouse/bxd +curl http://genenetwork.org/api/v_pre1/datasets/mouse/bxd [ { "AvgID": 1, "CreateTime": "Fri, 01 Aug 2003 00:00:00 GMT", "DataScale": "log2", "FullName": "UTHSC/ETHZ/EPFL BXD Liver Polar Metabolites Extraction A, CD Cohorts (Mar 2017) log2", "Id": 1, "Long_Abbreviation": "BXDMicroArray_ProbeSet_August03", "ProbeFreezeId": 3, "ShortName": "Brain U74Av2 08/03 MAS5", "Short_Abbreviation": "Br_U_0803_M", "confidentiality": 0, "public": 0 }, ... { "AvgID": 3, "CreateTime": "Tue, 14 Aug 2018 00:00:00 GMT", "DataScale": "log2", "FullName": "EPFL/LISP BXD CD Liver Affy Mouse Gene 1.0 ST (Aug18) RMA", "Id": 859, "Long_Abbreviation": "EPFLMouseLiverCDRMAApr18", "ProbeFreezeId": 181, "ShortName": "EPFL/LISP BXD CD Liver Affy Mouse Gene 1.0 ST (Aug18) RMA", "Short_Abbreviation": "EPFLMouseLiverCDRMA0818", "confidentiality": 0, "public": 1 } ] ``` (I added the option to specify species just in case we end up with the same group name across multiple species at some point, though it's currently unnecessary) @@ -61,11 +61,11 @@ curl http://gn2.genenetwork.org/api/v_pre1/datasets/mouse/bxd ### For mRNA Assay/"ProbeSet" ### ``` -curl http://gn2.genenetwork.org/api/v_pre1/dataset/HC_M2_0606_P +curl http://genenetwork.org/api/v_pre1/dataset/HC_M2_0606_P ``` OR ``` -curl http://gn2.genenetwork.org/api/v_pre1/dataset/bxd/HC_M2_0606_P``` +curl http://genenetwork.org/api/v_pre1/dataset/bxd/HC_M2_0606_P``` { "confidential": 0, "data_scale": "log2", "dataset_type": "mRNA expression", "full_name": "Hippocampus Consortium M430v2 (Jun06) PDNN", "id": 112, "name": "HC_M2_0606_P", "public": 2, "short_name": "Hippocampus M430v2 BXD 06/06 PDNN", "tissue": "Hippocampus mRNA", "tissue_id": 9 } ``` (This also has the option to specify group/riset) @@ -73,26 +73,26 @@ curl http://gn2.genenetwork.org/api/v_pre1/dataset/bxd/HC_M2_0606_P``` ### For "Phenotypes" (basically non-mRNA Expression; stuff like weight, sex, etc) ### For these traits, the query fetches publication info and takes the group and phenotype 'ID' as input. For example: ``` -curl http://gn2.genenetwork.org/api/v_pre1/dataset/bxd/10001 +curl http://genenetwork.org/api/v_pre1/dataset/bxd/10001 { "dataset_type": "phenotype", "description": "Central nervous system, morphology: Cerebellum weight, whole, bilateral in adults of both sexes [mg]", "id": 10001, "name": "CBLWT2", "pubmed_id": 11438585, "title": "Genetic control of the mouse cerebellum: identification of quantitative trait loci modulating size and architecture", "year": "2001" } ``` ## Fetch Sample Data for Dataset ## ``` -curl http://gn2.genenetwork.org/api/v_pre1/sample_data/HSNIH-PalmerPublish.csv +curl http://genenetwork.org/api/v_pre1/sample_data/HSNIH-PalmerPublish.csv ``` Returns a CSV file with sample/strain names as the columns and trait IDs as rows ## Fetch Sample Data for Single Trait ## ``` -curl http://gn2.genenetwork.org/api/v_pre1/sample_data/HC_M2_0606_P/1436869_at +curl http://genenetwork.org/api/v_pre1/sample_data/HC_M2_0606_P/1436869_at [ { "data_id": 23415463, "sample_name": "129S1/SvImJ", "sample_name_2": "129S1/SvImJ", "se": 0.123, "value": 8.201 }, { "data_id": 23415463, "sample_name": "A/J", "sample_name_2": "A/J", "se": 0.046, "value": 8.413 }, { "data_id": 23415463, "sample_name": "AKR/J", "sample_name_2": "AKR/J", "se": 0.134, "value": 8.856 }, ... ] ``` ## Fetch Trait List for Dataset ## ``` -curl http://gn2.genenetwork.org/api/v_pre1/traits/HXBBXHPublish.json +curl http://genenetwork.org/api/v_pre1/traits/HXBBXHPublish.json [ { "Additive": 0.0499967532467532, "Id": 10001, "LRS": 16.2831307029479, "Locus": "rs106114574", "PhenotypeId": 1449, "PublicationId": 319, "Sequence": 1 }, ... ] ``` @@ -101,7 +101,7 @@ Both JSON and CSV formats can be specified, with JSON as default. There is also ## Fetch Trait Info (Name, Description, Location, etc) ## ### For mRNA Expression/"ProbeSet" ### ``` -curl http://gn2.genenetwork.org/api/v_pre1/trait/HC_M2_0606_P/1436869_at +curl http://genenetwork.org/api/v_pre1/trait/HC_M2_0606_P/1436869_at { "additive": -0.214087568058076, "alias": "HHG1; HLP3; HPE3; SMMCI; Dsh; Hhg1", "chr": "5", "description": "sonic hedgehog (hedgehog)", "id": 99602, "locus": "rs8253327", "lrs": 12.7711275309832, "mb": 28.457155, "mean": 9.27909090909091, "name": "1436869_at", "p_value": 0.306, "se": null, "symbol": "Shh" } ``` @@ -110,7 +110,7 @@ For phenotypes this just gets the max LRS, its location, and additive effect (a Since each group/riset only has one phenotype "dataset", this query takes either the group/riset name or the group/riset name + "Publish" (for example "BXDPublish", which is the dataset name in the DB) as input ``` -curl http://gn2.genenetwork.org/api/v_pre1/trait/BXD/10001 +curl http://genenetwork.org/api/v_pre1/trait/BXD/10001 { "additive": 2.39444435069444, "id": 4, "locus": "rs48756159", "lrs": 13.4974911471087 } ``` @@ -130,7 +130,7 @@ Each method's query takes the following parameters respectively (more will be ad Example query: ``` -curl http://gn2.genenetwork.org/api/v_pre1/mapping?trait_id=10015&db=BXDPublish&method=gemma&use_loco=true +curl http://genenetwork.org/api/v_pre1/mapping?trait_id=10015&db=BXDPublish&method=gemma&use_loco=true ``` ### R/qtl ### @@ -146,7 +146,7 @@ curl http://gn2.genenetwork.org/api/v_pre1/mapping?trait_id=10015&db=BXDPublish& Example query: ``` -curl http://gn2.genenetwork.org/api/v_pre1/mapping?trait_id=1418701_at&db=HC_M2_0606_P&method=rqtl&num_perm=100 +curl http://genenetwork.org/api/v_pre1/mapping?trait_id=1418701_at&db=HC_M2_0606_P&method=rqtl&num_perm=100 ``` Some combinations of methods/models may not make sense. The R/qtl manual should be referred to for any questions on its use (specifically the scanone function in this case) @@ -164,6 +164,6 @@ This query currently takes the following parameters (though more will be added): Example query: ``` -curl http://gn2.genenetwork.org/api/v_pre1/correlation?trait_id=1427571_at&db=HC_M2_0606_P&target_db=BXDPublish&type=sample&return_count=100 +curl http://genenetwork.org/api/v_pre1/correlation?trait_id=1427571_at&db=HC_M2_0606_P&target_db=BXDPublish&type=sample&return_count=100 [ { "#_strains": 6, "p_value": 0.004804664723032055, "sample_r": -0.942857142857143, "trait": 20511 }, { "#_strains": 6, "p_value": 0.004804664723032055, "sample_r": -0.942857142857143, "trait": 20724 }, { "#_strains": 12, "p_value": 1.8288943424888848e-05, "sample_r": -0.9233615170820528, "trait": 13536 }, { "#_strains": 7, "p_value": 0.006807187408935392, "sample_r": 0.8928571428571429, "trait": 10157 }, { "#_strains": 7, "p_value": 0.006807187408935392, "sample_r": -0.8928571428571429, "trait": 20392 }, ... ] ``` diff --git a/wqflask/base/data_set.py b/wqflask/base/data_set.py index fae62875..8652e6b7 100644 --- a/wqflask/base/data_set.py +++ b/wqflask/base/data_set.py @@ -56,7 +56,7 @@ from pprint import pformat as pf from db.gn_server import menu_main from db.call import fetchall,fetchone,fetch1 -from utility.tools import USE_GN_SERVER, USE_REDIS, flat_files, flat_file_exists +from utility.tools import USE_GN_SERVER, USE_REDIS, flat_files, flat_file_exists, GN2_BASE_URL from utility.logger import getLogger logger = getLogger(__name__ ) @@ -94,7 +94,7 @@ Publish or ProbeSet. E.g. """ self.datasets = {} if rebuild: #ZS: May make this the only option - data = json.loads(requests.get("http://gn2.genenetwork.org/api/v_pre1/gen_dropdown").content) + data = json.loads(requests.get(GN2_BASE_URL + "/api/v_pre1/gen_dropdown").content) #data = gen_menu.gen_dropdown_json() else: file_name = "wqflask/static/new/javascript/dataset_menu_structure.json" diff --git a/wqflask/base/trait.py b/wqflask/base/trait.py index 5525472e..e454c593 100644 --- a/wqflask/base/trait.py +++ b/wqflask/base/trait.py @@ -14,6 +14,7 @@ from base.data_set import create_dataset from db import webqtlDatabaseFunction from utility import webqtlUtil from utility import hmac +from utility.tools import GN2_BASE_URL from wqflask import app @@ -135,9 +136,9 @@ class GeneralTrait(object): alias = 'Not available' if self.symbol: - human_response = requests.get("http://gn2.genenetwork.org/gn3/gene/aliases/" + self.symbol.upper()) - mouse_response = requests.get("http://gn2.genenetwork.org/gn3/gene/aliases/" + self.symbol.capitalize()) - other_response = requests.get("http://gn2.genenetwork.org/gn3/gene/aliases/" + self.symbol.lower()) + human_response = requests.get(GN2_BASE_URL + "gn3/gene/aliases/" + self.symbol.upper()) + mouse_response = requests.get(GN2_BASE_URL + "gn3/gene/aliases/" + self.symbol.capitalize()) + other_response = requests.get(GN2_BASE_URL + "gn3/gene/aliases/" + self.symbol.lower()) if human_response and mouse_response and other_response: alias_list = json.loads(human_response.content) + json.loads(mouse_response.content) + json.loads(other_response.content) diff --git a/wqflask/utility/tools.py b/wqflask/utility/tools.py index 0fbedccb..9354ece6 100644 --- a/wqflask/utility/tools.py +++ b/wqflask/utility/tools.py @@ -234,6 +234,8 @@ def show_settings(): GN_VERSION = get_setting('GN_VERSION') HOME = get_setting('HOME') WEBSERVER_MODE = get_setting('WEBSERVER_MODE') +GN2_BASE_URL = get_setting('GN2_BASE_URL') +GN2_BRANCH_URL = get_setting('GN2_BRANCH_URL') GN_SERVER_URL = get_setting('GN_SERVER_URL') SERVER_PORT = get_setting_int('SERVER_PORT') SQL_URI = get_setting('SQL_URI') diff --git a/wqflask/wqflask/ctl/ctl_analysis.py b/wqflask/wqflask/ctl/ctl_analysis.py index 6fda02fd..4415b86a 100644 --- a/wqflask/wqflask/ctl/ctl_analysis.py +++ b/wqflask/wqflask/ctl/ctl_analysis.py @@ -20,7 +20,7 @@ from base import data_set from base import trait as TRAIT from utility import helper_functions -from utility.tools import locate +from utility.tools import locate, GN2_BRANCH_URL from rpy2.robjects.packages import importr @@ -56,6 +56,8 @@ class CTL(object): self.edges_list = [] logger.info("Obtained pointers to CTL functions") + self.gn2_url = GN2_BRANCH_URL + def addNode(self, gt): node_dict = { 'data' : {'id' : str(gt.name) + ":" + str(gt.dataset.name), 'sid' : str(gt.name), diff --git a/wqflask/wqflask/do_search.py b/wqflask/wqflask/do_search.py index 05caa100..b0ca5ced 100644 --- a/wqflask/wqflask/do_search.py +++ b/wqflask/wqflask/do_search.py @@ -13,6 +13,7 @@ import sys # sys.path.append("..") Never in a running webserver from db import webqtlDatabaseFunction +from utility.tools import GN2_BASE_URL import logging from utility.logger import getLogger @@ -919,7 +920,7 @@ def get_aliases(symbol, species): return [] filtered_aliases = [] - response = requests.get("http://gn2.genenetwork.org/gn3/gene/aliases/" + symbol_string) + response = requests.get(GN2_BASE_URL + "/gn3/gene/aliases/" + symbol_string) if response: alias_list = json.loads(response.content) diff --git a/wqflask/wqflask/network_graph/network_graph.py b/wqflask/wqflask/network_graph/network_graph.py index a332db46..152e4168 100644 --- a/wqflask/wqflask/network_graph/network_graph.py +++ b/wqflask/wqflask/network_graph/network_graph.py @@ -47,6 +47,7 @@ from utility.TDCell import TDCell from base.trait import GeneralTrait from base import data_set from utility import webqtlUtil, helper_functions, corr_result_helpers +from utility.tools import GN2_BRANCH_URL from db import webqtlDatabaseFunction import utility.webqtlUtil #this is for parallel computing only. from wqflask.correlation import correlation_functions @@ -195,6 +196,7 @@ class NetworkGraph(object): self.nodes_list.append(node_dict) self.elements = json.dumps(self.nodes_list + self.edges_list) + self.gn2_url = GN2_BRANCH_URL groups = [] for sample in self.all_sample_list: diff --git a/wqflask/wqflask/search_results.py b/wqflask/wqflask/search_results.py index 698389ab..8f702d58 100644 --- a/wqflask/wqflask/search_results.py +++ b/wqflask/wqflask/search_results.py @@ -28,6 +28,7 @@ from flask import render_template, Flask, g from utility import formatting from utility import hmac +from utility.tools import GN2_BASE_URL from utility.type_checking import is_float, is_int, is_str, get_float, get_int, get_string from utility.logger import getLogger @@ -295,7 +296,7 @@ def get_aliases(symbol_list, species): symbols_string = ",".join(updated_symbols) filtered_aliases = [] - response = requests.get("http://gn2.genenetwork.org/gn3/gene/aliases2/" + symbols_string) + response = requests.get(GN2_BASE_URL + "/gn3/gene/aliases2/" + symbols_string) if response: alias_lists = json.loads(response.content) seen = set() diff --git a/wqflask/wqflask/static/new/javascript/ctl_graph.js b/wqflask/wqflask/static/new/javascript/ctl_graph.js index 94bd7e9d..bd950592 100644 --- a/wqflask/wqflask/static/new/javascript/ctl_graph.js +++ b/wqflask/wqflask/static/new/javascript/ctl_graph.js @@ -82,18 +82,12 @@ window.onload=function() { function create_qtips(cy){ cy.nodes().qtip({ content: function(){ - gn_link = ''+''+this.data().id +''+'
' + gn_link = ''+''+this.data().id +''+'
' ncbi_link = 'NCBI'+'
' omim_link = '
OMIM'+'
' qtip_content = gn_link + ncbi_link + omim_link return qtip_content - //return ''+'
'+this.data().id +''+'' }, - // content: { - // title: ''+''+this.target() +''+'', - // text: this.target, - // button: true - // }, position: { my: 'top center', at: 'bottom center' diff --git a/wqflask/wqflask/static/new/javascript/dataset_select_menu_orig.js b/wqflask/wqflask/static/new/javascript/dataset_select_menu_orig.js index fad600d2..794804f4 100644 --- a/wqflask/wqflask/static/new/javascript/dataset_select_menu_orig.js +++ b/wqflask/wqflask/static/new/javascript/dataset_select_menu_orig.js @@ -74,7 +74,6 @@ redo_dropdown = function(dropdown, items) { this_opt_group = null for (_i = 0, _len = group_family_list.length; _i < _len; _i++) { item = group_family_list[_i]; - console.log("THE ITEM:", item) if (item[2] != "None" && current_family == ""){ current_family = item[2] this_opt_group = $("") diff --git a/wqflask/wqflask/static/new/javascript/network_graph.js b/wqflask/wqflask/static/new/javascript/network_graph.js index 4d507a18..02c3b817 100644 --- a/wqflask/wqflask/static/new/javascript/network_graph.js +++ b/wqflask/wqflask/static/new/javascript/network_graph.js @@ -85,7 +85,7 @@ window.onload=function() { cy.nodes().qtip({ content: function(){ qtip_content = '' - gn_link = ''+''+this.data().id +''+'
' + gn_link = ''+''+this.data().id +''+'
' qtip_content += gn_link if (typeof(this.data().geneid) !== 'undefined'){ ncbi_link = 'NCBI'+'
' @@ -115,7 +115,7 @@ window.onload=function() { correlation_line = 'Sample r: ' + this.data().correlation + '
' p_value_line = 'Sample p(r): ' + this.data().p_value + '
' overlap_line = 'Overlap: ' + this.data().overlap + '
' - scatter_plot = '
View Scatterplot' + scatter_plot = 'View Scatterplot' return correlation_line + p_value_line + overlap_line + scatter_plot }, position: { diff --git a/wqflask/wqflask/templates/ctl_results.html b/wqflask/wqflask/templates/ctl_results.html index d85075a9..0108d93a 100644 --- a/wqflask/wqflask/templates/ctl_results.html +++ b/wqflask/wqflask/templates/ctl_results.html @@ -61,6 +61,7 @@ diff --git a/wqflask/wqflask/templates/index_page.html b/wqflask/wqflask/templates/index_page.html index 0116245d..f8720d39 100644 --- a/wqflask/wqflask/templates/index_page.html +++ b/wqflask/wqflask/templates/index_page.html @@ -219,9 +219,9 @@

GN1 Mirror and development sites

diff --git a/wqflask/wqflask/templates/index_page_orig.html b/wqflask/wqflask/templates/index_page_orig.html index 963531cb..06b71f53 100755 --- a/wqflask/wqflask/templates/index_page_orig.html +++ b/wqflask/wqflask/templates/index_page_orig.html @@ -254,8 +254,8 @@

GeneNetwork v2:

GeneNetwork v1: