Compare commits
7 Commits
sqlite-gro
...
6d5f74bd62
Author | SHA1 | Date | |
---|---|---|---|
6d5f74bd62 | |||
2e00d503c8 | |||
516c2cdf81 | |||
8f9b78ac32 | |||
17b985d238 | |||
69a0791a6d | |||
4414d1720e |
@ -117,7 +117,8 @@ server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
# Redirect to non-www
|
||||
return 301 $scheme://domain_name$request_uri; ...
|
||||
return 301 $scheme://domain_name$request_uri;
|
||||
...
|
||||
}
|
||||
|
||||
server {
|
||||
|
@ -2,16 +2,17 @@
|
||||
<meta property="og:locale" content="en_UK" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:description" content="A web app for taking the Scottish Korfball Association Refereeing Theory Exam on-line." />
|
||||
<meta property="og:url" content="{{ url_for(request.endpoint, _external = True, **request.view_args) }}" />
|
||||
<meta property="og:url" content="{{ url_for(request.endpoint, _external = True, **(request.view_args or {})) }}" />
|
||||
<meta property="og:site_name" content="Scottish Korfball Association Referee Theory Exam" />
|
||||
<meta property="og:image" content="{{ url_for('static', filename='favicon.png', _external = True) }}" />
|
||||
<meta property="og:image" content="{{ url_for('.static', filename='favicon.png', _external = True) }}" />
|
||||
<meta property="og:image:alt" content="Logo of the SKA Refereeing Exam App" />
|
||||
<meta property="og:image:width" content="512" />
|
||||
<meta property="og:image:height" content="512" />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:description" content="A web app for taking the Scottish Korfball Association Refereeing Theory Exam on-line." />
|
||||
<meta name="twitter:image" content="{{ url_for('static', filename='favicon.png', _external = True) }}" />
|
||||
<meta name="twitter:image" content="{{ url_for('.static', filename='favicon.png', _external = True) }}" />
|
||||
<meta name="twitter:image:alt" content="Logo of the SKA Refereeing Exam App" />
|
||||
<meta name="twitter:creator" content="@viveksantayana" />
|
||||
<meta name="twitter:site" content="@viveksantayana" />
|
||||
<meta name="theme-color" content="#343a40" />
|
||||
<meta name="theme-color" content="#343a40" />
|
||||
<link rel="shortcut icon" href="{{ url_for('.static', filename='favicon.ico') }}">
|
@ -28,10 +28,10 @@ class Config(object):
|
||||
MAIL_SUPPRESS_SEND = False
|
||||
MAIL_ASCII_ATTACHMENTS = bool(os.getenv('MAIL_ASCII_ATTACHMENTS'))
|
||||
|
||||
class ProductionConfig(Config):
|
||||
class Production(Config):
|
||||
pass
|
||||
|
||||
class DevelopmentConfig(Config):
|
||||
class Development(Config):
|
||||
APP_HOST = '127.0.0.1'
|
||||
DEBUG = True
|
||||
SESSION_COOKIE_SECURE = False
|
||||
@ -39,7 +39,7 @@ class DevelopmentConfig(Config):
|
||||
MAIL_DEBUG = True
|
||||
MAIL_SUPPRESS_SEND = False
|
||||
|
||||
class TestingConfig(DevelopmentConfig):
|
||||
class Testing(Development):
|
||||
TESTING = True
|
||||
SESSION_COOKIE_SECURE = False
|
||||
MAIL_SERVER = os.getenv('MAIL_SERVER')
|
||||
|
@ -2,16 +2,17 @@
|
||||
<meta property="og:locale" content="en_UK" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:description" content="A web app for taking the Scottish Korfball Association Refereeing Theory Exam on-line." />
|
||||
<meta property="og:url" content="{{ url_for(request.endpoint, _external = True, **request.view_args) }}" />
|
||||
<meta property="og:url" content="{{ url_for(request.endpoint, _external = True, **(request.view_args or {})) }}" />
|
||||
<meta property="og:site_name" content="Scottish Korfball Association Referee Theory Exam" />
|
||||
<meta property="og:image" content="{{ url_for('static', filename='favicon.png', _external = True) }}" />
|
||||
<meta property="og:image" content="{{ url_for('.static', filename='favicon.png', _external = True) }}" />
|
||||
<meta property="og:image:alt" content="Logo of the SKA Refereeing Exam App" />
|
||||
<meta property="og:image:width" content="512" />
|
||||
<meta property="og:image:height" content="512" />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:description" content="A web app for taking the Scottish Korfball Association Refereeing Theory Exam on-line." />
|
||||
<meta name="twitter:image" content="{{ url_for('static', filename='favicon.png', _external = True) }}" />
|
||||
<meta name="twitter:image" content="{{ url_for('.static', filename='favicon.png', _external = True) }}" />
|
||||
<meta name="twitter:image:alt" content="Logo of the SKA Refereeing Exam App" />
|
||||
<meta name="twitter:creator" content="@viveksantayana" />
|
||||
<meta name="twitter:site" content="@viveksantayana" />
|
||||
<meta name="theme-color" content="#343a40" />
|
||||
<meta name="theme-color" content="#343a40" />
|
||||
<link rel="shortcut icon" href="{{ url_for('.static', filename='favicon.ico') }}">
|
@ -1,8 +1,82 @@
|
||||
{% extends "components/base.html" %}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
|
||||
rel="stylesheet"
|
||||
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
|
||||
crossorigin="anonymous">
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.1/font/bootstrap-icons.css">
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="{{ url_for('views.static', filename='css/style.css') }}"
|
||||
/>
|
||||
<link rel="shortcut icon" href="{{ url_for('views.static', filename='favicon.ico') }}">
|
||||
{% block style %}
|
||||
{% endblock %}
|
||||
<title>{% block title %} SKA Referee Test Beta {% endblock %}</title>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
|
||||
{% block content %}
|
||||
<h1>Page Not Found</h1>
|
||||
<p>
|
||||
The page you were looking for does not exist. Try going back and navigating to the desired destination correctly.
|
||||
</p>
|
||||
{% endblock %}
|
||||
{% block navbar %}
|
||||
{% include "components/navbar.html" %}
|
||||
{% endblock %}
|
||||
|
||||
<div class="container quiz-container">
|
||||
{% block top_alerts %}
|
||||
{% include "components/server-alerts.html" %}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h1>Page Not Found</h1>
|
||||
<p>
|
||||
The page you were looking for does not exist. Try going back and navigating to the desired destination correctly.
|
||||
</p>
|
||||
{% endblock %}
|
||||
<footer class="container site-footer">
|
||||
{% include "components/footer.html" %}
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<!-- JQuery, Popper, and Bootstrap js dependencies -->
|
||||
<script
|
||||
src="https://code.jquery.com/jquery-3.6.0.min.js"
|
||||
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
|
||||
crossorigin="anonymous">
|
||||
</script>
|
||||
<script>
|
||||
window.jQuery || document.write(`<script src="{{ url_for('.static', filename='js/jquery-3.6.0.min.js') }}"><\/script>`)
|
||||
</script>
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.10.2/dist/umd/popper.min.js"
|
||||
integrity="sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB"
|
||||
crossorigin="anonymous">
|
||||
</script>
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js"
|
||||
integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
<!-- Custom js -->
|
||||
<script type="text/javascript">
|
||||
var csrf_token = "{{ csrf_token() }}";
|
||||
|
||||
$.ajaxSetup({
|
||||
beforeSend: function(xhr, settings) {
|
||||
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
|
||||
xhr.setRequestHeader("X-CSRFToken", csrf_token);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="{{ url_for('views.static', filename='js/script.js') }}"
|
||||
></script>
|
||||
{% block script %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
@ -2,16 +2,17 @@
|
||||
<meta property="og:locale" content="en_UK" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:description" content="A web app for taking the Scottish Korfball Association Refereeing Theory Exam on-line." />
|
||||
<meta property="og:url" content="{{ url_for(request.endpoint, _external = True, **request.view_args) }}" />
|
||||
<meta property="og:url" content="{{ url_for(request.endpoint, _external = True, **(request.view_args or {})) }}" />
|
||||
<meta property="og:site_name" content="Scottish Korfball Association Referee Theory Exam" />
|
||||
<meta property="og:image" content="{{ url_for('static', filename='favicon.png', _external = True) }}" />
|
||||
<meta property="og:image" content="{{ url_for('.static', filename='favicon.png', _external = True) }}" />
|
||||
<meta property="og:image:alt" content="Logo of the SKA Refereeing Exam App" />
|
||||
<meta property="og:image:width" content="512" />
|
||||
<meta property="og:image:height" content="512" />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:description" content="A web app for taking the Scottish Korfball Association Refereeing Theory Exam on-line." />
|
||||
<meta name="twitter:image" content="{{ url_for('static', filename='favicon.png', _external = True) }}" />
|
||||
<meta name="twitter:image" content="{{ url_for('.static', filename='favicon.png', _external = True) }}" />
|
||||
<meta name="twitter:image:alt" content="Logo of the SKA Refereeing Exam App" />
|
||||
<meta name="twitter:creator" content="@viveksantayana" />
|
||||
<meta name="twitter:site" content="@viveksantayana" />
|
||||
<meta name="theme-color" content="#343a40" />
|
||||
<meta name="theme-color" content="#343a40" />
|
||||
<link rel="shortcut icon" href="{{ url_for('views.static', filename='favicon.ico') }}">
|
@ -19,6 +19,39 @@ def validate_json(file):
|
||||
file.stream.seek(0)
|
||||
data = json.loads(file.read())
|
||||
if not isinstance(data, list): return False
|
||||
for block in data:
|
||||
block_type = block.pop('type', None)
|
||||
if block_type not in ['block', 'question']: return False
|
||||
if block_type == 'question':
|
||||
if not all (key in block for key in ['q_no', 'text', 'options', 'correct', 'q_type', 'tags']): return False
|
||||
if not isinstance(block['q_no'], int): return False
|
||||
if not isinstance(block['text'], str): return False
|
||||
if not isinstance(block['options'], list): return False
|
||||
for option in block['options']:
|
||||
if not isinstance(option, str): return False
|
||||
if not isinstance(block['correct'], int): return False
|
||||
if not isinstance(block['q_type'], str): return False
|
||||
if block['q_type'] not in ['Multiple Choice', 'Yes/No', 'List']: return False
|
||||
if not isinstance(block['tags'], list): return False
|
||||
for tag in block['tags']:
|
||||
if not isinstance(tag, str): return False
|
||||
if block_type == 'block':
|
||||
if not all (key in block for key in ['question_header', 'questions']): return False
|
||||
if not isinstance(block['question_header'], str): return False
|
||||
if not isinstance(block['questions'], list): return False
|
||||
for question in block['questions']:
|
||||
if not all (key in question for key in ['q_no', 'text', 'options', 'correct', 'q_type', 'tags']): return False
|
||||
if not isinstance(question['text'], str): return False
|
||||
if not isinstance(question['q_no'], int): return False
|
||||
if not isinstance(question['options'], list): return False
|
||||
for option in question['options']:
|
||||
if not isinstance(option, str): return False
|
||||
if not isinstance(question['correct'], int): return False
|
||||
if not isinstance(question['q_type'], str): return False
|
||||
if question['q_type'] not in ['Multiple Choice', 'Yes/No', 'List']: return False
|
||||
if not isinstance(question['tags'], list): return False
|
||||
for tag in question['tags']:
|
||||
if not isinstance(tag, str): return False
|
||||
return True
|
||||
|
||||
def randomise_list(list:list):
|
||||
|
@ -1 +1 @@
|
||||
from app.config import ProductionConfig as Config
|
||||
from app.config import Production as Config
|
@ -36,19 +36,16 @@ def create_app():
|
||||
def _check_cookie_consent():
|
||||
if request.cookies.get('cookie_consent'):
|
||||
return
|
||||
if any([ request.path.startswith(x) for x in [ '/admin/static/', '/static/', '/cookies/' ] ]):
|
||||
if any([ request.path.startswith(x) for x in [ '/admin/static/', '/root/', '/quiz/static', '/cookies/' ] ]):
|
||||
return
|
||||
flash(f'<strong>Cookie Consent</strong>: This web site only stores minimal, functional cookies. It does not store any tracking information. By using this site, you consent to this use of cookies. For more information, see our <a href="{url_for("views._privacy")}">privacy policy</a>.', 'cookie_alert')
|
||||
|
||||
@app.errorhandler(404)
|
||||
def _404_handler(error):
|
||||
return render_template('404.html')
|
||||
def _404_handler(error): return render_template('404.html')
|
||||
@app.errorhandler(CSRFError)
|
||||
def _csrf_handler():
|
||||
return jsonify({'error':'Could not validate a secure connection.'}), 403
|
||||
def _csrf_handler(): return jsonify({'error':'Could not validate a secure connection.'}), 403
|
||||
@app.context_processor
|
||||
def _now():
|
||||
return {'now': datetime.now()}
|
||||
def _now(): return {'now': datetime.now()}
|
||||
|
||||
from app.admin.views import admin
|
||||
from app.api.views import api
|
||||
@ -83,5 +80,4 @@ def create_app():
|
||||
|
||||
app = create_app()
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run()
|
||||
if __name__ == '__main__': app.run()
|
@ -1,4 +1,2 @@
|
||||
from main import app
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run()
|
||||
if __name__ == '__main__': app.run()
|
Reference in New Issue
Block a user