-
Notifications
You must be signed in to change notification settings - Fork 0
/
stock_flask.py
executable file
·170 lines (141 loc) · 5.05 KB
/
stock_flask.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
#!/usr/bin/env python3
"""
Main Flask application file
- This script is the WSGI form parser/validator.
- This script requires Flask to be installed.
- It expects to be passed:
- stock name from nginx html form
- It sends all returnables to return flask's render_template
"""
import json
import logging
import flask
from flask import g
from flask import Flask
from flask import request
from flask import redirect
from flask import render_template
from flask import session
from flask import url_for
from pymongo.errors import ConnectionFailure
from pymongo.errors import ServerSelectionTimeoutError
from pymongo.errors import OperationFailure
from urllib.parse import quote_plus, urlencode
from authlib.integrations.flask_client import OAuth
from lib import mongodb
from lib.mongodb import StockDoesNotExist
from lib.init import Credentials
""" nb:02/25/23 - If the Instance cannot connect to MongoDB, Nginx will return 404 """
mongocli = mongodb.MongoCli()
secrets = Credentials().get_all_credentials()
app = Flask(__name__)
app.secret_key = secrets["APP_SECRET_KEY"]
app.url_map.strict_slashes = False
logging.basicConfig(level=logging.DEBUG)
if __name__ != "__main__":
""" if no "AWS" logging in docker-compose file, access and error logs go 'docker logs'
For local logs use the following in gunicorn.conf.py
errorlog = '/tmp/stocks.error.log'
accesslog = '/tmp/stocks.access.log'
"""
gunicorn_logger = logging.getLogger("gunicorn.error")
app.logger.handlers = gunicorn_logger.handlers
app.logger.setLevel(gunicorn_logger.level)
oauth = OAuth(app)
oauth.register(
"auth0",
client_id = secrets["AUTH0_CLIENT_ID"],
client_secret = secrets["AUTH0_CLIENT_SECRET"],
client_kwargs={
"scope": "openid profile email",
},
server_metadata_url=f'https://{secrets["AUTH0_DOMAIN"]}/.well-known/openid-configuration',
)
@app.route("/")
def home():
user_data = session.get('user')
if user_data is not None:
user_info = user_data.get('userinfo')
session['first_name'] = user_info.get('given_name')
session['email'] = user_info.get('email')
session['picture_url'] = user_info.get('picture')
else:
session['picture_text'] = "Welcome - "
session['email_text'] = "There!"
return render_template("welcome.html")
@app.route("/callback", methods=["GET", "POST"])
def callback():
token = oauth.auth0.authorize_access_token()
session["user"] = token
return redirect("/")
@app.route("/login")
def login():
return oauth.auth0.authorize_redirect(
redirect_uri=url_for("callback", _external=True)
)
@app.route("/logout")
def logout():
session.clear()
return redirect(
"https://"
+ secrets["AUTH0_DOMAIN"]
+ "/v2/logout?"
+ urlencode(
{
"returnTo": url_for("home", _external=True),
"client_id": secrets["AUTH0_CLIENT_ID"],
},
quote_via=quote_plus,
)
)
@app.route("/search")
def search():
"""
Return a view to Flask with relevant details
'stock' comes in as a 'str' from the Flash HTML form and most easily is tested
by casting to 'int'. It is then queried @mongodb and returns HTML Done this way it catches stock='' and if stock is None without explictly checking.
"""
try:
querystring = request.args
app.logger.debug(f"querystring: {querystring}")
stock = querystring.get("stock")
if not str(stock):
raise ValueError
except (TypeError, ValueError):
app.logger.error(f"Invalid data: querystring: {querystring} : invalid")
return render_template("dne_stock.html")
except Exception as e:
msg = f"Bug: querystring:{querystring}, Error: {e}"
app.logger.exception(msg)
flask.abort(500)
else:
try:
stock = str(stock).upper()
g.stock = stock
stock_data = mongocli.lookup_stock(stock)
if len(stock_data) < 2:
return render_template("dne_stock.html")
if stock_data["Error"]:
return render_template("dne_stock.html")
except mongodb.StockDoesNotExist as e:
app.logger.error(str(e))
return render_template("dne_stock.html")
except ValueError as e:
app.logger.error(str(e))
return render_template("dne_stock.html")
except OperationFailure as e:
msg = "PROD FAILURE! " + str(e)
app.logger.error(msg)
return render_template("dne_stock.html")
except ConnectionFailure as e:
msg = "Connect FAILURE! " + str(e)
app.logger.error(msg)
return render_template("dne_stock.html")
except ServerSelectionTimeoutError as e:
msg = "Server FAILURE! " + str(e)
app.logger.error(msg)
return render_template("dne_stock.html")
else:
return render_template("stock_data.html", stock_data=stock_data)
if __name__ == '__main__':
app.run(debug=True)