My aim is to have a QR scanner that can take the data and check it against a list of names and emails in a Google Sheet, modifying a 'Signed In' column if necessary, and telling the user the result. (Either: Successfully signed in; Already signed in; or Not on the list.) For now, in place of the scanner, I've just got a html form where I can type in some example data to test the system out. If I get that working I can worry about the camera/QR stuff later.
I've put the code of two files below. 'flask_app.py' is what the user will see. 'UpdateSheet.py' deals with reading/changing the Google Sheet (I've tested this on its own in pythonanywhere and it works), and returns a value 1, 2, or 3 to flask_app.py depending on what's happened. I used this tutorial as my starting point and changed things around according to what I need.
Here's flask_app.py:
from flask import Flask, request
from UpdateSheet import Compare
app = Flask(__name__)
app.config["DEBUG"] = True
@app.route("/", methods=["GET", "POST"])
def adder_page():
if request.method == "POST":
QR_Data = request.form["QRData"]
result = Compare(QR_Data)
if result == 1:
return '''
<html>
<body>
<p>Successfully signed in.</p>
<p><a href="/">Click here to scan another QR Code.</a></p>
</body>
</html>
'''
elif result == 2:
return '''
<html>
<body>
<p>This person has already signed in.</p>
<p><a href="/">Click here to scan another QR Code.</a></p>
</body>
</html>
'''
elif result == 3:
return '''
<html>
<body>
<p>This person cannot be signed in: they have not completed the induction.</p>
<p><a href="/">Click here to scan another QR Code.</a></p>
</body>
</html>
'''
return '''
<html>
<body>
<form method="post" action=".">
<p><input name="QRData" />QR Code Data:</p>
<p><input type="submit" value="Sign In" /></p>
</form>
</body>
</html>
'''
And here's UpdateSheet.py:
from __future__ import print_function
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/spreadsheets']
# The ID and range of the spreadsheet.
Inductees = '1n1pTDsh3q5zPWxQLsewQ-3YBgyXKsx_t9LniZEZCDh8'
NamesAndEmails = 'Sheet1!A2:C'
SignedIn = 0 # 1=successful, 2=already signed in, 3=not done induction
creds = None
if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'/home/willsygma/mysite/credentials.json', SCOPES)
creds = flow.run_local_server()
with open('token.pickle', 'wb') as token:
pickle.dump(creds, token)
service = build('sheets', 'v4', credentials=creds)
# Call the Sheets API
sheet = service.spreadsheets()
result = sheet.values().get(spreadsheetId=Inductees,
range=NamesAndEmails).execute()
values = result.get('values', [])
def Compare(values, DataInput):
DataInput = ""
ScannedName = []
ScannedEmail = ""
DataInput = DataInput.replace('+', ' ')
for word in DataInput.split():
if '@' in word:
ScannedEmail = word
else:
ScannedName.append(word)
ScannedName = ' '.join(ScannedName) # converts list to a string
if not values: # If the sheet is blank
SignedIn = 3
else:
counter = 1
Matched = False
for Row in values:
counter+=1
if ScannedName == Row[0] and ScannedEmail == Row[1]: # a match
Matched = True
SignIn(Row, ScannedName, counter)
if Matched == False:
SignedIn = 3
return SignedIn
def SignIn(Row, Name, counter):
if Row[2] == 'Y': # if they have already signed in
SignedIn = 2
else: # if the Signed In column already reads 'Y'
SignedIn = 1
body = {'values': [["Y"]]}
sheet.values().update(
spreadsheetId=Inductees, range="C" + str(counter),
valueInputOption="RAW", body=body).execute() # Signs in
return SignedIn
The webpage is a 'Something went wrong :-(' message with Error Code: Unhandled Exception.
This is what I get in the error log:
2019-02-12 13:58:14,527: Error running WSGI application
2019-02-12 13:58:14,533: OSError: [Errno 98] Address already in use
2019-02-12 13:58:14,533: File "/var/www/willsygma_pythonanywhere_com_wsgi.py", line 16, in <module>
2019-02-12 13:58:14,533: from flask_app import app as application # noqa
2019-02-12 13:58:14,533:
2019-02-12 13:58:14,534: File "/home/willsygma/mysite/flask_app.py", line 2, in <module>
2019-02-12 13:58:14,534: from UpdateSheet import Compare
2019-02-12 13:58:14,534:
2019-02-12 13:58:14,534: File "/home/willsygma/mysite/UpdateSheet.py", line 30, in <module>
2019-02-12 13:58:14,534: creds = flow.run_local_server()
2019-02-12 13:58:14,534:
2019-02-12 13:58:14,534: File "/home/willsygma/.local/lib/python3.7/site-packages/google_auth_oauthlib/flow.py", line 407, in run_local_server
2019-02-12 13:58:14,535: host, port, wsgi_app, handler_class=_WSGIRequestHandler)
2019-02-12 13:58:14,535:
2019-02-12 13:58:14,535: File "/usr/lib/python3.7/wsgiref/simple_server.py", line 153, in make_server
2019-02-12 13:58:14,535: server = server_class((host, port), handler_class)
2019-02-12 13:58:14,535:
2019-02-12 13:58:14,535: File "/usr/lib/python3.7/socketserver.py", line 449, in __init__
2019-02-12 13:58:14,535: self.server_bind()
2019-02-12 13:58:14,536:
2019-02-12 13:58:14,536: File "/usr/lib/python3.7/wsgiref/simple_server.py", line 50, in server_bind
2019-02-12 13:58:14,536: HTTPServer.server_bind(self)
2019-02-12 13:58:14,536:
2019-02-12 13:58:14,536: File "/usr/lib/python3.7/http/server.py", line 137, in server_bind
2019-02-12 13:58:14,537: socketserver.TCPServer.server_bind(self)
2019-02-12 13:58:14,537:
2019-02-12 13:58:14,537: File "/usr/lib/python3.7/socketserver.py", line 463, in server_bind
2019-02-12 13:58:14,537: self.socket.bind(self.server_address)
I don't expect to get this working but where might I start?
NB: I've been learning Python for an embarrassing length of time with no success. I have the wrong brain for it. Basically I'm a desperate office administrator out of my depth. I've seen other threads on this error message but I am several years away from understand the answers. However I'm pretty sure they don't apply to my project. Please explain anything like you're talking to a computer-illiterate 6-year-old. Alternatively, if I should stop trying, please don't hesitate to tell me. Thanks in advance.