fine-tuning login

This commit is contained in:
forest 2020-05-10 13:51:54 -05:00
parent e6fcb847f0
commit 7fe0d9a9c5
8 changed files with 52 additions and 41 deletions

View File

@ -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
```
```
## 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.

View File

@ -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 <a href="{link}">{link}</a> to log into capsul.
""",
sender=current_app.config['MAIL_DEFAULT_SENDER'],
recipients=[email]
If you didn't request this, ignore this message.
""",
html=f"""
<p>Navigate to <a href="{link}">{link}</a> to log into capsul.</p>
<p>If you didn't request this, ignore this message.</p>
""",
recipients=[email]
)
)
)
return render_template("check-your-email.html")
return render_template("login-landing.html", email=email)
flash(error)

View File

@ -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

View File

@ -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)
);

View File

@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{% block title %}{% endblock %}</title>
<title>{% block title %}{% endblock %}{% if self.title() %} - {% endif %}capsul</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="apple-touch-icon" href="/icon.png" />
@ -14,7 +14,7 @@
<div class="float-right">
{% if session["account"] %}
<span>{{ session["account"] }}</span>
<span>Logged in as {{ session["account"] }}</span>
<a href="{{ url_for('auth.logout') }}">Log Out</a>
{% else %}
<a href="{{ url_for('auth.login') }}">Log In</a>

View File

@ -1,6 +0,0 @@
{% extends 'base.html' %}
{% block content %}
Check Your Email My Dude
{% endblock %}

View File

@ -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 %}

View File

@ -1,5 +1,6 @@
{% extends 'base.html' %}
{% block title %}login{% endblock %}
{% block content %}
<form method="post">