summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore7
-rw-r--r--app.py71
-rw-r--r--requirements.txt7
-rw-r--r--static/styles/base.css11
-rw-r--r--static/styles/join.css54
-rw-r--r--static/styles/join_common.css44
-rw-r--r--static/styles/join_form.css33
-rw-r--r--views/base.html3
-rw-r--r--views/join_form.html (renamed from views/join.html)8
-rw-r--r--views/join_intro.html24
-rw-r--r--views/join_success.html18
11 files changed, 198 insertions, 82 deletions
diff --git a/.gitignore b/.gitignore
index f6e7164..0f2d2dc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,9 @@
+# Secrets
.env
+
# Cert files
cert.pem
-key.pem \ No newline at end of file
+key.pem
+
+# Database
+thisisadatabasethatcontainsdata.db
diff --git a/app.py b/app.py
index 0467dd6..cc16026 100644
--- a/app.py
+++ b/app.py
@@ -1,3 +1,4 @@
+from gevent import monkey; monkey.patch_all() # MUST BE FIRST IMPORT
from bottle import Bottle, run, debug, static_file, request, redirect, response, HTTPError
from bottle import jinja2_template as template
from oauthlib.oauth2 import WebApplicationClient
@@ -11,25 +12,29 @@ from bottle.ext import sqlite
load_dotenv()
CLIENT_ID = os.environ.get("CLIENT_ID") # DOTENV ligger paa discorden, repoet er publkic saa det
-CLIENT_SECRET = os.environ.get("CLIENT_ID") # DOTENV PAHAHAH
+CLIENT_SECRET = os.environ.get("CLIENT_SECRET") # DOTENV PAHAHAH
REDIRECT_URI = "https://localhost:8080/callback"
AUTH_BASE_URL = 'https://oauth.battle.net/authorize'
TOKEN_URL = "https://oauth.battle.net/token"
client = WebApplicationClient(CLIENT_ID)
-db = sqlite3.connect("thisisadatabasethatcontainsdata.db")
-db.execute("""
+DB_PATH = "thisisadatabasethatcontainsdata.db"
+
+connection = sqlite3.connect(DB_PATH)
+cursor = connection.cursor()
+cursor.executescript("""
CREATE TABLE IF NOT EXISTS applications (
- name VARCHAR(32),
- role VARCHAR(32),
- motivation TEXT
- )
+ username VARCHAR(12) NOT NULL,
+ preferredRole VARCHAR(6) NOT NULL,
+ motivation TEXT NOT NULL,
+ userId INTEGER UNIQUE NOT NULL
+ );
""")
-db.commit()
-db.close()
+cursor.close()
+connection.close()
app = Bottle()
-plugin = sqlite.Plugin(dbfile="thisisadatabasethatcontainsdata.db")
+plugin = sqlite.Plugin(dbfile=DB_PATH)
app.install(plugin)
@app.route("/")
@@ -37,6 +42,10 @@ app.install(plugin)
def index():
return template("index")
[email protected]("/join_intro.html")
+def join_intro():
+ return template("join_intro")
+
@app.route("/battle")
def battle():
state = secrets.token_urlsafe(16)
@@ -45,23 +54,32 @@ def battle():
return redirect(authorization_url)
@app.route('/callback')
-def callback():
+def join_form():
state = request.get_cookie('oauth_state')
- code = request.query.get('code')
oauth2_session = OAuth2Session(CLIENT_ID, state=state, redirect_uri=REDIRECT_URI)
token_response = oauth2_session.fetch_token(TOKEN_URL, authorization_response=request.url, client_secret=CLIENT_SECRET)
- return f'Access token: {token_response.get("access_token")}'
+ # Get the user ID of the just authenticated user. As per the API
+ # documentation, this should be used to identify users.
+ #
+ # See: https://develop.battle.net/documentation/guides/regionality-and-apis#:~:text=Developers%20should%20use%20an%20accountId
+ query_parameters = {
+ "region": "eu",
+ }
+ response = oauth2_session.get("https://oauth.battle.net/oauth/userinfo", params=query_parameters)
+ response.raise_for_status()
+ user_info = response.json()
+ user_id = user_info["id"]
[email protected]("/join.html")
-def join_form():
- return template("join")
+ # We pass the token retrieved here so it can be submitted with the rest of the application.
+ return template("join_form", user_id=user_id)
[email protected]("/join.html", method="POST")
[email protected]("/callback", method="POST")
def join_submission(db: sqlite3.Connection):
name = request.forms.get("name")
preferred_role = request.forms.get("preferredRole")
motivation = request.forms.get("motivation")
+ user_id = request.forms.get("userId")
if name == None or name.strip() == "":
raise HTTPError(400, "Namefield is empty or missing. ( warning: this is not good )")
@@ -71,10 +89,21 @@ def join_submission(db: sqlite3.Connection):
raise HTTPError(400, "Preferred role must be one of the options (DPS, Tank, Healer) ( idiot )")
if motivation == None or motivation.strip() == "":
raise HTTPError(400, "Motivitaion field is empty or missing.")
-
- db.execute("SELECT * FROM applications").fetchone()
+ if user_id == None or not user_id.isdigit():
+ raise HTTPError(400, "Missing or invalid user id")
+
+ try:
+ db.execute("INSERT INTO applications(username, preferredRole, motivation, userId) VALUES (?, ?, ?, ?)", (name, preferred_role, motivation, user_id))
+ except sqlite3.IntegrityError as e:
+ print(e.sqlite_errorcode == sqlite3.SQLITE_CONSTRAINT_UNIQUE)
+ print(str(e))
+ if e.sqlite_errorcode == sqlite3.SQLITE_CONSTRAINT_UNIQUE:
+ # The database (model) rejected the application because the unique constraint wasn't met!
+ raise HTTPError(400, "You've already submitted an application!")
+ else:
+ raise
- db.execute("INSERT INTO applications(name, role, motivation) VALUES (?, ?, ?)", (name, preferred_role, motivation))
+ return template("join_success")
@app.route("/<type:re:styles|images>/<filename>")
def server_static(type, filename):
@@ -82,4 +111,4 @@ def server_static(type, filename):
debug(True)
run(app, host='localhost', port=8080, reloader=True,
- server="waitress", keyfile="./pki/server.key", certfile="./pki/server.crt")
+ server="gevent", keyfile="./pki/server.key", certfile="./pki/server.crt")
diff --git a/requirements.txt b/requirements.txt
index 1544077..0fa0176 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,12 +1,17 @@
bottle==0.12.25
+bottle-sqlite==0.2.0
certifi==2024.2.2
charset-normalizer==3.3.2
-gunicorn==21.2.0
+gevent==24.2.1
+greenlet==3.0.3
idna==3.7
Jinja2==3.1.3
MarkupSafe==2.1.5
oauthlib==3.2.2
packaging==24.0
+python-dotenv==1.0.1
requests==2.31.0
requests-oauthlib==2.0.0
urllib3==2.2.1
+zope.event==5.0
+zope.interface==6.3
diff --git a/static/styles/base.css b/static/styles/base.css
index f9b1ae6..2ae562e 100644
--- a/static/styles/base.css
+++ b/static/styles/base.css
@@ -60,3 +60,14 @@ footer {
font-size: small;
margin: 1rem;
}
+
+/* Chill link styling */
+a {
+ /* dark and twisted color, lighter for contrast */
+ color: #a27d7d;
+ text-decoration: underline;
+}
+
+a:visited {
+ color: inherit;
+}
diff --git a/static/styles/join.css b/static/styles/join.css
deleted file mode 100644
index f958aad..0000000
--- a/static/styles/join.css
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * This file contains styles specific to the "join" view. The corresponding
- * HTML/template file is `views/join.html`.
- */
-
-main {
- width: 100%;
- max-width: 500px;
- margin: 2rem auto;
-}
-
-.signup {
-
-}
-
-.signup__box {
- margin-bottom: 1reM;
-}
-
-.signup__label {
- font-weight: bold;
-}
-
-.signup__input {
- width: 100%;
- padding: .5rem;
- border-radius: 5px;
-}
-
-textarea.signup__input {
- /* Remove UA's default monospace font */
- font-family: inherit;
-
- /* Horizontal resizing totally breaks our layout :( */
- resize: vertical;
-}
-
-.signup__submit {
- /* Horizontally center the element */
- display: block;
- margin-inline: auto;
-
- /* Make it look dark and twisted */
- background-color: #6e1818;
- color: white;
- border: none;
- border-radius: 500px;
- padding: 1rem;
- font-size: large;
-}
-
-/* The usual dimming effect makes interaction feel more tactile */
-.signup__submit:hover { filter: brightness(90%); }
-.signup__submit:active { filter: brightness(60%); } \ No newline at end of file
diff --git a/static/styles/join_common.css b/static/styles/join_common.css
new file mode 100644
index 0000000..93bdb1d
--- /dev/null
+++ b/static/styles/join_common.css
@@ -0,0 +1,44 @@
+/*
+ * This file contains styles specific to the "join" views. There are a couple
+ * of views which are all part of the same user flow and reuse some styles. The
+ * corresponding HTML/template files are `views/join_*.html`.
+ */
+
+main {
+ /* Center align and keep width readable. */
+ width: 100%;
+ max-width: 500px;
+ margin: 2rem auto;
+
+}
+
+/* Some pages are text heavy. Keep a nice line distance. */
+p { line-height: 1.5; }
+
+.button {
+ /* Horizontally center the element */
+ display: block;
+ margin-inline: auto;
+
+ /* Make it look dark and twisted */
+ background-color: #6e1818;
+ color: white;
+ border: none;
+ border-radius: 500px;
+ padding: 1rem;
+ font-size: large;
+}
+
+/* The usual dimming effect makes interaction feel more tactile */
+.button:hover { filter: brightness(90%); }
+.button:active { filter: brightness(60%); }
+
+/* We use button-styles anchor-tags to preserve HTML semantics. */
+a.button {
+ /* Remove link styling */
+ color: inherit;
+ text-decoration: none;
+
+ /* Inline elements expand by default. */
+ width: fit-content;
+}
diff --git a/static/styles/join_form.css b/static/styles/join_form.css
new file mode 100644
index 0000000..f4ba0f1
--- /dev/null
+++ b/static/styles/join_form.css
@@ -0,0 +1,33 @@
+/*
+ * This file contains styles specific to the "join_form" view. The corresponding
+ * HTML/template file is `views/join_form.html`.
+ *
+ * See also the file `static/styles/join_common.css` which contains some styles
+ * which are reused among the "join_" group of views.
+ */
+
+.signup {
+
+}
+
+.signup__box {
+ margin-bottom: 1reM;
+}
+
+.signup__label {
+ font-weight: bold;
+}
+
+.signup__input {
+ width: 100%;
+ padding: .5rem;
+ border-radius: 5px;
+}
+
+textarea.signup__input {
+ /* Remove UA's default monospace font */
+ font-family: inherit;
+
+ /* Horizontal resizing totally breaks our layout :( */
+ resize: vertical;
+}
diff --git a/views/base.html b/views/base.html
index 9133090..3f65912 100644
--- a/views/base.html
+++ b/views/base.html
@@ -14,8 +14,7 @@
<ul class="navbar__links" role="navigation" aria-label="Main">
<li><a class="navbar__location" href="/index.html">About us</a></li>
<li><a class="navbar__location" href="/history.html">History</a></li>
- <li><a class="navbar__location" href="/join.html">Join</a></li>
- <li><a class="navbar__location" href="/battle">Log in</a></li>
+ <li><a class="navbar__location" href="/join_intro.html">Join</a></li>
</ul>
</header>
<main>{% block content %}{% endblock %}</main>
diff --git a/views/join.html b/views/join_form.html
index 784019c..440c993 100644
--- a/views/join.html
+++ b/views/join_form.html
@@ -1,7 +1,8 @@
{% extends "base.html" %}
{% block head %}
- <link rel="stylesheet" href="/styles/join.css">
+ <link rel="stylesheet" href="/styles/join_common.css">
+ <link rel="stylesheet" href="/styles/join_form.css">
<script type="module">
var dropdown = document.getElementById("preferredRole");
document.getElementById("applicationForm").addEventListener("submit", (event) => {
@@ -15,6 +16,7 @@
{% block content %}
<form method="POST" class="signup" id="applicationForm">
+ <input type="hidden" name="userId" value="{{ user_id | e }}">
<div class="signup__box">
<label class="signup__label" for="name">Name</label>
<p>
@@ -51,7 +53,7 @@
<textarea required class="signup__input" id="motivation" name="motivation" rows="20" placeholder="I would like to join because..."></textarea>
</div>
<div>
- <button class="signup__submit" type="submit">Submit</button>
+ <button class="button" type="submit">Submit</button>
</div>
</form>
-{% endblock %} \ No newline at end of file
+{% endblock %}
diff --git a/views/join_intro.html b/views/join_intro.html
new file mode 100644
index 0000000..abea4fd
--- /dev/null
+++ b/views/join_intro.html
@@ -0,0 +1,24 @@
+{% extends "base.html" %}
+
+{% block head %}
+ <link rel="stylesheet" href="/styles/join_common.css">
+{% endblock %}
+
+{% block content %}
+ <h1>Joining the Blind Guild</h1>
+ <p>
+ So you want to join the Blind Guild.
+ Be warned,
+ we are a very exclusive club
+ and we aren't actively seeking new members.
+ However, if you're a skilled player
+ and feel like you could help elevate the Blind Guild,
+ feel free to send us an application!
+ </p>
+ <p>
+ In order to sync up, we'll need you to connect your battle.net account.
+ Click the button below to sign in with your account.
+ Then you'll be taken to the application form.
+ </p>
+ <a class="button" href="/battle">Sign in</a>
+{% endblock %}
diff --git a/views/join_success.html b/views/join_success.html
new file mode 100644
index 0000000..7e9dace
--- /dev/null
+++ b/views/join_success.html
@@ -0,0 +1,18 @@
+{% extends "base.html" %}
+
+{% block head %}
+ <link rel="stylesheet" href="/styles/join_common.css">
+{% endblock %}
+
+{% block content %}
+ <h1>Application recieved</h1>
+ <p>
+ Your application was submitted successfully!
+ We'll review it and decide if you're cool enough to join our exclusive club.
+ Please note that it may take a few days for us to get to your application.
+ </p>
+ <p>
+ If you're accepted into our elite gang of high-tier gamers,
+ you'll receive an in-game invite to the Blind Guild.
+ </p>
+{% endblock %}