-
Notifications
You must be signed in to change notification settings - Fork 69
/
Copy pathapp.py
executable file
·373 lines (316 loc) · 10.8 KB
/
app.py
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
#!/usr/bin/env python
from flask import Flask, request, redirect, session, url_for, render_template, Response, jsonify, make_response, send_from_directory
from flask.ext.assets import Environment, Bundle
from flask.ext.mail import Mail
import urllib
import urlparse
import json
import random
import base64
import re
import filters
import threading
import api
from stackblink import stackblink
from skymorph import skymorph
def import_sdss():
from sdss import sdss
pass
t1 = threading.Thread(target=import_sdss)
t1.start()
app = Flask(__name__)
mail = Mail(app)
filters.register_filters(app)
app.secret_key = 'not a secret key'
try:
import local_config
app.config['ASSETS_DEBUG'] = local_config.DEBUG
except ImportError:
pass
# bundling
assets = Environment(app)
# This filter can be helping for debugging javascript.
def noop_filter(_in, out, **kw):
out.write(_in.read())
# static files
@app.route('/sitemap.xml')
@app.route('/robots.txt')
def static_from_route():
return send_from_directory(app.static_folder, request.path[1:])
# main routes
@app.route('/')
def index():
return render_template('index.html')
@app.route('/upcoming')
def upcoming():
return render_template('upcoming.html')
@app.route('/3d/')
def view_3d_slash():
return render_template('full3d.html', noop=noop_filter)
@app.route('/offline_3d')
def view_3d_offline():
pt_vars = {};
pt_vars['offline_mode'] = True
pt_vars['score_rankings'] = json.dumps(api.rankings('score', 4000, True), allow_nan=False)
pt_vars['value_rankings'] = json.dumps(api.rankings('value', 4000, True), allow_nan=False)
pt_vars['accessibility_rankings'] = json.dumps(api.rankings('accessibility', 4000, True), allow_nan=False)
pt_vars['smallest_rankings'] = json.dumps(api.rankings('smallest', 4000, True), allow_nan=False)
return render_template('full3d.html', noop=noop_filter, passthrough_vars=pt_vars, \
offline_mode=True)
@app.route('/3d/notsupported.html')
def notsupported_3d():
return render_template('notsupported.html')
@app.route('/asteroid-<asteroid_slug>')
def asteroid_details(asteroid_slug=None):
# slug is a slug of asteroid prov des
if not asteroid_slug:
return 'Sorry, could not find this asteroid in our database.', 404
unslug = asteroid_slug.replace('-', ' ')
# Need to get top 10, otherwise sometimes the best match is not returned by mongo.
candidates = api.autocomplete(unslug, 10) # TODO better way?
if len(candidates) < 1:
return 'Sorry, could not find this asteroid in our database.', 404
asteroid = candidates[0]
jpl_result = api.jpl_lookup(asteroid['prov_des'])
if 'spec' in asteroid:
composition_result = api.compositions()[asteroid['spec']]
else:
composition_result = []
return render_template('asteroid.html', asteroid=asteroid, jpl=jpl_result, composition=composition_result)
# General api routes
@app.route('/api/mpc')
def api_mpc():
try:
query = json.loads(request.args.get('query') or '{}')
limit = min(5000, int(request.args.get('limit') or 1000))
json_resp = json.dumps(api.mpc(query, limit))
return Response(json_resp, mimetype='application/json')
except Exception, e:
print str(e)
resp = jsonify({'error': 'bad request'})
resp.status_code = 500
return resp
@app.route('/api/kepler')
def api_kepler():
try:
query = json.loads(request.args.get('query'))
limit = min(1000, int(request.args.get('limit')))
json_resp = json.dumps(api.kepler(query, limit))
return Response(json_resp, mimetype='application/json')
except Exception, e:
print str(e)
resp = jsonify({'error': 'bad request'})
resp.status_code = 500
return resp
@app.route('/api/exoplanets')
def api_exoplanets():
try:
query = json.loads(request.args.get('query'))
limit = min(1000, int(request.args.get('limit')))
json_resp = json.dumps(api.exoplanets(query, limit))
return Response(json_resp, mimetype='application/json')
except ValueError:
resp = jsonify({'error': 'bad request'})
resp.status_code = 500
return resp
@app.route('/api/asterank')
def api_asterank():
try:
query = json.loads(request.args.get('query'))
limit = min(1000, int(request.args.get('limit')))
json_resp = json.dumps(api.asterank(query, limit))
return Response(json_resp, mimetype='application/json')
except Exception, e:
print str(e)
resp = jsonify({'error': 'bad request'})
resp.status_code = 500
return resp
@app.route('/api/rankings')
def rankings():
try:
limit = int(request.args.get('limit')) or 10
orbital_info_only = request.args.get('orbits_only')
results = api.rankings(request.args.get('sort_by'), limit, orbits_only=orbital_info_only)
json_resp = json.dumps(results)
return Response(json_resp, mimetype='application/json', headers={ \
'Cache-Control': 'max-age=432000', # 5 days
})
except Exception, e:
resp = jsonify({'error': 'bad request', 'details': str(e)})
resp.status_code = 500
return resp
@app.route('/api/autocomplete')
def autocomplete():
results = api.autocomplete(request.args.get('query'), 10)
json_resp = json.dumps(results)
return Response(json_resp, mimetype='application/json', headers={ \
'Cache-Control': 'max-age=432000', # 5 days
})
@app.route('/api/compositions')
def compositions():
json_resp = json.dumps(api.compositions())
return Response(json_resp, mimetype='application/json')
@app.route('/jpl/lookup')
def horizons():
query = request.args.get('query')
result = api.jpl_lookup(query)
if result:
json_resp = json.dumps(result)
return Response(json_resp, mimetype='application/json')
else:
return Response('{}', mimetype='application/json')
# Skymorph routes
@app.route('/api/skymorph/search')
def skymorph_search_target():
return jsonify({'results': skymorph.search_target(request.args.get('target'))})
@app.route('/api/skymorph/images_for')
def skymorph_images_for():
return jsonify({'images': skymorph.images_for(request.args.get('target'))})
@app.route('/api/skymorph/search_orbit')
def skymorph_search_orbit():
search_results = skymorph.search_ephem( \
request.args.get('epoch'),
request.args.get('ecc'),
request.args.get('per'),
request.args.get('per_date'),
request.args.get('om'),
request.args.get('w'),
request.args.get('i'),
request.args.get('H'),
)
ret = {'results': search_results}
return jsonify(ret)
@app.route('/api/skymorph/search_position')
def skymorph_search_time():
search_results = skymorph.search_position( \
request.args.get('ra'),
request.args.get('dec'),
request.args.get('time'),
)
ret = {'results': search_results}
return jsonify(ret)
@app.route('/api/skymorph/image')
def skymorph_image():
ret = skymorph.get_image(request.args.get('key'))
if type(ret) == dict:
return jsonify(ret)
else:
response = make_response(ret)
response.headers['Content-type'] = 'image/gif'
return response
@app.route('/api/skymorph/fast_image')
def skymorph_fast_image():
ret = skymorph.get_fast_image(request.args.get('key'))
if type(ret) == dict:
return jsonify(ret)
else:
response = make_response(ret)
response.headers['Content-type'] = 'image/png'
return response
# SDSS routes
@app.route('/api/sdss/get_unknown_group')
def sdss_unknown_group():
from sdss import sdss
json_resp = json.dumps(sdss.get_unknown_group())
return Response(json_resp, mimetype='application/json', headers={ \
'Cache-Control': 'no-cache',
})
@app.route('/api/sdss/image')
def sdss_image():
from sdss import sdss
ret = sdss.image_from_key(request.args.get('key'))
response = make_response(ret)
response.headers['Content-type'] = 'image/png'
return response
# Stack/blink Discover routes
@app.route('/discover')
def discover():
first_time = session.get('discover_first_time', True)
session['discover_first_time'] = False
return render_template('discover.html',
first_time=first_time,
image_count=stackblink.get_image_count(),
interesting_count=stackblink.get_interesting_count(),
user_count=stackblink.get_user_count(),
)
@app.route('/api/stackblink/get_neat_control_group')
def get_neat_control_group():
json_resp = json.dumps(stackblink.get_control_groups())
return Response(json_resp, mimetype='application/json', headers={ \
'Cache-Control': 'no-cache',
})
@app.route('/api/stackblink/get_sdss_unknown_group')
def get_sdss_unknown_group():
from sdss import sdss
json_resp = json.dumps(sdss.get_unknown_group())
return Response(json_resp, mimetype='application/json', headers={ \
'Cache-Control': 'no-cache',
})
@app.route('/api/stackblink/record', methods=['GET', 'POST'])
def stackblink_record():
postdata = json.loads(request.data)
json_resp = json.dumps(stackblink.record( \
postdata.get('email', None), \
postdata.get('keys', None), \
postdata.get('interesting', None), \
postdata.get('poor_quality', None)))
return Response(json_resp, mimetype='application/json', headers={ \
'Cache-Control': 'no-cache',
})
# Kepler
@app.route('/exoplanets')
@app.route('/kepler3d')
def kepler3d():
return render_template('kepler3d.html')
# User custom objects
@app.route('/api/user_objects', methods=['GET', 'POST'])
def user_objects():
if request.method == 'GET':
return jsonify({'results': api.retrieve_user_objects(300)}) # limit set to 300 objects for now
postdata = json.loads(request.data)
if 'object' not in postdata:
return jsonify({})
obj = postdata['object']
image_keys = postdata.get('keys', None)
return jsonify(api.insert_user_object(obj, image_keys))
# Other Pages
@app.route('/about', methods=['GET', 'POST'])
def about():
if request.method == 'GET':
return render_template('about.html')
else:
email = request.form.get('email', None)
feedback = request.form.get('feedback', None)
if not feedback or feedback.find('a href') > -1:
return 'Form rejected because you look like a spambot. Please email me directly.'
from flask.ext.mail import Message
msg = Message('Asterank Feedback',
sender='[email protected]',
recipients=['[email protected]'],
body='%s:\r\n%s' % (email, feedback))
mail.send(msg)
return render_template('about.html')
@app.route('/feedback')
@app.route('/contact')
def contact():
return render_template('contact.html')
@app.route('/mpc')
def mpc():
return render_template('mpc.html')
@app.route('/kepler')
def kepler():
return render_template('kepler.html')
@app.route('/exoplanets')
def exoplanets():
return render_template('exoplanets.html')
@app.route('/neat')
def neat_docs():
return redirect('/skymorph')
@app.route('/skymorph')
def skymorph_docs():
return render_template('skymorph.html')
@app.route('/api')
def api_route():
return render_template('api.html')
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', use_reloader=True, threaded=True)