From 7fe0d9a9c5277cfdaa8035d469b83fcc58668ae4 Mon Sep 17 00:00:00 2001 From: forest Date: Sun, 10 May 2020 13:51:54 -0500 Subject: [PATCH] fine-tuning login --- README.md | 25 ++++++------ capsulflask/auth.py | 39 ++++++++++--------- capsulflask/model.py | 9 ++++- .../02_up_accounts_vms_etc.sql | 2 +- capsulflask/templates/base.html | 4 +- capsulflask/templates/check-your-email.html | 6 --- capsulflask/templates/login-landing.html | 7 ++++ capsulflask/templates/login.html | 1 + 8 files changed, 52 insertions(+), 41 deletions(-) delete mode 100644 capsulflask/templates/check-your-email.html create mode 100644 capsulflask/templates/login-landing.html diff --git a/README.md b/README.md index 8614d12..7e0dcf5 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,6 @@ Python Flask web application for capsul.org -## postgres database schema management - -capsulflask has a concept of a schema version. When the application starts, it will query the database for a table named -`schemaversion` that has one row and one column (`version`). If the `version` it finds is not equal to the `desiredSchemaVersion` variable set in `db.py`, it will run migration scripts from the `schema_migrations` folder one by one until the `schemaversion` table shows the correct version. - -For example, the script named `02_up_xyz.sql` should contain code that migrates the database from schema version 1 to schema version 2. Likewise, the script `02_down_xyz.sql` should contain code that migrates from schema version 2 back to schema version 1. - -**IMPORTANT: if you need to make changes to the schema, make a NEW schema version. DO NOT EDIT the existing schema versions.** - -In general, for safety, schema version upgrades should not delete data. Schema version downgrades will simply throw an error and exit for now. ## how to run locally @@ -33,11 +23,22 @@ pip install -r requirements.txt Run an instance of Postgres (I used docker for this, you can use whatever you want, point is its listening on localhost:5432) ``` -docker run -it -e POSTGRES_PASSWORD=dev -p 5432:5432 postgres +docker run --rm -it -e POSTGRES_PASSWORD=dev -p 5432:5432 postgres ``` Run the app ``` FLASK_APP=capsulflask flask run -``` \ No newline at end of file +``` + +## postgres database schema management + +capsulflask has a concept of a schema version. When the application starts, it will query the database for a table named +`schemaversion` that has one row and one column (`version`). If the `version` it finds is not equal to the `desiredSchemaVersion` variable set in `db.py`, it will run migration scripts from the `schema_migrations` folder one by one until the `schemaversion` table shows the correct version. + +For example, the script named `02_up_xyz.sql` should contain code that migrates the database from schema version 1 to schema version 2. Likewise, the script `02_down_xyz.sql` should contain code that migrates from schema version 2 back to schema version 1. + +**IMPORTANT: if you need to make changes to the schema, make a NEW schema version. DO NOT EDIT the existing schema versions.** + +In general, for safety, schema version upgrades should not delete data. Schema version downgrades will simply throw an error and exit for now. \ No newline at end of file diff --git a/capsulflask/auth.py b/capsulflask/auth.py index a2b7572..673a8b1 100644 --- a/capsulflask/auth.py +++ b/capsulflask/auth.py @@ -18,7 +18,7 @@ from capsulflask.db import get_model bp = Blueprint("auth", __name__, url_prefix="/auth") def account_required(view): - """View decorator that redirects anonymous users to the login page.""" + """View decorator that redirects non-logged-in users to the login page.""" @functools.wraps(view) def wrapped_view(**kwargs): @@ -36,31 +36,34 @@ def login(): error = None if not email: - error = "Email is required." + error = "email is required" elif not re.match(r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)", email): - error = "Enter a valid email address." - + error = "enter a valid email address" if error is None: token = get_model().login(email) + if token is None: + error = "too many logins. please use one of the existing login links that have been emailed to you" + else: + link = f"{current_app.config['BASE_URL']}/auth/magic/{token}" - link = f"{current_app.config['BASE_URL']}/auth/magic/{token}" + current_app.config["FLASK_MAIL_INSTANCE"].send( + Message( + "Click This Link to Login to Capsul", + body=f""" + Navigate to {link} to log into capsul. - current_app.config["FLASK_MAIL_INSTANCE"].send( - Message( - "Click This Link to Login to Capsul", - body=f""" - Navigate to {link} to log into capsul. - """, - html=f""" - Navigate to {link} to log into capsul. - """, - sender=current_app.config['MAIL_DEFAULT_SENDER'], - recipients=[email] + If you didn't request this, ignore this message. + """, + html=f""" +

