src: login works

master
tiyn 2 years ago
parent eaf690f832
commit cd09ab9a12

@ -5,9 +5,15 @@ The blog is intended to be used to review and critique things.
## Features/To-Dos ## Features/To-Dos
- [ ] Plain text support for blog entries
- [ ] HTML files (.html) - [ ] Accounts
- [ ] Markdown Files (.md) - [x] Login
- [x] Logout
- [ ] Register
- [ ] Review blog entries
- [ ] Writing entries
- [ ] Editing entries
- [ ] Deleting entries
- [ ] Infinite-scroll blog page - [ ] Infinite-scroll blog page
- [ ] Archive page - [ ] Archive page
- [ ] Months as headings - [ ] Months as headings
@ -16,14 +22,16 @@ The blog is intended to be used to review and critique things.
- [ ] Standalone article page - [ ] Standalone article page
- [ ] Links to scrolling blog page - [ ] Links to scrolling blog page
- [ ] RSS feed - [ ] RSS feed
- [ ] Navigation - [ ] Eye candy
- [ ] Header - [ ] Star rating
- [ ] Footer - [ ] Rich text editor
- [ ] Switchable CSS - [x] Navigation
- [ ] CSS dark-theme - [x] Header
- [ ] CSS light-theme - [x] Footer
- [ ] Config file - [x] Switchable CSS
- [ ] Docker installation - [x] CSS dark-theme
- [x] CSS light-theme
- [x] Docker installation
- [ ] Logo - [ ] Logo
## Usage ## Usage
@ -48,12 +56,11 @@ The `config.py` can be found in the `src` folder.
Set the following volumes with the -v tag. Set the following volumes with the -v tag.
| Volume-Name | Container mount | Description | | Volume-Name | Container mount | Description |
| ------------- | --------------------------- | ------------------------------------------------------------ | | ------------- | ---------------------- | ---------------------------------- |
| `config-file` | `/blog/src/config.py` | Config file | | `config-file` | `/blog/src/config.py` | Config file |
| `entries` | `/blog/src/templates/entry` | Directory for blog entries | | `css` | `/blog/src/static/css` | (optional) Directory for css files |
| `css` | `/blog/src/static/css` | (optional) Directory for css files | | `html` | `/blog/src/templates` | (optional) Directory for templates |
| `html` | `/blog/src/templates` | (optional) Directory for templates (entry-volume not needed) |
#### Ports #### Ports

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

