Login system pt.2
This commit is contained in:
parent
5989f0d97e
commit
1fcb701083
|
|
@ -4,12 +4,13 @@
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "Launch Starfall",
|
"clientOS": "unix",
|
||||||
"console": "integratedTerminal",
|
"console": "integratedTerminal",
|
||||||
|
"name": "Launch Starfall",
|
||||||
|
"preLaunchTask": "install_reqs",
|
||||||
"program": "${workspaceFolder}/app.py",
|
"program": "${workspaceFolder}/app.py",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "debugpy",
|
"type": "debugpy"
|
||||||
"clientOS": "unix"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"version": "0.2.0"
|
"version": "0.2.0"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"command": "./.venv/bin/activate",
|
||||||
|
"label": "activate",
|
||||||
|
"type": "shell"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"args": [
|
||||||
|
"install",
|
||||||
|
"--upgrade",
|
||||||
|
"-r",
|
||||||
|
"requirements.txt"
|
||||||
|
],
|
||||||
|
"command": "./.venv/bin/pip",
|
||||||
|
"label": "install_reqs",
|
||||||
|
"type": "shell"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": "2.0.0"
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from sqlalchemy.orm import Mapped, mapped_column
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
|
|
||||||
from starfall.db import db
|
from starfall.db import db
|
||||||
|
|
@ -9,5 +11,17 @@ class User(db.Model):
|
||||||
username: Mapped[str] = mapped_column()
|
username: Mapped[str] = mapped_column()
|
||||||
password: Mapped[str] = mapped_column()
|
password: Mapped[str] = mapped_column()
|
||||||
|
|
||||||
def __init__(self, **kwargs) -> None:
|
def __init__(self, **kwargs: Any) -> None:
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
def auth(self):
|
||||||
|
return (
|
||||||
|
User.query.filter_by(username=self.username, password=self.password).first()
|
||||||
|
is not None
|
||||||
|
)
|
||||||
|
|
||||||
|
def username_free(self):
|
||||||
|
return User.query.filter_by(username=self.username).first() is None
|
||||||
|
|
||||||
|
def email_free(self):
|
||||||
|
return User.query.filter_by(email=self.email).first() is None
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
from flask_babel import _, lazy_gettext
|
from flask_babel import LazyString, lazy_gettext
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from wtforms import PasswordField, StringField
|
from wtforms import PasswordField, StringField
|
||||||
from wtforms.validators import DataRequired
|
from wtforms.validators import DataRequired
|
||||||
|
|
||||||
|
from starfall.db.schema.users import User
|
||||||
from starfall.web.blueprints.base import BaseBlueprint
|
from starfall.web.blueprints.base import BaseBlueprint
|
||||||
from starfall.web.controllers.base import BaseController
|
from starfall.web.controllers.base import BaseController
|
||||||
|
|
||||||
|
|
@ -36,3 +37,16 @@ class LoginController(BaseController):
|
||||||
@classmethod
|
@classmethod
|
||||||
def apply(cls, bp: BaseBlueprint):
|
def apply(cls, bp: BaseBlueprint):
|
||||||
bp.data["form"] = LoginForm()
|
bp.data["form"] = LoginForm()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def handle_form(cls) -> tuple[str, LazyString | str]:
|
||||||
|
form = LoginForm()
|
||||||
|
if not form.validate_on_submit():
|
||||||
|
return "", ""
|
||||||
|
|
||||||
|
user = User(
|
||||||
|
username=str(form.username.data),
|
||||||
|
password=cls.encrypt_password(str(form.password.data)),
|
||||||
|
)
|
||||||
|
|
||||||
|
return "", ""
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
from flask import request
|
from flask import flash, request
|
||||||
from flask_babel import LazyString, lazy_gettext
|
from flask_babel import lazy_gettext
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from wtforms import EmailField, PasswordField, StringField
|
from wtforms import EmailField, PasswordField, StringField
|
||||||
from wtforms.validators import DataRequired
|
from wtforms.fields.simple import PasswordField
|
||||||
|
from wtforms.validators import DataRequired, EqualTo, Length
|
||||||
|
|
||||||
from starfall.db import db
|
from starfall.db import db
|
||||||
from starfall.db.schema.users import User
|
from starfall.db.schema.users import User
|
||||||
|
|
@ -26,12 +27,27 @@ class RegisterForm(FlaskForm):
|
||||||
password: PasswordField = PasswordField(
|
password: PasswordField = PasswordField(
|
||||||
label=lazy_gettext("page.register.form.password"), # pyright: ignore[reportArgumentType]
|
label=lazy_gettext("page.register.form.password"), # pyright: ignore[reportArgumentType]
|
||||||
render_kw={
|
render_kw={
|
||||||
"autocomplete": "password",
|
|
||||||
"class": "form-control",
|
"class": "form-control",
|
||||||
"placeholder": lazy_gettext("page.register.form.password"),
|
"placeholder": lazy_gettext("page.register.form.password"),
|
||||||
},
|
},
|
||||||
validators=[
|
validators=[
|
||||||
DataRequired(message=lazy_gettext("page.register.error.password")), # pyright: ignore[reportArgumentType]
|
DataRequired(message=lazy_gettext("page.register.error.password")), # pyright: ignore[reportArgumentType]
|
||||||
|
Length(8, message=lazy_gettext("page.register.error.password_too_short")), # pyright: ignore[reportArgumentType]
|
||||||
|
],
|
||||||
|
)
|
||||||
|
retype_password: PasswordField = PasswordField(
|
||||||
|
label=lazy_gettext("page.register.form.retype_password"), # pyright: ignore[reportArgumentType]
|
||||||
|
render_kw={
|
||||||
|
"class": "form-control",
|
||||||
|
"placeholder": lazy_gettext("page.register.form.retype_password"),
|
||||||
|
},
|
||||||
|
validators=[
|
||||||
|
DataRequired(message=lazy_gettext("page.register.error.retype_password")), # pyright: ignore[reportArgumentType]
|
||||||
|
Length(8, message=lazy_gettext("page.register.error.password_too_short")), # pyright: ignore[reportArgumentType]
|
||||||
|
EqualTo(
|
||||||
|
"password",
|
||||||
|
message=lazy_gettext("page.register.error.password_not_matching"), # pyright: ignore[reportArgumentType]
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
email: EmailField = EmailField(
|
email: EmailField = EmailField(
|
||||||
|
|
@ -51,22 +67,31 @@ class RegisterController(BaseController):
|
||||||
@classmethod
|
@classmethod
|
||||||
def apply(cls, bp: BaseBlueprint):
|
def apply(cls, bp: BaseBlueprint):
|
||||||
if "POST" == request.method:
|
if "POST" == request.method:
|
||||||
bp.data["status_class"], bp.data["status"] = cls.handle_form()
|
cls.handle_form()
|
||||||
bp.data["form"] = RegisterForm()
|
bp.data["form"] = RegisterForm()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def handle_form(cls) -> tuple[str | None, LazyString | None]:
|
def handle_form(cls):
|
||||||
form = RegisterForm()
|
form = RegisterForm()
|
||||||
if not form.validate_on_submit():
|
if not form.validate_on_submit():
|
||||||
return None, None
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
user = User(
|
user = User(
|
||||||
username=str(form.username.data),
|
username=str(form.username.data),
|
||||||
password=cls.encrypt_password(str(form.password.data)),
|
password=cls.encrypt_password(str(form.password.data)),
|
||||||
email=str(form.email.data),
|
email=str(form.email.data),
|
||||||
)
|
)
|
||||||
try:
|
|
||||||
|
if not user.username_free():
|
||||||
|
flash(lazy_gettext("page.register.status.username_exists"), "danger") # pyright: ignore[reportArgumentType]
|
||||||
|
return
|
||||||
|
|
||||||
|
if not user.email_free():
|
||||||
|
flash(lazy_gettext("page.register.status.email_exists"), "danger") # pyright: ignore[reportArgumentType]
|
||||||
|
return
|
||||||
|
|
||||||
db.session.add(user)
|
db.session.add(user)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
except Exception:
|
except Exception:
|
||||||
return "error", lazy_gettext("page.register.status.email_already_exists")
|
flash(lazy_gettext("page.register.status.insert_error"), "danger") # pyright: ignore[reportArgumentType]
|
||||||
return "success", lazy_gettext("page.register.status.success")
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
{%with messages = get_flashed_messages(with_categories=true)%}
|
||||||
|
{%if messages%}
|
||||||
|
{%for category, message in messages%}
|
||||||
|
{# Categories: danger (Error), success (Success), info (Message) #}
|
||||||
|
<div class="alert alert-{{category}} alert-dismissible" role="alert">
|
||||||
|
{{message}}
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="base.label.close"></button>
|
||||||
|
</div>
|
||||||
|
{%endfor%}
|
||||||
|
{%endif%}
|
||||||
|
{%endwith%}
|
||||||
|
|
@ -9,9 +9,7 @@
|
||||||
<h1 class="text-center text-primary-emphasis">{{_('page.login.title')}}</h1>
|
<h1 class="text-center text-primary-emphasis">{{_('page.login.title')}}</h1>
|
||||||
|
|
||||||
<form class="border border-secondary bg-secondary-subtle rounded p-3" method="POST">
|
<form class="border border-secondary bg-secondary-subtle rounded p-3" method="POST">
|
||||||
{%if bp.data["status"]%}
|
{%include "components/flash.jinja"%}
|
||||||
<div class="alert alert-{{bp.data['status_class']}}" role="alert">{{bp.data["status"]}}</div>
|
|
||||||
{%endif%}
|
|
||||||
{{bp.data["form"].hidden_tag() }}
|
{{bp.data["form"].hidden_tag() }}
|
||||||
{{form.field(bp.data["form"].username)}}
|
{{form.field(bp.data["form"].username)}}
|
||||||
{{form.field(bp.data["form"].password)}}
|
{{form.field(bp.data["form"].password)}}
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,11 @@
|
||||||
<h1 class="text-center text-primary-emphasis">{{_('page.register.title')}}</h1>
|
<h1 class="text-center text-primary-emphasis">{{_('page.register.title')}}</h1>
|
||||||
|
|
||||||
<form class="border border-secondary bg-secondary-subtle rounded p-3" method="POST">
|
<form class="border border-secondary bg-secondary-subtle rounded p-3" method="POST">
|
||||||
{%if bp.data["status"]%}
|
{%include "components/flash.jinja"%}
|
||||||
<div class="alert alert-{{bp.data['status_class']}}" role="alert">{{bp.data["status"]}}</div>
|
|
||||||
{%endif%}
|
|
||||||
{{bp.data["form"].hidden_tag() }}
|
{{bp.data["form"].hidden_tag() }}
|
||||||
{{form.field(input=bp.data["form"].username, id="username", prefix="@")}}
|
{{form.field(input=bp.data["form"].username, id="username", prefix="@")}}
|
||||||
{{form.field(input=bp.data["form"].password)}}
|
{{form.field(input=bp.data["form"].password)}}
|
||||||
|
{{form.field(input=bp.data["form"].retype_password)}}
|
||||||
{{form.field(input=bp.data["form"].email)}}
|
{{form.field(input=bp.data["form"].email)}}
|
||||||
<button type="submit" class="my-3 btn btn-primary text-center">{{_('page.register.form.submit')}}</button>
|
<button type="submit" class="my-3 btn btn-primary text-center">{{_('page.register.form.submit')}}</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue