Finish script cleanup: PEP8, PEP257
This commit is contained in:
parent
021398c573
commit
0b7faf8784
@ -1,71 +1,202 @@
|
|||||||
from flask import Flask, render_template, request, redirect, url_for
|
"""A script for the Sortierhut Game
|
||||||
from wtforms import Form, StringField, SelectField, RadioField, TextAreaField, BooleanField, validators
|
|
||||||
|
Based on the Flask and WTForms web frameworks.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__version__ = '0.0'
|
||||||
|
__author__ = 'aamma, asauer'
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
import csv
|
import csv
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from flask import Flask, render_template, request, redirect, url_for
|
||||||
|
from wtforms import Form, StringField, SelectField, RadioField, TextAreaField, BooleanField, validators
|
||||||
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.jinja_env.trim_blocks = True
|
app.jinja_env.trim_blocks = True
|
||||||
app.jinja_env.lstrip_blocks = True
|
app.jinja_env.lstrip_blocks = True
|
||||||
|
|
||||||
|
|
||||||
datafile = "data.csv"
|
datafile = 'data.csv'
|
||||||
solutionfile = "solutions.csv"
|
solutionfile = 'solutions.csv'
|
||||||
|
|
||||||
|
|
||||||
|
def create_used_id_list():
|
||||||
|
"""Read datafile and create a list of the id in each row.
|
||||||
|
|
||||||
|
Useful to compare if a given id is already used.
|
||||||
|
"""
|
||||||
|
data = list()
|
||||||
|
if not os.path.exists(datafile):
|
||||||
|
open(datafile, 'a').close()
|
||||||
|
|
||||||
|
with open(datafile, 'r') as f:
|
||||||
|
reader = csv.reader(f)
|
||||||
|
|
||||||
|
for line in reader:
|
||||||
|
# line[0] is the row's id
|
||||||
|
data.append(line[0])
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def convert_csv_to_list_of_lists(csv_file):
|
||||||
|
"""Convert a csv file to a list whose items are lists.
|
||||||
|
|
||||||
|
csv_file -- a valid comma-separated file.
|
||||||
|
|
||||||
|
Useful because a list of lists can be easily iterated.
|
||||||
|
"""
|
||||||
|
list_of_lists = list()
|
||||||
|
|
||||||
|
if not os.path.exists(csv_file):
|
||||||
|
open(csv_file, 'a').close()
|
||||||
|
|
||||||
|
with open(csv_file, 'r', newline='') as f:
|
||||||
|
reader = csv.reader(f)
|
||||||
|
|
||||||
|
for line in reader:
|
||||||
|
list_of_lists.append(line)
|
||||||
|
|
||||||
|
return list_of_lists
|
||||||
|
|
||||||
|
|
||||||
def check_input(form, field):
|
def check_input(form, field):
|
||||||
|
"""Check if a SelectField from the questions() is still in default mode.
|
||||||
|
|
||||||
|
form -- the form on which this function is called (instance of QuestionForm).
|
||||||
|
field -- the form field whose input is checked.
|
||||||
|
"""
|
||||||
if field.data == 'default':
|
if field.data == 'default':
|
||||||
raise validators.ValidationError('Bitte wähle eine Option aus')
|
raise validators.ValidationError('Bitte wähle eine Option aus')
|
||||||
|
|
||||||
|
|
||||||
class QuestionForm(Form):
|
|
||||||
computers = [('default', 'Bitte auswählen'), ('hal', 'HAL 9000 (2001: Odyssee im Weltraum)'), ('deepthought', 'Deep Thought (Hitchhiker\'s Guide)'), ('neuromancer', 'Neuromancer (Neuromancer)'), ('samantha', 'Samatha (Her)'), ('tars', 'TARS und CASE (Interstellar)')]
|
|
||||||
computer = SelectField(u'Fiktionaler Lieblingscomputer', choices=computers, validators=[validators.InputRequired(), check_input])
|
|
||||||
statuses = [('default', 'Bitte auswählen'), ('200', '200 OK'), ('300', '300 Multiple Choices'), ('301', '301 Moved Permanently'), ('402', '402 Payment Required'), ('404', '404 (Sleep) Not Found'), ('408', '408 Request Timeout'), ('418', '418 I am a teapot'), ('450', '450 Blocked by Windows Parental Controls'), ('451', '451 Unavailable For Legal Reasons'), ('502', '502 Bad Gateway (Internetkurort)')]
|
|
||||||
status = SelectField(u'Welcher HTTP-Statuscode trifft am häufigsten auf dich zu?', choices=statuses, validators=[validators.InputRequired(), check_input])
|
|
||||||
vegetables = [('default', 'Bitte auswählen'), ('karotte', '🥕'), ('broccoli','🥦'), ('aubergine', '🍆'), ('kartoffel', '🥔'), ('bretzel', '🥨'), ('tomate', '🍅'), ('chili', '🌶️')]
|
|
||||||
vegetable = SelectField(u'Lieblingsgemüse', choices=vegetables, validators=[validators.InputRequired(), check_input])
|
|
||||||
spirit_animals = [('default', 'Bitte auswählen'), ('feuer', 'Feuerfuchs'), ('wasser', 'Wasserhahn'), ('erde', 'Erdferkel'), ('luft', 'Luftschlange')]
|
|
||||||
spirit_animal = SelectField(u'Spirit Animal', choices=spirit_animals, validators=[validators.InputRequired(), check_input])
|
|
||||||
operating_systems = [('default', 'Bitte auswählen'), ('windows', 'Windows'), ('mac', 'Mac'), ('linux', 'Linux'), ('kaffee', 'Kaffee'), ('glados', 'GLaDOS')]
|
|
||||||
operating_system = SelectField(u'Bevorzugtes Betriebssystem', choices=operating_systems, validators=[validators.InputRequired(), check_input])
|
|
||||||
check = BooleanField('Bitte nicht ankreuzen')
|
|
||||||
|
|
||||||
|
|
||||||
class SolutionForm(Form):
|
|
||||||
user_id = StringField('id', [validators.InputRequired()])
|
|
||||||
choices = [('computer', 'Fiktionaler Lieblingscomputer'), ('status', 'HTTP-Statuscode'), ('vegetable', 'Lieblingsgemüse'), ('spirit_animal', 'Spirit Animal'), ('operating system', 'Betriebssystem'), ('check', 'Bitte nicht ankreuzen')]
|
|
||||||
question = RadioField(u'Welche Frage ist ausschlaggebend für die Hauszuordnung?', choices=choices, validators=[validators.InputRequired(message='Bitte ankreuzen'),])
|
|
||||||
solution_text = TextAreaField(u'Textfeld')
|
|
||||||
|
|
||||||
def create_used_id_list():
|
|
||||||
data = list()
|
|
||||||
if not os.path.exists(datafile):
|
|
||||||
open(datafile, "a").close()
|
|
||||||
|
|
||||||
with open(datafile, "r") as f:
|
|
||||||
reader = csv.reader(f)
|
|
||||||
for line in reader:
|
|
||||||
data.append(line[0])
|
|
||||||
return data
|
|
||||||
|
|
||||||
def check_id(form, field):
|
def check_id(form, field):
|
||||||
|
"""Check if the datafile contains a given id.
|
||||||
|
|
||||||
|
form -- the form on which this function is called (instance of AnswerForm).
|
||||||
|
field -- the id input field whose input is checked.
|
||||||
|
"""
|
||||||
used_ids = create_used_id_list()
|
used_ids = create_used_id_list()
|
||||||
if field.data not in used_ids:
|
if field.data not in used_ids:
|
||||||
raise validators.ValidationError('Leider keine gültige ID')
|
raise validators.ValidationError('Leider keine gültige ID')
|
||||||
|
|
||||||
|
|
||||||
|
class QuestionForm(Form):
|
||||||
|
"""A form of humorous questions."""
|
||||||
|
computers = [
|
||||||
|
('default', 'Bitte auswählen'),
|
||||||
|
('hal', 'HAL 9000 (2001: Odyssee im Weltraum)'),
|
||||||
|
('deepthought', 'Deep Thought (Hitchhiker\'s Guide)'),
|
||||||
|
('neuromancer', 'Neuromancer (Neuromancer)'),
|
||||||
|
('samantha', 'Samatha (Her)'),
|
||||||
|
('tars', 'TARS und CASE (Interstellar)')
|
||||||
|
]
|
||||||
|
statuses = [
|
||||||
|
('default', 'Bitte auswählen'),
|
||||||
|
('200', '200 OK'),
|
||||||
|
('300', '300 Multiple Choices'),
|
||||||
|
('301', '301 Moved Permanently'),
|
||||||
|
('402', '402 Payment Required'),
|
||||||
|
('404', '404 (Sleep) Not Found'),
|
||||||
|
('408', '408 Request Timeout'),
|
||||||
|
('418', '418 I am a teapot'),
|
||||||
|
('450', '450 Blocked by Windows Parental Controls'),
|
||||||
|
('451', '451 Unavailable For Legal Reasons'),
|
||||||
|
('502', '502 Bad Gateway (Internetkurort)')
|
||||||
|
]
|
||||||
|
vegetables = [
|
||||||
|
('default', 'Bitte auswählen'),
|
||||||
|
('karotte', '🥕 Karotte'),
|
||||||
|
('broccoli','🥦 Brokkoli'),
|
||||||
|
('aubergine', '🍆 Aubergine'),
|
||||||
|
('kartoffel', '🥔 Kartoffel'),
|
||||||
|
('bretzel', '🥨 Bretzel'),
|
||||||
|
('tomate', '🍅 Tomate'),
|
||||||
|
('chili', '🌶️ Chili')
|
||||||
|
]
|
||||||
|
spirit_animals = [
|
||||||
|
('default', 'Bitte auswählen'),
|
||||||
|
('feuer', 'Feuerfuchs'),
|
||||||
|
('wasser', 'Wasserhahn'),
|
||||||
|
('erde', 'Erdferkel'),
|
||||||
|
('luft', 'Luftschlange')
|
||||||
|
]
|
||||||
|
operating_systems = [
|
||||||
|
('default', 'Bitte auswählen'),
|
||||||
|
('windows', 'Windows'),
|
||||||
|
('mac', 'Mac'),
|
||||||
|
('linux', 'Linux'),
|
||||||
|
('kaffee', 'Kaffee'),
|
||||||
|
('glados', 'GLaDOS')
|
||||||
|
]
|
||||||
|
|
||||||
|
computer = SelectField(u'Fiktionaler Lieblingscomputer', choices=computers,
|
||||||
|
validators=[validators.InputRequired(), check_input])
|
||||||
|
status = SelectField(u'Welcher HTTP-Statuscode trifft am häufigsten auf dich zu?',
|
||||||
|
choices=statuses,
|
||||||
|
validators=[validators.InputRequired(), check_input])
|
||||||
|
vegetable = SelectField(u'Lieblingsgemüse', choices=vegetables,
|
||||||
|
validators=[validators.InputRequired(), check_input])
|
||||||
|
spirit_animal = SelectField(u'Spirit Animal', choices=spirit_animals,
|
||||||
|
validators=[validators.InputRequired(), check_input])
|
||||||
|
operating_system = SelectField(u'Bevorzugtes Betriebssystem', choices=operating_systems,
|
||||||
|
validators=[validators.InputRequired(), check_input])
|
||||||
|
check = BooleanField('Bitte nicht ankreuzen')
|
||||||
|
|
||||||
|
|
||||||
class AnswerForm(Form):
|
class AnswerForm(Form):
|
||||||
|
"""A form for a user_id as a sort of password."""
|
||||||
user_id = StringField('Id', [validators.InputRequired(), check_id])
|
user_id = StringField('Id', [validators.InputRequired(), check_id])
|
||||||
|
|
||||||
|
|
||||||
|
class SolutionForm(Form):
|
||||||
|
"""A form for a solution idea for the Sortierhut riddle."""
|
||||||
|
choices = [
|
||||||
|
('computer', 'Fiktionaler Lieblingscomputer'),
|
||||||
|
('status', 'HTTP-Statuscode'),
|
||||||
|
('vegetable', 'Lieblingsgemüse'),
|
||||||
|
('spirit_animal', 'Spirit Animal'),
|
||||||
|
('operating system', 'Betriebssystem'),
|
||||||
|
('check', 'Bitte nicht ankreuzen')
|
||||||
|
]
|
||||||
|
|
||||||
|
user_id = StringField('id', [validators.InputRequired(),])
|
||||||
|
question = RadioField(choices=choices, validators=[validators.InputRequired(),])
|
||||||
|
solution_text = TextAreaField(u'Textfeld')
|
||||||
|
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
|
"""Display a home page with an explanation and many navigation links."""
|
||||||
return render_template('index.html', title='Sortierhut')
|
return render_template('index.html', title='Sortierhut')
|
||||||
|
|
||||||
|
|
||||||
@app.route('/questions', methods=['GET', 'POST'])
|
@app.route('/questions', methods=['GET', 'POST'])
|
||||||
def questions():
|
def questions():
|
||||||
|
"""Display a form with some questions.
|
||||||
|
|
||||||
|
Raise ValidationError and stay on questions() page
|
||||||
|
if any of the dropdown fields are still in the default position on
|
||||||
|
"Bitte auswählen".
|
||||||
|
|
||||||
|
Else redirect to result().
|
||||||
|
"""
|
||||||
|
def generate_id():
|
||||||
|
"""Generate a new unique user id."""
|
||||||
|
data = create_used_id_list()
|
||||||
|
# best loop ever
|
||||||
|
while True:
|
||||||
|
new_id = str(uuid.uuid1()).split('-')[0]
|
||||||
|
if new_id in data:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
return new_id
|
||||||
|
|
||||||
form = QuestionForm(request.form)
|
form = QuestionForm(request.form)
|
||||||
|
# Assign a number to each house
|
||||||
houses = dict()
|
houses = dict()
|
||||||
houses[0] = 'knuth'
|
houses[0] = 'knuth'
|
||||||
houses[1] = 'lovelace'
|
houses[1] = 'lovelace'
|
||||||
@ -74,97 +205,139 @@ def questions():
|
|||||||
houses[8] = 'lamarr'
|
houses[8] = 'lamarr'
|
||||||
|
|
||||||
if request.method == 'POST' and form.validate():
|
if request.method == 'POST' and form.validate():
|
||||||
with open(datafile, "a", newline='') as f:
|
with open(datafile, 'a', newline='') as f:
|
||||||
new_row = list()
|
new_row = list()
|
||||||
new_id = generate_id()
|
new_id = generate_id()
|
||||||
new_row.append(new_id)
|
new_row.append(new_id)
|
||||||
|
|
||||||
for item in request.form:
|
for item in request.form:
|
||||||
new_row.append(request.form[item])
|
new_row.append(request.form[item])
|
||||||
|
|
||||||
|
# If the BooleanField is not checked,
|
||||||
|
# the request.form dict does not contain an entry for 'check'
|
||||||
if len(new_row) == 6:
|
if len(new_row) == 6:
|
||||||
new_row.append('n')
|
new_row.append('n')
|
||||||
|
|
||||||
|
# This is the riddle's kern:
|
||||||
|
# Compute the mod 10 of the selected http status code
|
||||||
|
# and this then determines the sorting
|
||||||
magical_house_number = int(new_row[2]) % 10
|
magical_house_number = int(new_row[2]) % 10
|
||||||
new_row.append(houses[magical_house_number])
|
new_row.append(houses[magical_house_number])
|
||||||
|
|
||||||
writer = csv.writer(f)
|
writer = csv.writer(f)
|
||||||
writer.writerow(new_row)
|
writer.writerow(new_row)
|
||||||
|
|
||||||
return redirect(url_for('result', user_id=new_id))
|
return redirect(url_for('result', user_id=new_id))
|
||||||
|
|
||||||
return render_template('questions.html', form=form, title='Sortierhut')
|
return render_template('questions.html', form=form, title='Sortierhut')
|
||||||
|
|
||||||
@app.route('/submit_solution', methods=['GET', 'POST'])
|
|
||||||
def submit_solution():
|
|
||||||
form = SolutionForm(request.form)
|
|
||||||
if request.method == 'POST' and form.validate():
|
|
||||||
with open(solutionfile, "a", newline='') as f:
|
|
||||||
solution_list = list()
|
|
||||||
for item in request.form:
|
|
||||||
solution_list.append(request.form[item])
|
|
||||||
writer = csv.writer(f)
|
|
||||||
writer.writerow(solution_list)
|
|
||||||
return redirect(url_for('thanks'))
|
|
||||||
return render_template('submit_solution.html', form=form, title='Sortierhut')
|
|
||||||
|
|
||||||
@app.route('/result<user_id>')
|
@app.route('/result<user_id>')
|
||||||
def result(user_id):
|
def result(user_id):
|
||||||
|
"""Display the user's id and a comment on what to do next.
|
||||||
|
|
||||||
|
user_id -- argument passed by redirect call in the questions() function.
|
||||||
|
|
||||||
|
Only called in questions().
|
||||||
|
"""
|
||||||
return render_template('result.html', title='Sortierhut', id=user_id)
|
return render_template('result.html', title='Sortierhut', id=user_id)
|
||||||
|
|
||||||
def convert_csv_to_list_of_lists(csv_file):
|
|
||||||
list_of_lists = list()
|
|
||||||
|
|
||||||
if not os.path.exists(csv_file):
|
|
||||||
open(csv_file, 'a').close()
|
|
||||||
|
|
||||||
with open(csv_file, 'r', newline='') as f:
|
|
||||||
reader = csv.reader(f)
|
|
||||||
for line in reader:
|
|
||||||
list_of_lists.append(line)
|
|
||||||
return list_of_lists
|
|
||||||
|
|
||||||
@app.route('/admint_form')
|
|
||||||
def admin_form():
|
|
||||||
file_data = convert_csv_to_list_of_lists(datafile)
|
|
||||||
return render_template('admin_form.html', title='Sortierhut', text='Hallo, Admin Fooboar', file_data=file_data)
|
|
||||||
|
|
||||||
@app.route('/admint_solution')
|
|
||||||
def admin_solution():
|
|
||||||
file_data = convert_csv_to_list_of_lists(solutionfile)
|
|
||||||
return render_template('admin_solution.html', title='Sortierhut', file_data=file_data)
|
|
||||||
|
|
||||||
@app.route('/answers', methods=['GET', 'POST'])
|
@app.route('/answers', methods=['GET', 'POST'])
|
||||||
def access_answers():
|
def access_answers():
|
||||||
|
"""Display a form for an id that is needed to access the corresponded answers.
|
||||||
|
|
||||||
|
Raise ValidationError and stay on access_answers() page
|
||||||
|
if no id is submitted or the id is not valid.
|
||||||
|
|
||||||
|
Else redirect to view_answers() page.
|
||||||
|
"""
|
||||||
form = AnswerForm(request.form)
|
form = AnswerForm(request.form)
|
||||||
|
|
||||||
if request.method == 'POST' and form.validate():
|
if request.method == 'POST' and form.validate():
|
||||||
ident = request.form['user_id']
|
ident = request.form['user_id']
|
||||||
return redirect(url_for('view_access_answers', user_id=ident))
|
return redirect(url_for('view_answers', user_id=ident))
|
||||||
|
|
||||||
return render_template('access_answers.html', form=form, title='Sortierhut')
|
return render_template('access_answers.html', form=form, title='Sortierhut')
|
||||||
|
|
||||||
|
|
||||||
@app.route('/view_answers<user_id>')
|
@app.route('/view_answers<user_id>')
|
||||||
def view_answers(user_id):
|
def view_answers(user_id):
|
||||||
|
"""Display the user's answers.
|
||||||
|
|
||||||
|
user_id -- argument passed by the redirect call in the access_answers() function.
|
||||||
|
|
||||||
|
Only called in access_answers().
|
||||||
|
"""
|
||||||
|
# Create list object to be filled with the datafile row matching the user_id
|
||||||
user_row = list()
|
user_row = list()
|
||||||
with open(datafile, "r", newline='') as f:
|
|
||||||
|
with open(datafile, 'r', newline='') as f:
|
||||||
reader = csv.reader(f)
|
reader = csv.reader(f)
|
||||||
|
|
||||||
for line in reader:
|
for line in reader:
|
||||||
|
# line[0] is the row's id
|
||||||
if line[0] == user_id:
|
if line[0] == user_id:
|
||||||
user_row = line
|
user_row = line
|
||||||
break
|
break
|
||||||
return render_template('view_answers.html', title='Sortierhut', user_id=user_id, user_row=user_row)
|
|
||||||
|
return render_template('view_answers.html', title='Sortierhut',
|
||||||
|
user_id=user_id, user_row=user_row)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/submit_solution', methods=['GET', 'POST'])
|
||||||
|
def submit_solution():
|
||||||
|
"""Display a form for solution ideas.
|
||||||
|
|
||||||
|
Raise ValidationError and stay on submit_solution() page
|
||||||
|
if the form input is not valid.
|
||||||
|
|
||||||
|
Else redirect to thanks() page.
|
||||||
|
"""
|
||||||
|
form = SolutionForm(request.form)
|
||||||
|
|
||||||
|
if request.method == 'POST' and form.validate():
|
||||||
|
with open(solutionfile, 'a', newline='') as f:
|
||||||
|
solution_list = list()
|
||||||
|
|
||||||
|
# Transfer input data from request.form dict to solution_list list
|
||||||
|
for item in request.form:
|
||||||
|
solution_list.append(request.form[item])
|
||||||
|
|
||||||
|
writer = csv.writer(f)
|
||||||
|
writer.writerow(solution_list)
|
||||||
|
|
||||||
|
return redirect(url_for('thanks'))
|
||||||
|
|
||||||
|
return render_template('submit_solution.html', form=form, title='Sortierhut')
|
||||||
|
|
||||||
|
|
||||||
@app.route('/thanks')
|
@app.route('/thanks')
|
||||||
def thanks():
|
def thanks():
|
||||||
|
"""Display how the right solution will be announced.
|
||||||
|
|
||||||
|
Only called in submit_solution().
|
||||||
|
"""
|
||||||
return render_template('thanks.html', title='Sortierhut')
|
return render_template('thanks.html', title='Sortierhut')
|
||||||
|
|
||||||
|
|
||||||
@app.route('/houses')
|
@app.route('/houses')
|
||||||
def houses():
|
def houses():
|
||||||
|
"""Display a description of the 5 groups (=houses)."""
|
||||||
return render_template('houses.html', title='Sortierhut')
|
return render_template('houses.html', title='Sortierhut')
|
||||||
|
|
||||||
def generate_id():
|
|
||||||
data = create_used_id_list()
|
|
||||||
# best loop ever
|
|
||||||
while True:
|
|
||||||
new_id = str(uuid.uuid1()).split("-")[0]
|
|
||||||
|
|
||||||
if new_id in data:
|
@app.route('/admint_form')
|
||||||
break
|
def admin_form():
|
||||||
else:
|
"""Display a table of the data from submitted question form."""
|
||||||
return new_id
|
file_data = convert_csv_to_list_of_lists(datafile)
|
||||||
|
return render_template('admin_form.html', title='Sortierhut',
|
||||||
|
text='Hallo, Admin Fooboar', file_data=file_data)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/admint_solution')
|
||||||
|
def admin_solution():
|
||||||
|
"""Display a table of the submitted solutions."""
|
||||||
|
file_data = convert_csv_to_list_of_lists(solutionfile)
|
||||||
|
return render_template('admin_solution.html', title='Sortierhut', file_data=file_data)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user