fine-tuning login
This commit is contained in:
parent
e6fcb847f0
commit
7fe0d9a9c5
25
README.md
25
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
|
||||
```
|
||||
```
|
||||
|
||||
## 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.
|
@ -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)
|
||||
|
||||
|
@ -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
|
@ -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)
|
||||
);
|
||||
|
||||
|
@ -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>
|
||||
|
@ -1,6 +0,0 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
Check Your Email My Dude
|
||||
{% endblock %}
|
7
capsulflask/templates/login-landing.html
Normal file
7
capsulflask/templates/login-landing.html
Normal 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 %}
|
@ -1,5 +1,6 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}login{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form method="post">
|
||||
|
Loading…
Reference in New Issue
Block a user