moved form code to application folder

This commit is contained in:
crunk 2024-03-30 18:09:04 +01:00
parent 7fc2534744
commit b435b159e3
17 changed files with 422 additions and 14 deletions

View File

@ -0,0 +1,26 @@
"""Form object declaration."""
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, validators
from wtforms.validators import Length
class BorrowForm(FlaskForm):
"""Borrow a publication form."""
borrowed = StringField(
"Fill in your name if you're going to borrow this publication.",
[
validators.InputRequired(),
Length(
min=3, message="Just so we know who is borrowing this book."
),
],
)
secret = StringField(
"Librarians secret:",
[
validators.InputRequired(),
Length(min=2, message="Fill in the secret to unlock to library."),
],
)
submit = SubmitField("Borrow")

View File

@ -0,0 +1,14 @@
"""Forgotten password form to help user."""
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, validators
from wtforms.validators import Email, Length
class ForgotPasswordForm(FlaskForm):
"""Forgotten password csv-library form"""
email = StringField(
"Email address:",
validators=[validators.InputRequired(), Email(), Length(6, 64)],
)
submit = SubmitField("Send email")

View File

@ -0,0 +1,17 @@
"""Login form to validate user."""
from flask_wtf import FlaskForm
from wtforms import PasswordField, StringField, SubmitField, validators
from wtforms.validators import Email, Length
class LoginForm(FlaskForm):
"""Login csv-library form"""
email = StringField(
"Email address:",
validators=[validators.InputRequired(), Email(), Length(6, 64)],
)
password = PasswordField(
"Password:", validators=[validators.InputRequired()]
)
submit = SubmitField("Sign In")

View File

@ -0,0 +1,37 @@
"""Register form to make a new user."""
from flask_wtf import FlaskForm
from wtforms import PasswordField, StringField, SubmitField, validators
from wtforms.validators import Email, EqualTo, Length, ValidationError
class RegisterForm(FlaskForm):
"""Register for csv-library form"""
username = StringField(
"Username:",
validators=[validators.InputRequired(), Length(3, 150)],
)
email = StringField(
"Email address:",
validators=[
validators.InputRequired(),
Email(),
Length(6, 64),
],
)
password = PasswordField(
"New password:",
validators=[validators.InputRequired(), Length(12, 72)],
)
confirmpassword = PasswordField(
"Confirm your password:",
validators=[
validators.InputRequired(),
Length(12, 72),
EqualTo("password", message="Passwords must match !"),
],
)
submit = SubmitField("Register to the library")

View File

@ -0,0 +1,22 @@
"""Reset Password Form form to reset a users PasswordField."""
from flask_wtf import FlaskForm
from wtforms import PasswordField, SubmitField, validators
from wtforms.validators import EqualTo, Length
class ResetPasswordForm(FlaskForm):
"""ResetPassword for csv-library form"""
password = PasswordField(
"New password:",
validators=[validators.InputRequired(), Length(12, 72)],
)
confirmpassword = PasswordField(
"Confirm your password:",
validators=[
validators.InputRequired(),
Length(12, 72),
EqualTo("password", message="Passwords must match !"),
],
)
submit = SubmitField("Reset your password")

View File

@ -0,0 +1,76 @@
"""Form object declaration."""
from flask_wtf import FlaskForm
from flask_wtf.file import FileAllowed, FileField
from wtforms import (
IntegerField,
RadioField,
StringField,
SubmitField,
validators,
)
from wtforms.validators import Length, NumberRange
class PublicationForm(FlaskForm):
"""Publication upload form."""
uploadpublication = StringField(
"Title of the publication:",
[
validators.InputRequired(),
Length(
min=3, message="A publication in the library needs a title."
),
],
)
author = StringField(
"The author or editor:",
[
validators.InputRequired(),
Length(
min=3,
message=(
"If the author or editor is not known just type unkown."
),
),
],
)
year = IntegerField(
"Year:",
[validators.InputRequired(), NumberRange(min=0, max=2050)],
default=2023,
)
fields = StringField("Fields:")
type = StringField(
"Type of publication:",
[
validators.InputRequired(),
Length(
min=3,
message=(
"Here you can use terms such as zine, paperback,"
" hardcover."
),
),
],
)
publishers = StringField("Publishers:")
license = StringField("License:")
highlights = StringField("Highlights from the publication:")
comments = StringField("Comments on the publication:")
image = FileField(
"Image of the book:",
validators=[FileAllowed(["jpg", "png", "gif"], "Images only!")],
)
pdf = FileField(
"Pdf of the book:",
validators=[FileAllowed(["pdf"], "Only pdf uploads supported")],
)
secret = StringField(
"Librarians secret:",
[
validators.InputRequired(),
Length(min=2, message="Fill in the secret to unlock to library."),
],
)
submit = SubmitField("Submit")

View File

@ -4,7 +4,7 @@ from uuid import uuid1
from app import db from app import db
from flask import render_template from flask import render_template
from flask_mail import Message from flask_mail import Message
from forms.forgotpasswordform import ForgotPasswordForm from application.forms.forgotpasswordform import ForgotPasswordForm
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError, DatabaseError,
DataError, DataError,
@ -14,7 +14,7 @@ from sqlalchemy.exc import (
from application.models.usermodel import User from application.models.usermodel import User
def ForgotPassword(mail): def ForgotPassword():
forgotpasswordform = ForgotPasswordForm() forgotpasswordform = ForgotPasswordForm()
if forgotpasswordform.validate_on_submit(): if forgotpasswordform.validate_on_submit():
user = User.query.filter_by( user = User.query.filter_by(
@ -29,7 +29,7 @@ def ForgotPassword(mail):
contain any new mail, please check your spam folder.)""" contain any new mail, please check your spam folder.)"""
) )
return render_template( return render_template(
"forgotpassword.html", forgotpasswordform=forgotpasswordform "user/forgotpassword.html", forgotpasswordform=forgotpasswordform
) )

View File

@ -1,7 +1,7 @@
from flask import abort, flash, redirect, render_template, request, url_for from flask import abort, flash, redirect, render_template, request, url_for
from flask_bcrypt import check_password_hash from flask_bcrypt import check_password_hash
from flask_login import login_user from flask_login import login_user
from forms.loginform import LoginForm from application.forms.loginform import LoginForm
from application.models.usermodel import User from application.models.usermodel import User
@ -23,7 +23,7 @@ def LoginUser():
else: else:
flash("Invalid email or password!", "danger") flash("Invalid email or password!", "danger")
loginform.password.errors.append("Invalid email or password!") loginform.password.errors.append("Invalid email or password!")
return render_template("login.html", loginform=loginform) return render_template("user/login.html", loginform=loginform)
except Exception as e: except Exception as e:
flash(e, "danger") flash(e, "danger")
return render_template("user/login.html", loginform=loginform) return render_template("user/login.html", loginform=loginform)

View File

@ -2,7 +2,7 @@ from app import db
from flask import flash, redirect, render_template, url_for from flask import flash, redirect, render_template, url_for
from flask_bcrypt import generate_password_hash from flask_bcrypt import generate_password_hash
from flask_login import login_user from flask_login import login_user
from forms.registerform import RegisterForm from application.forms.registerform import RegisterForm
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError, DatabaseError,
DataError, DataError,

View File