@ -1,58 +1,24 @@
from flask import Flask, flash, make_response, render_template, request, redirect, abort, url_for from flask import Flask, flash, make_response, render_template, request, redirect, abort, url_for
from flask_login import current_user, login_user, LoginManager, logout_user from flask_login import current_user, login_user, LoginManager, logout_user
from flask_wtf import CSRFProtect
import content as con_gen import content as con_gen
import config import config
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, BooleanField
from wtforms.validators import DataRequired
app = Flask(__name__) app = Flask(__name__)
login = LoginManager(app) csrf = CSRFProtect()
login.login_view = 'login' app.secret_key = "123534"
csrf.init_app(app)
class LoginForm(FlaskForm): login = LoginManager(app)
username = StringField("Username", validators=[DataRequired()]) login.login_view = "login"
password = PasswordField("Password", validators=[DataRequired()])
remember_me = BooleanField("Remember Me")
submit = SubmitField("Sign In")
TITLE = config.TITLE TITLE = config.TITLE
STYLE = config.STYLE STYLE = config.STYLE
DESCRIPTION = config.DESCRIPTION DESCRIPTION = config.DESCRIPTION
WEBSITE = config.WEBSITE WEBSITE = config.WEBSITE
from werkzeug.security import generate_password_hash, check_password_hash
class User():
def __init__(self, username):
self.username = username
self.id = 1
self.is_active = True
self.is_authenticated = False
self.is_anonymous = False
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
def get_id(self):
return self.id
u = User("marten")
u.set_password("test")
class Config(object):
SECRET_KEY = "123534"
app.config.from_object(Config)
@app.errorhandler(404) @app.errorhandler(404)
def page_not_found(e): def page_not_found(e):
return render_template("error.html", title=TITLE, errorcode="404", style=STYLE), 404 return render_template("error.html", title=TITLE, errorcode="404", style=STYLE), 404
@ -67,7 +33,7 @@ def index():
@app.route("/archive") @app.route("/archive")
@app.route("/archive.html") @app.route("/archive.html")
def blog_archive(): def archive():
content = con_gen.gen_arch_string() content = con_gen.gen_arch_string()
return render_template("archive.html", title=TITLE, content_string=content, style=STYLE) return render_template("archive.html", title=TITLE, content_string=content, style=STYLE)
@ -91,24 +57,36 @@ def feed():
return response return response
@login.user_loader @login.user_loader
def load_user(id): def load_user(ident):
## TODO: load user from db by id ## TODO: load user from db by id
return id db_user = db.get_by_id(ident)
if db_user is not None:
return db.db_to_user(*db_user)
return None
from login import LoginForm, User
from database import Database
db = Database()
@app.route("/login", methods=["GET", "POST"]) @app.route("/login", methods=["GET", "POST"])
@app.route("/login.html", methods=["GET", "POST"])
def login(): def login():
#if current_user.is_authenticated: if current_user.is_authenticated:
# return redirect("/index") return redirect(url_for("index"))
form = LoginForm() form = LoginForm()
if form.validate_on_submit(): if form.validate_on_submit():
user = u db_user = db.get_by_name(form.username.data)
#user = form.username.data if db_user is None:
if user is None or not user.check_password(form.password.data): flash("Invalid username or password")
return redirect(url_for("login"))
user = db.db_to_user(*db_user)
if not user.check_password(form.password.data):
flash("Invalid username or password") flash("Invalid username or password")
return redirect(url_for("login")) return redirect(url_for("login"))
login_user(user, remember=form.remember_me.data) login_user(user, remember=form.remember_me.data)
return redirect(url_for("index")) return redirect(url_for("index"))
return render_template("login.html", title="Sign In", form=form, style=STYLE) return render_template("login.html", title=TITLE, form=form, style=STYLE)
@app.route('/logout') @app.route('/logout')
def logout(): def logout():

@ -1,5 +1,3 @@
ENTRY_DIR = "templates/entry"
def gen_arch_string(): def gen_arch_string():
""" """
Creates and returns a archive string of every file in ENTRY_DIR. Creates and returns a archive string of every file in ENTRY_DIR.

Binary file not shown.

@ -0,0 +1,66 @@
import os
import sqlite3
from login import User
class Database:
def __init__(self):
self.TABLE_FILE = 'USERS'
self.DB_DIR = os.path.dirname(".")
self.setup_db()
def connect(self):
"""Connect to an existing database instance based on the object
attributes.
"""
path = os.path.join(self.DB_DIR, "data.db")
return sqlite3.connect(path)
def setup_db(self):
"""Creates a database with tables."""
db = self.connect()
crs = db.cursor()
query = "CREATE TABLE IF NOT EXISTS " + self.TABLE_FILE + \
"(id INTEGER PRIMARY KEY AUTOINCREMENT," + \
"name CHAR(32) NOT NULL UNIQUE," + \
"password CHAR(32) NOT NULL)"
crs.execute(query)
def insert_user(self, name, password):
"""Insert a new user into the database.
"""
if self.check_name(name):
db = self.connect()
crs = db.cursor()
query = "INSERT INTO " + self.TABLE_FILE + "(`name`,`password`)" + \
"VALUES (?, ?) ON CONFLICT DO NOTHING"
crs.execute(query, (name, password))
db.commit()
return True
return False
def check_name(self, name):
if self.get_by_name(name) is None:
return True
return False
def get_by_id(self, ident):
db = self.connect()
crs = db.cursor()
query = "SELECT * FROM " + self.TABLE_FILE + " WHERE id = ?"
crs.execute(query, (ident, ))
return crs.fetchone()
def get_by_name(self, name):
db = self.connect()
crs = db.cursor()
query = "SELECT * FROM " + self.TABLE_FILE + " WHERE name = ?"
crs.execute(query, (name, ))
return crs.fetchone()
def db_to_user(self, ident, name, pass_hash):
user = User(name, pass_hash)
user.set_id(ident)
return user

