forked from nprapps/dailygraphics
-
Notifications
You must be signed in to change notification settings - Fork 0
/
oauth.py
139 lines (107 loc) · 4.25 KB
/
oauth.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
#!/usr/bin/env python
import app_config
import os
from app_config import authomatic
from authomatic.adapters import WerkzeugAdapter
from exceptions import KeyError
from flask import Blueprint, make_response, redirect, render_template, url_for
from functools import wraps
from render_utils import load_graphic_config, make_context
# Via: https://developers.google.com/drive/v3/reference/files/export
# and: https://developers.google.com/drive/v3/web/manage-downloads
DRIVE_API_EXPORT_TEMPLATE = 'https://www.googleapis.com/drive/v3/files/%s/export?mimeType=%s'
oauth = Blueprint('_oauth', __name__)
@oauth.route('/oauth/')
def oauth_alert():
"""
Show an OAuth alert to start authentication process.
"""
context = make_context()
if not _has_api_credentials():
return render_template('oauth/warning.html', **context)
credentials = get_credentials()
if credentials:
resp = authomatic.access(credentials, 'https://www.googleapis.com/oauth2/v1/userinfo?alt=json')
if resp.status == 200:
context['email'] = resp.data['email']
return render_template('oauth/oauth.html', **context)
@oauth.route('/authenticate/', methods=['GET', 'POST'])
def authenticate():
"""
Run OAuth workflow.
"""
from flask import request
response = make_response()
context = make_context()
if not _has_api_credentials():
return render_template('oauth/warning.html', **context)
result = authomatic.login(WerkzeugAdapter(request, response), 'google')
if result:
context['result'] = result
if not result.error:
save_credentials(result.user.credentials)
return render_template('oauth/authenticate.html', **context)
return response
def oauth_required(f):
"""
Decorator to ensure oauth workflow has happened.
"""
@wraps(f)
def decorated_function(*args, **kwargs):
from flask import request
if request.path.startswith('/graphics/'):
slug = request.path.split('/')[-2]
graphic_path = '%s/%s' % (app_config.GRAPHICS_PATH, slug)
try:
graphic_config = load_graphic_config(graphic_path)
except IOError:
return f(*args, **kwargs)
credentials = get_credentials()
if hasattr(graphic_config, 'COPY_GOOGLE_DOC_KEY') and graphic_config.COPY_GOOGLE_DOC_KEY and (not credentials or not credentials.valid):
return redirect(url_for('_oauth.oauth_alert'))
return f(*args, **kwargs)
return decorated_function
def get_credentials():
"""
Read Authomatic credentials object from disk and refresh if necessary.
"""
file_path = os.path.expanduser(app_config.GOOGLE_OAUTH_CREDENTIALS_PATH)
try:
with open(file_path) as f:
serialized_credentials = f.read()
except IOError:
return None
credentials = authomatic.credentials(serialized_credentials)
if not credentials.valid:
credentials.refresh()
save_credentials(credentials)
return credentials
def save_credentials(credentials):
"""
Take Authomatic credentials object and save to disk.
"""
file_path = os.path.expanduser(app_config.GOOGLE_OAUTH_CREDENTIALS_PATH)
with open(file_path, 'w') as f:
f.write(credentials.serialize())
def get_document(key, file_path, mimeType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'):
"""
Uses Authomatic to get the google doc
"""
credentials = get_credentials()
url = DRIVE_API_EXPORT_TEMPLATE % (key, mimeType)
response = app_config.authomatic.access(credentials, url)
if response.status != 200:
if response.status == 404:
raise KeyError("Error! Your Google Doc does not exist or you do not have permission to access it.")
else:
raise KeyError("Error! Google returned a %s error" % response.status)
with open(file_path, 'wb') as writefile:
writefile.write(response.content)
def _has_api_credentials():
"""
Test for API credentials
"""
client_id = os.environ.get('GOOGLE_OAUTH_CLIENT_ID')
client_secret = os.environ.get('GOOGLE_OAUTH_CONSUMER_SECRET')
salt = os.environ.get('AUTHOMATIC_SALT')
return bool(client_id and client_secret and salt)