@ -4,7 +4,7 @@ from app import db
from flask import flash, redirect, render_template, url_for from flask import flash, redirect, render_template, url_for
from flask_bcrypt import generate_password_hash from flask_bcrypt import generate_password_hash
from flask_login import login_user from flask_login import login_user
from forms.resetpasswordform import ResetPasswordForm from application.forms.resetpasswordform import ResetPasswordForm
from sqlalchemy.exc import ( from sqlalchemy.exc import (
DatabaseError, DatabaseError,
DataError, DataError,

View File

@ -0,0 +1 @@
Single-database configuration for Flask.

View File

@ -0,0 +1,50 @@
# A generic, single database configuration.
[alembic]
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s
# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false
# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic,flask_migrate
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = WARN
handlers = console
qualname =
[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine
[logger_alembic]
level = INFO
handlers =
qualname = alembic
[logger_flask_migrate]
level = INFO
handlers =
qualname = flask_migrate
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S

113
library/migrations/env.py Normal file
View File

@ -0,0 +1,113 @@
import logging
from logging.config import fileConfig
from flask import current_app
from alembic import context
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
logger = logging.getLogger('alembic.env')
def get_engine():
try:
# this works with Flask-SQLAlchemy<3 and Alchemical
return current_app.extensions['migrate'].db.get_engine()
except (TypeError, AttributeError):
# this works with Flask-SQLAlchemy>=3
return current_app.extensions['migrate'].db.engine
def get_engine_url():
try:
return get_engine().url.render_as_string(hide_password=False).replace(
'%', '%%')
except AttributeError:
return str(get_engine().url).replace('%', '%%')
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
config.set_main_option('sqlalchemy.url', get_engine_url())
target_db = current_app.extensions['migrate'].db
# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.
def get_metadata():
if hasattr(target_db, 'metadatas'):
return target_db.metadatas[None]
return target_db.metadata
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url, target_metadata=get_metadata(), literal_binds=True
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
# this callback is used to prevent an auto-migration from being generated
# when there are no changes to the schema
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
def process_revision_directives(context, revision, directives):
if getattr(config.cmd_opts, 'autogenerate', False):
script = directives[0]
if script.upgrade_ops.is_empty():
directives[:] = []
logger.info('No changes in schema detected.')
conf_args = current_app.extensions['migrate'].configure_args
if conf_args.get("process_revision_directives") is None:
conf_args["process_revision_directives"] = process_revision_directives
connectable = get_engine()
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=get_metadata(),
**conf_args
)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()

View File

@ -0,0 +1,24 @@
"""${message}
Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}
"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}
# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}
def upgrade():
${upgrades if upgrades else "pass"}
def downgrade():
${downgrades if downgrades else "pass"}

View File

@ -0,0 +1,28 @@
"""empty message
Revision ID: 3105f85a9d8e
Revises:
Create Date: 2024-03-30 17:50:00.878071
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '3105f85a9d8e'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###

View File

@ -13,16 +13,17 @@ from application.user.loginuser import LoginUser
from application.user.registeruser import RegisterUser from application.user.registeruser import RegisterUser
from application.user.forgotpassword import ForgotPassword from application.user.forgotpassword import ForgotPassword
from application.user.resetpassword import ResetPassword from application.user.resetpassword import ResetPassword
from application.models.usermodel import User
from flask import Blueprint, redirect, render_template, request, session from flask import Blueprint, redirect, render_template, request, session, url_for
from flask_wtf.csrf import CSRFProtect, CSRFError from flask_wtf.csrf import CSRFProtect, CSRFError
from flask_login import ( from flask_login import (
logout_user, logout_user,
login_required, login_required,
current_user, current_user,
) )
from forms.borrowform import BorrowForm from application.forms.borrowform import BorrowForm
from forms.uploadform import PublicationForm from application.forms.uploadform import PublicationForm
from icalendar import Calendar from icalendar import Calendar
from PIL import Image from PIL import Image
from requests import get from requests import get
@ -121,7 +122,7 @@ def saveimage(image, id):
"""helper function that can save images""" """helper function that can save images"""
image.save(os.path.join(APP.config["UPLOAD_FOLDER"], image.filename)) image.save(os.path.join(APP.config["UPLOAD_FOLDER"], image.filename))
orig_image = Image.open( orig_image = Image.open(
os.path.join(APP.config["UPLOAD_FOLDER"], image.filename) os.path.join(APP.confmailig["UPLOAD_FOLDER"], image.filename)
) )
new_width = 640 new_width = 640
new_height = int(new_width * orig_image.height / orig_image.width) new_height = int(new_width * orig_image.height / orig_image.width)
@ -150,7 +151,7 @@ def register():
@APP.route("/forgotpassword", methods=["GET", "POST"]) @APP.route("/forgotpassword", methods=["GET", "POST"])
def forgotpassword(): def forgotpassword():
return ForgotPassword(mail) return ForgotPassword()
@APP.route("/resetpassword/<path>", methods=["GET", "POST"]) @APP.route("/resetpassword/<path>", methods=["GET", "POST"])

View File

@ -107,8 +107,7 @@ input {
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-align: right; padding: 0.8em;
padding: 0.8em 2em;
cursor: pointer; cursor: pointer;
} }