log in
This commit is contained in:
@ -1,8 +1,12 @@
|
||||
from flask import Flask
|
||||
from flask import Flask, session
|
||||
from dotenv import load_dotenv
|
||||
from .models import Avatars, Users
|
||||
from .auth import digest
|
||||
from .constants import PermissionLevel
|
||||
from .routes.users import is_logged_in, get_active_user
|
||||
from .constants import (
|
||||
PermissionLevel,
|
||||
InfoboxKind, InfoboxIcons, InfoboxHTMLClass
|
||||
)
|
||||
import os
|
||||
import time
|
||||
import secrets
|
||||
@ -64,6 +68,22 @@ def create_app():
|
||||
create_deleted_user()
|
||||
|
||||
from app.routes.app import bp as app_bp
|
||||
from app.routes.topics import bp as topics_bp
|
||||
from app.routes.users import bp as users_bp
|
||||
app.register_blueprint(app_bp)
|
||||
app.register_blueprint(topics_bp)
|
||||
app.register_blueprint(users_bp)
|
||||
|
||||
|
||||
@app.context_processor
|
||||
def inject_constants():
|
||||
return {
|
||||
"InfoboxIcons": InfoboxIcons,
|
||||
"InfoboxHTMLClass": InfoboxHTMLClass,
|
||||
}
|
||||
|
||||
@app.context_processor
|
||||
def inject_auth():
|
||||
return {"is_logged_in": is_logged_in, "get_active_user": get_active_user}
|
||||
|
||||
return app
|
||||
|
@ -1,4 +1,4 @@
|
||||
from enum import Enum
|
||||
from enum import Enum, IntEnum
|
||||
|
||||
class PermissionLevel(Enum):
|
||||
GUEST = 0
|
||||
@ -6,3 +6,23 @@ class PermissionLevel(Enum):
|
||||
MODERATOR = 2
|
||||
SYSTEM = 3
|
||||
ADMIN = 4
|
||||
|
||||
class InfoboxKind(IntEnum):
|
||||
INFO = 0
|
||||
LOCK = 1
|
||||
WARN = 2
|
||||
ERROR = 3
|
||||
|
||||
InfoboxIcons = {
|
||||
InfoboxKind.INFO: "/static/misc/info.svg",
|
||||
InfoboxKind.LOCK: "/static/misc/lock.svg",
|
||||
InfoboxKind.WARN: "/static/misc/warn.svg",
|
||||
InfoboxKind.ERROR: "/static/misc/error.svg",
|
||||
}
|
||||
|
||||
InfoboxHTMLClass = {
|
||||
InfoboxKind.INFO: "",
|
||||
InfoboxKind.LOCK: "warn",
|
||||
InfoboxKind.WARN: "warn",
|
||||
InfoboxKind.ERROR: "critical",
|
||||
}
|
||||
|
@ -1,8 +1,24 @@
|
||||
from .db import Model
|
||||
from .constants import PermissionLevel
|
||||
|
||||
class Users(Model):
|
||||
table = "users"
|
||||
|
||||
def is_guest(self):
|
||||
return self.permission == PermissionLevel.GUEST.value
|
||||
|
||||
def is_mod(self):
|
||||
return self.permission >= PermissionLevel.MODERATOR.value
|
||||
|
||||
def is_admin(self):
|
||||
return self.permission == PermissionLevel.ADMIN.value
|
||||
|
||||
def is_system(self):
|
||||
return self.permission == PermissionLevel.SYSTEM.value
|
||||
|
||||
def is_default_avatar(self):
|
||||
return self.avatar_id == 1
|
||||
|
||||
class Topics(Model):
|
||||
table = "topics"
|
||||
|
||||
|
9
app/routes/topics.py
Normal file
9
app/routes/topics.py
Normal file
@ -0,0 +1,9 @@
|
||||
from flask import Blueprint, render_template
|
||||
from ..models import Users
|
||||
|
||||
bp = Blueprint("topics", __name__, url_prefix = "/topics/")
|
||||
|
||||
@bp.get("/")
|
||||
def all_topics():
|
||||
admin = Users.find({"id": 1})
|
||||
return render_template("topics/topics.html", admin = admin)
|
77
app/routes/users.py
Normal file
77
app/routes/users.py
Normal file
@ -0,0 +1,77 @@
|
||||
from flask import (
|
||||
Blueprint, render_template, request, redirect, url_for, flash, session
|
||||
)
|
||||
from ..models import Users, Sessions
|
||||
from ..constants import InfoboxKind
|
||||
from ..auth import digest, verify
|
||||
import secrets
|
||||
import time
|
||||
|
||||
bp = Blueprint("users", __name__, url_prefix = "/users/")
|
||||
|
||||
|
||||
def is_logged_in():
|
||||
return "pyrom_session_key" in session
|
||||
|
||||
|
||||
def get_active_user():
|
||||
if not is_logged_in():
|
||||
return None
|
||||
sess = Sessions.find({"key": session["pyrom_session_key"]})
|
||||
if not sess:
|
||||
return None
|
||||
return Users.find({"id": sess.user_id})
|
||||
|
||||
|
||||
@bp.get("/log_in")
|
||||
def log_in():
|
||||
return render_template("users/log_in.html")
|
||||
|
||||
|
||||
@bp.post("/log_in")
|
||||
def log_in_post():
|
||||
target_user = Users.find({
|
||||
"username": request.form['username']
|
||||
})
|
||||
if not target_user:
|
||||
flash("Incorrect username or password.", InfoboxKind.ERROR)
|
||||
return redirect(url_for("users.log_in"))
|
||||
|
||||
if not verify(target_user.password_hash, request.form['password']):
|
||||
flash("Incorrect username or password.", InfoboxKind.ERROR)
|
||||
return redirect(url_for("users.log_in"))
|
||||
|
||||
session_obj = Sessions.create({
|
||||
"key": secrets.token_hex(16),
|
||||
"user_id": target_user.id,
|
||||
"expires_at": int(time.time()) + 30 * 24 * 60 * 60,
|
||||
})
|
||||
|
||||
session['pyrom_session_key'] = session_obj.key
|
||||
flash("Logged in!", InfoboxKind.INFO)
|
||||
return redirect(url_for("users.log_in"))
|
||||
|
||||
|
||||
@bp.get("/sign_up")
|
||||
def sign_up():
|
||||
return "not yet"
|
||||
|
||||
|
||||
@bp.get("/<username>")
|
||||
def page(username):
|
||||
return "stub"
|
||||
|
||||
|
||||
@bp.get("/<username>/setings")
|
||||
def settings(username):
|
||||
return "stub"
|
||||
|
||||
|
||||
@bp.get("/<username>/inbox")
|
||||
def inbox(username):
|
||||
return "stub"
|
||||
|
||||
|
||||
@bp.get("/list")
|
||||
def user_list():
|
||||
return "stub"
|
28
app/templates/base.html
Normal file
28
app/templates/base.html
Normal file
@ -0,0 +1,28 @@
|
||||
{% from 'common/infobox.html' import infobox with context %}
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
{% if title %}
|
||||
<title>Porom - {% block title %}{% endblock %}</title>
|
||||
{% else %}
|
||||
<title>Porom</title>
|
||||
{% endif %}
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
{% include 'common/topnav.html' %}
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
{{ infobox(message, category) }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% block content %}{% endblock %}
|
||||
<footer class="darkbg">
|
||||
<span>Porom commit</span>
|
||||
</footer>
|
||||
<script src="/static/js/copy-code.js"></script>
|
||||
<script src="/static/js/ui.js"></script>
|
||||
</body>
|
10
app/templates/common/infobox.html
Normal file
10
app/templates/common/infobox.html
Normal file
@ -0,0 +1,10 @@
|
||||
{% macro infobox(message, kind=InfoboxKind.INFO) %}
|
||||
<div class="{{ "infobox " + InfoboxHTMLClass[kind] }}">
|
||||
<span>
|
||||
<div class="infobox-icon-container">
|
||||
<img src="{{ InfoboxIcons[kind] }}">
|
||||
</div>
|
||||
{{ message }}
|
||||
</span>
|
||||
</div>
|
||||
{% endmacro %}
|
22
app/templates/common/topnav.html
Normal file
22
app/templates/common/topnav.html
Normal file
@ -0,0 +1,22 @@
|
||||
<nav id="topnav">
|
||||
<span>
|
||||
<a class="site-title" href="{{url_for('topics.all_topics')}}">Porom</a>
|
||||
</span>
|
||||
<span>
|
||||
{% if not is_logged_in() %}
|
||||
Welcome, guest. Please <a href="{{url_for('users.sign_up')}}">sign up</a> or <a href="{{url_for('users.log_in')}}">log in</a>
|
||||
{% else %}
|
||||
{% with user = get_active_user() %}
|
||||
Welcome, <a href="{{ url_for("users.page", username = user.username) }}">{{user.username}}</a>
|
||||
•
|
||||
<a href="{{ url_for("users.settings", username = user.username) }}">Settings</a>
|
||||
•
|
||||
<a href="{{ url_for("users.inbox", username = user.username) }}">Inbox</a>
|
||||
{% if user.is_mod() %}
|
||||
•
|
||||
<a href="{{ url_for("users.user_list") }}">User list</a>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
</span>
|
||||
</nav>
|
7
app/templates/topics/topics.html
Normal file
7
app/templates/topics/topics.html
Normal file
@ -0,0 +1,7 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<nav class="darkbg">
|
||||
<h1 class="thread-title">All topics</h1>
|
||||
<span>{{admin.is_default_avatar()}}</span>
|
||||
</nav>
|
||||
{% endblock %}
|
14
app/templates/users/log_in.html
Normal file
14
app/templates/users/log_in.html
Normal file
@ -0,0 +1,14 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block title %}Log in{% endblock %}
|
||||
{% block content %}
|
||||
<div class="darkbg login-container">
|
||||
<h1>Log In</h1>
|
||||
<form method="post">
|
||||
<label for="username">Username</label><br>
|
||||
<input type="text" id="username" name="username" required autocomplete="username"><br>
|
||||
<label for="password">Password</label><br>
|
||||
<input type="password" id="password" name="password" required autocomplete="current-password"><br>
|
||||
<input type="submit" value="Log in">
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
0
app/templates/users/sign_up.html
Normal file
0
app/templates/users/sign_up.html
Normal file
Reference in New Issue
Block a user