@ -0,0 +1,34 @@
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, BooleanField
from wtforms.validators import DataRequired
from werkzeug.security import generate_password_hash, check_password_hash
class User():
def __init__(self, name, pass_hash=None):
self.name = name
self.id = 0
self.is_active = True
self.is_authenticated = True
self.is_anonymous = False
self.pass_hash = pass_hash
def set_password(self, password):
self.pass_hash = generate_password_hash(password)
def set_id(self, ident):
self.id = ident
def check_password(self, password):
return check_password_hash(self.pass_hash, password)
def get_id(self):
return self.id
class LoginForm(FlaskForm):
username = StringField("Username", validators=[DataRequired()])
password = PasswordField("Password", validators=[DataRequired()])
remember_me = BooleanField("Remember Me")
submit = SubmitField("Sign In")

@ -1,4 +1,5 @@
Flask==2.1.2 Flask==2.1.2
flask_login==0.6.2 Flask_Login==0.6.2
flask_wtf==1.0.1 Flask_WTF==0.14.3
WTForms==3.0.1 Werkzeug==2.1.2
WTForms==2.2.1

@ -1,18 +1,26 @@
{% extends "template.html" %} {% extends "template.html" %}
{% block content %} {% block content %}
<h1>Sign In</h1>
<form action="" method="post" novalidate> <div class="container">
{{ form.hidden_tag() }} <div class="logging">
<p> <h1>Sign In</h1>
{{ form.username.label }}<br> <form action="" method="post" novalidate>
{{ form.username(size=32) }} {{ form.hidden_tag() }}
</p> <p>
<p> {{ form.username.label }}<br>
{{ form.password.label }}<br> {{ form.username(size=32) }}
{{ form.password(size=32) }} </p>
</p> <p>
<p>{{ form.remember_me() }} {{ form.remember_me.label }}</p> {{ form.password.label }}<br>
<p>{{ form.submit() }}</p> {{ form.password(size=32) }}
</form> </p>
<p>{{ form.remember_me() }} {{ form.remember_me.label }}</p>
<p>{{ form.submit() }}</p>
{% for mesg in get_flashed_messages() %}
<p>{{ mesg }}</p>
{% endfor %}
</form>
</div>
</div>
{% endblock %} {% endblock %}

@ -13,13 +13,13 @@
<input type="checkbox" id="main-menu-check"> <input type="checkbox" id="main-menu-check">
<label for="main-menu-check" class="show-menu">&#9776;</label> <label for="main-menu-check" class="show-menu">&#9776;</label>
<div class="main-menu"> <div class="main-menu">
<a href="/">Blog</a> <a href="{{ url_for('index') }}">Blog</a>
<a href="/archive">Archive</a> <a href="{{ url_for('archive') }}">Archive</a>
<label for="main-menu-check" class="hide-menu">X</label> <label for="main-menu-check" class="hide-menu">X</label>
{% if current_user.is_anonymous %} {% if current_user.is_anonymous %}
<a href="/login">Login</a> <a href="{{ url_for('login') }}">Login</a>
{% else %} {% else %}
<a href="/logout">Logout</a> <a href="{{ url_for('logout') }}">Logout</a>
{% endif %} {% endif %}
</div> </div>
</div> </div>

Loading…
Cancel
Save