-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathserver.py
More file actions
184 lines (130 loc) · 6.63 KB
/
server.py
File metadata and controls
184 lines (130 loc) · 6.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
import getpass
import requests
import flask
import json
from flask import request
from flask import session
import os
from optparse import OptionParser
from requests_oauthlib import OAuth2Session
import keys
from ga4gh.schemas import protocol as p
import ga4gh.schemas.ga4gh.variants_pb2 as v
PORT = 5000
API_SERVER = "api.23andme.com"
BASE_CLIENT_URL = "http://localhost:%s/" % PORT
DEFAULT_REDIRECT_URI = "%soauth" % BASE_CLIENT_URL
os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"
DEFAULT_SNPS = ["rs12913832"]
DEFAULT_SCOPES = ["names", "basic","email", "genomes"]
client_secret = keys.client_secret
parser = OptionParser(usage="usage: %prog -i CLIENT_ID [options]")
parser.add_option("-s", "--scopes", dest="scopes", action="append", default=[],
help="Your requested scopes. Eg: -s basic -s rs12913832")
parser.add_option("-r", "--redirect_uri", dest="redirect_uri", default=DEFAULT_REDIRECT_URI,
help="Your clients redirect_uri [%s]" % DEFAULT_REDIRECT_URI)
parser.add_option("-a", "--api_server", dest="api_server", default=API_SERVER,
help="Almost always: [api.23andme.com]")
parser.add_option("-p", "--select-profile", dest="select_profile", action="store_true", default=False,
help="If present, the auth screen will show a profile select screen")
(options, args) = parser.parse_args()
BASE_API_URL = "https://%s" % options.api_server
API_AUTH_URL = "%s/authorize" % BASE_API_URL
API_TOKEN_URL = "%s/token/" % BASE_API_URL
if options.select_profile:
API_AUTH_URL += "?select_profile=true"
redirect_uri = options.redirect_uri
client_id = keys.client_id
scopes = options.scopes or DEFAULT_SCOPES
if not client_secret:
print "Please navigate to your developer dashboard [%s/dev/] to retrieve your client_secret." % BASE_API_URL
client_secret = getpass.getpass("Please enter your client_secret:")
# GA4GH chromosome value to NC ID
chromeToAccession = {"1":"NC_000001.10", "2":"NC_000002.11", "3":"NC_000003.11", "4":"NC_000004.11", "5":"NC_000005.9", "6":"NC_000006.11",
"7":"NC_000007.13", "8":"NC_000008.10", "9":"NC_000009.11", "10":"NC_000010.10", "11":"NC_000011.9", "12":"NC_000012.11",
"13":"NC_000013.10", "14":"NC_000014.8", "15":"NC_000015.9", "16":"NC_000016.9", "17":"NC_000017.10", "18":"NC_000018.9",
"19":"NC_000019.9", "20":"NC_000020.10", "21":"NC_000021.8", "22":"NC_000022.10", "X":"NC_000023.10", "Y":"NC_000024.9"}
app = flask.Flask(__name__)
### Show index page, begin oauth process
### Go to api callback /oauth
@app.route("/")
def index():
print("in index")
print(DEFAULT_REDIRECT_URI)
ttam_oauth = OAuth2Session(client_id,
redirect_uri=redirect_uri,
scope=scopes)
auth_url, state = ttam_oauth.authorization_url(API_AUTH_URL)
return flask.render_template("index.html", auth_url=auth_url)
### Retrieve access token and complete oauth process
### Retrieve user profile id
### Call ga4gh() to begin parameter entry
@app.route("/oauth")
def oauth():
print("authenticating...")
# authentification information
ttam_oauth = OAuth2Session(client_id,
redirect_uri=redirect_uri)
token_dict = ttam_oauth.fetch_token(API_TOKEN_URL,
client_secret=client_secret,
authorization_response=request.url)
access_token = token_dict["access_token"]
headers = {"Authorization": "Bearer %s" % access_token}
account_response = requests.get("https://api.23andme.com/3/account/",headers=headers, verify=False)
account_response_json = account_response.json()
profile_id = account_response_json["data"][0]["profiles"][0]["id"]
# store headers and profile_id in session so that we can use it in the flask portion of the application
session["headers"] = headers
session["profile_id"] = profile_id
# after oauth has completed, begin actual request
return(ga4gh())
### Prompt user for search_variants_request parameters using ga4gh.html
def ga4gh():
print("input data...")
submit_ga4gh = "http://localhost:5000/variants/search"
return flask.render_template("user_input.html", auth_url=submit_ga4gh)
### Post users entered parameters
### Store parameters in protocol buffer
### Send off protocol buffer to translate()
@app.route("/variants/search", methods=["POST"])
def search_variants():
print("converting request to GA4GH")
start_pos = request.form["start_pos"]
end_pos = request.form["end_pos"]
chrome = request.form["chrome"]
session["chrome"] = chrome
aRequest = {"start": start_pos, "end": end_pos, "referenceName": chrome, "variantSetId": "abc"}
# using ga4gh protocol buffer, stuff parameters into SearchVariantsRequest
proto_request = p.fromJson(json.dumps(aRequest), p.SearchVariantsRequest)
return(translate(proto_request))
### Convert GA4GH request into 23andMe request
### Send off converted GA4GH -> 23andMe request
@app.route("/translate")
def translate(ga4gh_request):
# using ga4gh protocol buffer, stuff SearchVariantsRequest parameters into 23andMe request
print("creating 23andMe request from GA4GH protobuf")
profile_id = session.get("profile_id")
ttam_request = "https://api.23andme.com/3/profile/"+profile_id+"/variant/?accession_id="+chromeToAccession[ga4gh_request.reference_name]+"&start="+str(ga4gh_request.start)+"&end="+str(ga4gh_request.end)
headers = session.get("headers")
print("sending request to 23andMe")
profile_variant_response = requests.get(ttam_request,headers=headers, verify=False)
profile_variant_response_json = profile_variant_response.json()
print("converting response to GA4GH SearchVariantResponse")
ttam_response = profile_variant_response_json["data"]
# using the GA4GH schemas, stuff in 23andMe response into SearchVariantsResponse parameters
# have to return like this ("data":[]) because flask doesn't allow otherwise for security purposes
ga4gh_response = {"data":[]}
for i in range(0,len(ttam_response),2):
# had to switch from p.Variant to something else due to json serialization errors. this took hours of head banging :(
response = {"reference_name":session["chrome"].encode('ascii'), "alternate_bases":[ttam_response[i+1]["allele"].encode('ascii')], "reference_bases":ttam_response[i]["allele"].encode('ascii'), "start":ttam_response[i]["start"], "end":ttam_response[i]["end"], "variant_set_id":"1"}
proto_response = p.fromJson(json.dumps(response), v.Variant)
ga4gh_response["data"].append(response)
if profile_variant_response.status_code == 200:
# ga4gh_response is ths JSON we want, push it to results.html so the user can see their data
return flask.render_template("results.html", ga4gh_response=ga4gh_response)
else:
profile_variant_response.raise_for_status()
app.secret_key = keys.sessions_key
if __name__ == "__main__":
print "A local client for GA4GHandMe is now initialized."
app.run(debug=False, port=PORT)