Navigate to {link} to log into capsul.

+

If you didn't request this, ignore this message.

+ """, + recipients=[email] + ) ) - ) - return render_template("check-your-email.html") + return render_template("login-landing.html", email=email) flash(error) diff --git a/capsulflask/model.py b/capsulflask/model.py index ce75c7f..f6bfffc 100644 --- a/capsulflask/model.py +++ b/capsulflask/model.py @@ -12,6 +12,10 @@ class Model: if len(self.cursor.fetchall()) == 0: self.cursor.execute("INSERT INTO accounts (email) VALUES (%s)", (email, )) + self.cursor.execute("SELECT token FROM logintokens WHERE email = %s", (email, )) + if len(self.cursor.fetchall()) > 2: + return None + token = generate() self.cursor.execute("INSERT INTO logintokens (email, token) VALUES (%s, %s)", (email, token)) self.connection.commit() @@ -22,7 +26,8 @@ class Model: self.cursor.execute("SELECT email FROM logintokens WHERE token = %s", (token, )) rows = self.cursor.fetchall() if len(rows) > 0: - self.cursor.execute("DELETE FROM logintokens WHERE token = %s", (token, )) + email = rows[0][0] + self.cursor.execute("DELETE FROM logintokens WHERE email = %s", (email, )) self.connection.commit() - return rows[0][0] + return email return None \ No newline at end of file diff --git a/capsulflask/schema_migrations/02_up_accounts_vms_etc.sql b/capsulflask/schema_migrations/02_up_accounts_vms_etc.sql index 6a6c5db..52dfaae 100644 --- a/capsulflask/schema_migrations/02_up_accounts_vms_etc.sql +++ b/capsulflask/schema_migrations/02_up_accounts_vms_etc.sql @@ -15,7 +15,7 @@ CREATE TABLE vms ( CREATE TABLE payments ( email TEXT REFERENCES accounts(email) ON DELETE RESTRICT, created TIMESTAMP NOT NULL DEFAULT NOW(), - dollars INTEGER NOT NULL, + dollars NUMERIC(8, 2) NOT NULL, PRIMARY KEY (email, created) ); diff --git a/capsulflask/templates/base.html b/capsulflask/templates/base.html index 3294226..181542a 100644 --- a/capsulflask/templates/base.html +++ b/capsulflask/templates/base.html @@ -3,7 +3,7 @@ -{% block title %}{% endblock %} +{% block title %}{% endblock %}{% if self.title() %} - {% endif %}capsul @@ -14,7 +14,7 @@
{% if session["account"] %} - {{ session["account"] }} + Logged in as {{ session["account"] }} Log Out {% else %} Log In diff --git a/capsulflask/templates/check-your-email.html b/capsulflask/templates/check-your-email.html deleted file mode 100644 index 7ca1afd..0000000 --- a/capsulflask/templates/check-your-email.html +++ /dev/null @@ -1,6 +0,0 @@ -{% extends 'base.html' %} - - -{% block content %} - Check Your Email My Dude -{% endblock %} \ No newline at end of file diff --git a/capsulflask/templates/login-landing.html b/capsulflask/templates/login-landing.html new file mode 100644 index 0000000..8ad97a9 --- /dev/null +++ b/capsulflask/templates/login-landing.html @@ -0,0 +1,7 @@ +{% extends 'base.html' %} + +{% block title %}check your email{% endblock %} + +{% block content %} + check your email. a login link has been sent to {{ email }} +{% endblock %} \ No newline at end of file diff --git a/capsulflask/templates/login.html b/capsulflask/templates/login.html index e132dda..e8756b2 100644 --- a/capsulflask/templates/login.html +++ b/capsulflask/templates/login.html @@ -1,5 +1,6 @@ {% extends 'base.html' %} +{% block title %}login{% endblock %} {% block content %}