~fluix/tilde

ref: 517e13a463e83825e6c6fd74bbe4085ca8d87b7c tilde/auth/views.py -rw-r--r-- 3.9 KiB
517e13a4Steven Guikal Fix package files 6 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# SPDX-FileCopyrightText: 2021 Steven Guikal <void@fluix.one>
#
# SPDX-License-Identifier: AGPL-3.0-only

import click
import json

from flask import (
    Blueprint,
    current_app,
    flash,
    redirect,
    render_template,
    request,
    session,
    url_for,
)
from flask_login import login_required, login_user, logout_user
from itsdangerous.url_safe import URLSafeSerializer
from sqlalchemy.exc import IntegrityError

from .forms import LoginForm, RegistrationForm
from .models import Status, User

auth = Blueprint("auth", __name__, template_folder="templates")
db = current_app.config["db"]


@auth.route("/")
@login_required
def account():
    return render_template("account.html")


@auth.route("/logout", methods=["POST"])
@login_required
def logout():
    logout_user()
    flash("Logged out successfully.")
    return redirect(url_for("flatpages.index"))


@auth.route("/login", methods=["GET", "POST"])
def login():
    form = LoginForm(request.form)
    if request.method == "POST" and form.validate():
        if form.errors:
            return render_template("login.html", form=form)

        user = User.query.filter_by(username=form.username.data).first()
        if not user:
            form.username.errors.append("User does not exist.")
            return render_template("login.html", form=form)
        if not user.check_password(form.password.data):
            form.password.errors.append("Incorrect password.")
            return render_template("login.html", form=form)

        if user.status == Status.PENDING:
            if not user.check_activation(request.args.get("activate", "")):
                form.username.errors.append(user.status.error)
                return render_template("login.html", form=form)
            user.status = Status.ACTIVE
            db.session.add(user)
            db.session.commit()
        elif user.status.error:
            form.username.errors.append(user.status.error)
            return render_template("login.html", form=form)

        login_user(user)
        flash(f"Login successful. Welcome ~{user.username}!")
        return redirect(session.get("next", url_for("flatpages.index")))
    return render_template("login.html", form=form)


@auth.route("/register", methods=["GET", "POST"])
def register():
    form = RegistrationForm(request.form)
    if request.method == "POST" and form.validate():
        user = User(
            username=form.username.data,
            email=form.email.data,
            bio=form.bio.data,
        )
        user.set_password(form.password1.data)
        db.session.add(user)
        try:
            db.session.commit()
        except IntegrityError as e:
            db.session.rollback()
            form.username.errors.append("Username taken.")
            return render_template("register.html", form=form)

        flash("Account registration sent in. Please await a reply.")
        return redirect(url_for("flatpages.index"))
    return render_template("register.html", form=form)


@auth.cli.command("ergo")
def ergo():
    data = json.loads(input())
    out = {"success": True}

    user = User.query.filter_by(username=data.get("accountName", "")).first()
    if not user or not user.check_password(data.get("passphrase")):
        out = {"success": False, "error": "Username or password is incorrect."}
    elif user.status.error:
        out = {"success": False, "error": user.status.error}

    print(json.dumps(out))


@auth.cli.command("activate")
@click.argument("username")
def activate(username):
    user = User.query.filter_by(username=username).first()
    if not user:
        print("User does not exist")
        exit(1)
    if user.status != Status.PENDING:
        print(f"User status is {user.status}, not {Status.PENDING}.")
        exit(1)
    signer = URLSafeSerializer(current_app.secret_key, salt="activate")
    activation_code = signer.dumps([user.id, user.username])
    print(f"{url_for('auth.login')}?activate={activation_code}")