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
- [ ] Plain text support for blog entries
- [ ] HTML files (.html)
- [ ] Markdown Files (.md)
- [ ] Accounts
- [x] Login
- [x] Logout
- [ ] Register
- [ ] Review blog entries
- [ ] Writing entries
- [ ] Editing entries
- [ ] Deleting entries
- [ ] Infinite-scroll blog page
- [ ] Archive page
- [ ] Months as headings
@ -16,14 +22,16 @@ The blog is intended to be used to review and critique things.
- [ ] Standalone article page
- [ ] Links to scrolling blog page
- [ ] RSS feed
- [ ] Navigation
- [ ] Header
- [ ] Footer
- [ ] Switchable CSS
- [ ] CSS dark-theme
- [ ] CSS light-theme
- [ ] Config file
- [ ] Docker installation
- [ ] Eye candy
- [ ] Star rating
- [ ] Rich text editor
- [x] Navigation
- [x] Header
- [x] Footer
- [x] Switchable CSS
- [x] CSS dark-theme
- [x] CSS light-theme
- [x] Docker installation
- [ ] Logo
## Usage
@ -48,12 +56,11 @@ The `config.py` can be found in the `src` folder.
Set the following volumes with the -v tag.
| Volume-Name | Container mount | Description |
| ------------- | --------------------------- | ------------------------------------------------------------ |
| `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 |
| `html` | `/blog/src/templates` | (optional) Directory for templates (entry-volume not needed) |
| Volume-Name | Container mount | Description |
| ------------- | ---------------------- | ---------------------------------- |
| `config-file` | `/blog/src/config.py` | Config file |
| `css` | `/blog/src/static/css` | (optional) Directory for css files |
| `html` | `/blog/src/templates` | (optional) Directory for templates |
#### 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_login import current_user, login_user, LoginManager, logout_user
from flask_wtf import CSRFProtect
import content as con_gen
import config
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, BooleanField
from wtforms.validators import DataRequired
app = Flask(__name__)
login = LoginManager(app)
login.login_view = 'login'
csrf = CSRFProtect()
app.secret_key = "123534"
csrf.init_app(app)
class LoginForm(FlaskForm):
username = StringField("Username", validators=[DataRequired()])
password = PasswordField("Password", validators=[DataRequired()])
remember_me = BooleanField("Remember Me")
submit = SubmitField("Sign In")
login = LoginManager(app)
login.login_view = "login"
TITLE = config.TITLE
STYLE = config.STYLE
DESCRIPTION = config.DESCRIPTION
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)
def page_not_found(e):
return render_template("error.html", title=TITLE, errorcode="404", style=STYLE), 404
@ -67,7 +33,7 @@ def index():
@app.route("/archive")
@app.route("/archive.html")
def blog_archive():
def archive():
content = con_gen.gen_arch_string()
return render_template("archive.html", title=TITLE, content_string=content, style=STYLE)
@ -91,24 +57,36 @@ def feed():
return response
@login.user_loader
def load_user(id):
def load_user(ident):
## 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.html", methods=["GET", "POST"])
def login():
#if current_user.is_authenticated:
# return redirect("/index")
if current_user.is_authenticated:
return redirect(url_for("index"))
form = LoginForm()
if form.validate_on_submit():
user = u
#user = form.username.data
if user is None or not user.check_password(form.password.data):
db_user = db.get_by_name(form.username.data)
if db_user is None:
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")
return redirect(url_for("login"))
login_user(user, remember=form.remember_me.data)
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')
def logout():

@ -1,5 +1,3 @@
ENTRY_DIR = "templates/entry"
def gen_arch_string():
"""
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_login==0.6.2
flask_wtf==1.0.1
WTForms==3.0.1
Flask_Login==0.6.2
Flask_WTF==0.14.3
Werkzeug==2.1.2
WTForms==2.2.1

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

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

Loading…
Cancel
Save