forked from Github-Mirrors/canaille
Refactored utils
This commit is contained in:
parent
81e80b8a59
commit
d53fdde986
18 changed files with 112 additions and 101 deletions
|
@ -138,7 +138,7 @@ def setup_flask(app):
|
|||
|
||||
@app.context_processor
|
||||
def global_processor():
|
||||
from .flaskutils import current_user
|
||||
from .utils.flask import current_user
|
||||
|
||||
return {
|
||||
"has_smtp": "SMTP" in app.config,
|
||||
|
|
|
@ -21,17 +21,6 @@ from flask_themer import render_template
|
|||
from werkzeug.datastructures import CombinedMultiDict
|
||||
from werkzeug.datastructures import FileStorage
|
||||
|
||||
from .apputils import b64_to_obj
|
||||
from .apputils import default_fields
|
||||
from .apputils import login_placeholder
|
||||
from .apputils import obj_to_b64
|
||||
from .apputils import profile_hash
|
||||
from .flaskutils import current_user
|
||||
from .flaskutils import permissions_needed
|
||||
from .flaskutils import render_htmx_template
|
||||
from .flaskutils import request_is_htmx
|
||||
from .flaskutils import smtp_needed
|
||||
from .flaskutils import user_needed
|
||||
from .forms import FirstLoginForm
|
||||
from .forms import ForgottenPasswordForm
|
||||
from .forms import InvitationForm
|
||||
|
@ -39,12 +28,23 @@ from .forms import LoginForm
|
|||
from .forms import PasswordForm
|
||||
from .forms import PasswordResetForm
|
||||
from .forms import profile_form
|
||||
from .forms import TableForm
|
||||
from .mails import send_invitation_mail
|
||||
from .mails import send_password_initialization_mail
|
||||
from .mails import send_password_reset_mail
|
||||
from .models import Group
|
||||
from .models import User
|
||||
from .utils import b64_to_obj
|
||||
from .utils import default_fields
|
||||
from .utils import login_placeholder
|
||||
from .utils import obj_to_b64
|
||||
from .utils import profile_hash
|
||||
from .utils.flask import current_user
|
||||
from .utils.flask import permissions_needed
|
||||
from .utils.flask import render_htmx_template
|
||||
from .utils.flask import request_is_htmx
|
||||
from .utils.flask import smtp_needed
|
||||
from .utils.flask import user_needed
|
||||
from .utils.forms import TableForm
|
||||
|
||||
|
||||
bp = Blueprint("account", __name__)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
from canaille.apputils import obj_to_b64
|
||||
from canaille.flaskutils import permissions_needed
|
||||
from canaille.forms import HTMXForm
|
||||
from canaille.mails import profile_hash
|
||||
from canaille.mails import send_test_mail
|
||||
from canaille.utils import obj_to_b64
|
||||
from canaille.utils.flask import permissions_needed
|
||||
from canaille.utils.forms import HTMXForm
|
||||
from flask import Blueprint
|
||||
from flask import current_app
|
||||
from flask import flash
|
||||
|
|
|
@ -1,26 +1,20 @@
|
|||
import math
|
||||
|
||||
import wtforms.form
|
||||
from canaille.flaskutils import request_is_htmx
|
||||
from canaille.utils.flask import request_is_htmx
|
||||
from flask import abort
|
||||
from flask import current_app
|
||||
from flask import g
|
||||
from flask import make_response
|
||||
from flask import request
|
||||
from flask_babel import lazy_gettext as _
|
||||
from flask_wtf import FlaskForm
|
||||
from flask_wtf.file import FileAllowed
|
||||
from flask_wtf.file import FileField
|
||||
|
||||
from .apputils import validate_uri
|
||||
from .i18n import native_language_name_from_code
|
||||
from .models import Group
|
||||
from .models import User
|
||||
|
||||
|
||||
def is_uri(form, field):
|
||||
if not validate_uri(field.data):
|
||||
raise wtforms.ValidationError(_("This is not a valid URL"))
|
||||
from .utils.forms import HTMXBaseForm
|
||||
from .utils.forms import HTMXForm
|
||||
from .utils.forms import is_uri
|
||||
|
||||
|
||||
def unique_login(form, field):
|
||||
|
@ -57,57 +51,6 @@ def existing_login(form, field):
|
|||
)
|
||||
|
||||
|
||||
class HTMXFormMixin:
|
||||
def validate(self, *args, **kwargs):
|
||||
"""
|
||||
If the request is a HTMX request, this will only render the field
|
||||
that triggered the request (after having validated the form). This
|
||||
uses the Flask abort method to interrupt the flow with an exception.
|
||||
"""
|
||||
if not request_is_htmx():
|
||||
return super().validate(*args, **kwargs)
|
||||
|
||||
field = self[request.headers.get("HX-Trigger-Name")]
|
||||
field.widget.hide_value = False
|
||||
self.process(request.form)
|
||||
super().validate(*args, **kwargs)
|
||||
form_macro = current_app.jinja_env.get_template("macro/form.html")
|
||||
response = make_response(form_macro.module.render_field(field))
|
||||
abort(response)
|
||||
|
||||
|
||||
class HTMXForm(HTMXFormMixin, FlaskForm):
|
||||
pass
|
||||
|
||||
|
||||
class HTMXBaseForm(HTMXFormMixin, wtforms.form.BaseForm):
|
||||
pass
|
||||
|
||||
|
||||
class TableForm(HTMXForm):
|
||||
def __init__(self, cls=None, page_size=25, fields=None, filter=None, **kwargs):
|
||||
filter = filter or {}
|
||||
super().__init__(**kwargs)
|
||||
if self.query.data:
|
||||
self.items = cls.fuzzy(self.query.data, fields, **filter)
|
||||
else:
|
||||
self.items = cls.query(**filter)
|
||||
|
||||
self.page_size = page_size
|
||||
self.nb_items = len(self.items)
|
||||
self.page_max = max(1, math.ceil(self.nb_items / self.page_size))
|
||||
first_item = (self.page.data - 1) * self.page_size
|
||||
last_item = min((self.page.data) * self.page_size, self.nb_items)
|
||||
self.items_slice = self.items[first_item:last_item]
|
||||
|
||||
page = wtforms.IntegerField(default=1)
|
||||
query = wtforms.StringField(default="")
|
||||
|
||||
def validate_page(self, field):
|
||||
if field.data < 1 or field.data > self.page_max:
|
||||
raise wtforms.validators.ValidationError(_("The page number is not valid"))
|
||||
|
||||
|
||||
class LoginForm(HTMXForm):
|
||||
login = wtforms.StringField(
|
||||
_("Login"),
|
||||
|
|
|
@ -7,13 +7,13 @@ from flask import url_for
|
|||
from flask_babel import gettext as _
|
||||
from flask_themer import render_template
|
||||
|
||||
from .flaskutils import permissions_needed
|
||||
from .flaskutils import render_htmx_template
|
||||
from .forms import CreateGroupForm
|
||||
from .forms import EditGroupForm
|
||||
from .forms import TableForm
|
||||
from .models import Group
|
||||
from .models import User
|
||||
from .utils.flask import permissions_needed
|
||||
from .utils.flask import render_htmx_template
|
||||
from .utils.forms import TableForm
|
||||
|
||||
bp = Blueprint("groups", __name__, url_prefix="/groups")
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ def setup_i18n(app):
|
|||
|
||||
|
||||
def locale_selector():
|
||||
from .flaskutils import current_user
|
||||
from .utils.flask import current_user
|
||||
|
||||
user = current_user()
|
||||
available_language_codes = getattr(g, "available_language_codes", [])
|
||||
|
|
|
@ -10,9 +10,9 @@ from flask import url_for
|
|||
from flask_babel import gettext as _
|
||||
from flask_themer import render_template
|
||||
|
||||
from .apputils import get_current_domain
|
||||
from .apputils import get_current_mail_domain
|
||||
from .apputils import profile_hash
|
||||
from .utils import get_current_domain
|
||||
from .utils import get_current_mail_domain
|
||||
from .utils import profile_hash
|
||||
|
||||
DEFAULT_SMTP_HOST = "localhost"
|
||||
DEFAULT_SMTP_PORT = 25
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from canaille.flaskutils import permissions_needed
|
||||
from canaille.flaskutils import render_htmx_template
|
||||
from canaille.forms import TableForm
|
||||
from canaille.oidc.models import AuthorizationCode
|
||||
from canaille.utils.flask import permissions_needed
|
||||
from canaille.utils.flask import render_htmx_template
|
||||
from canaille.utils.forms import TableForm
|
||||
from flask import abort
|
||||
from flask import Blueprint
|
||||
from flask import request
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import datetime
|
||||
|
||||
from canaille.flaskutils import permissions_needed
|
||||
from canaille.flaskutils import render_htmx_template
|
||||
from canaille.flaskutils import request_is_htmx
|
||||
from canaille.forms import TableForm
|
||||
from canaille.oidc.forms import ClientAddForm
|
||||
from canaille.oidc.models import Client
|
||||
from canaille.utils.flask import permissions_needed
|
||||
from canaille.utils.flask import render_htmx_template
|
||||
from canaille.utils.flask import request_is_htmx
|
||||
from canaille.utils.forms import TableForm
|
||||
from flask import abort
|
||||
from flask import Blueprint
|
||||
from flask import flash
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import datetime
|
||||
import uuid
|
||||
|
||||
from canaille.flaskutils import user_needed
|
||||
from canaille.oidc.models import Client
|
||||
from canaille.oidc.models import Consent
|
||||
from canaille.utils.flask import user_needed
|
||||
from flask import Blueprint
|
||||
from flask import flash
|
||||
from flask import redirect
|
||||
|
|
|
@ -19,10 +19,10 @@ from flask_babel import gettext as _
|
|||
from flask_themer import render_template
|
||||
from werkzeug.datastructures import CombinedMultiDict
|
||||
|
||||
from ..flaskutils import current_user
|
||||
from ..flaskutils import set_parameter_in_url_query
|
||||
from ..forms import FullLoginForm
|
||||
from ..models import User
|
||||
from ..utils.flask import current_user
|
||||
from ..utils.flask import set_parameter_in_url_query
|
||||
from .forms import AuthorizeForm
|
||||
from .forms import LogoutForm
|
||||
from .models import Client
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import wtforms
|
||||
from canaille.forms import HTMXForm
|
||||
from canaille.forms import is_uri
|
||||
from canaille.oidc.models import Client
|
||||
from canaille.utils.forms import HTMXForm
|
||||
from canaille.utils.forms import is_uri
|
||||
from flask_babel import lazy_gettext as _
|
||||
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import datetime
|
||||
|
||||
from canaille.flaskutils import permissions_needed
|
||||
from canaille.flaskutils import render_htmx_template
|
||||
from canaille.forms import TableForm
|
||||
from canaille.models import User
|
||||
from canaille.oidc.models import Client
|
||||
from canaille.oidc.models import Token
|
||||
from canaille.utils.flask import permissions_needed
|
||||
from canaille.utils.flask import render_htmx_template
|
||||
from canaille.utils.forms import TableForm
|
||||
from flask import abort
|
||||
from flask import Blueprint
|
||||
from flask import flash
|
||||
|
|
68
canaille/utils/forms.py
Normal file
68
canaille/utils/forms.py
Normal file
|
@ -0,0 +1,68 @@
|
|||
import math
|
||||
|
||||
import wtforms
|
||||
from flask import abort
|
||||
from flask import current_app
|
||||
from flask import make_response
|
||||
from flask import request
|
||||
from flask_babel import gettext as _
|
||||
from flask_wtf import FlaskForm
|
||||
|
||||
from . import validate_uri
|
||||
from .flask import request_is_htmx
|
||||
|
||||
|
||||
def is_uri(form, field):
|
||||
if not validate_uri(field.data):
|
||||
raise wtforms.ValidationError(_("This is not a valid URL"))
|
||||
|
||||
|
||||
class HTMXFormMixin:
|
||||
def validate(self, *args, **kwargs):
|
||||
"""
|
||||
If the request is a HTMX request, this will only render the field
|
||||
that triggered the request (after having validated the form). This
|
||||
uses the Flask abort method to interrupt the flow with an exception.
|
||||
"""
|
||||
if not request_is_htmx():
|
||||
return super().validate(*args, **kwargs)
|
||||
|
||||
field = self[request.headers.get("HX-Trigger-Name")]
|
||||
field.widget.hide_value = False
|
||||
self.process(request.form)
|
||||
super().validate(*args, **kwargs)
|
||||
form_macro = current_app.jinja_env.get_template("macro/form.html")
|
||||
response = make_response(form_macro.module.render_field(field))
|
||||
abort(response)
|
||||
|
||||
|
||||
class HTMXForm(HTMXFormMixin, FlaskForm):
|
||||
pass
|
||||
|
||||
|
||||
class HTMXBaseForm(HTMXFormMixin, wtforms.form.BaseForm):
|
||||
pass
|
||||
|
||||
|
||||
class TableForm(HTMXForm):
|
||||
def __init__(self, cls=None, page_size=25, fields=None, filter=None, **kwargs):
|
||||
filter = filter or {}
|
||||
super().__init__(**kwargs)
|
||||
if self.query.data:
|
||||
self.items = cls.fuzzy(self.query.data, fields, **filter)
|
||||
else:
|
||||
self.items = cls.query(**filter)
|
||||
|
||||
self.page_size = page_size
|
||||
self.nb_items = len(self.items)
|
||||
self.page_max = max(1, math.ceil(self.nb_items / self.page_size))
|
||||
first_item = (self.page.data - 1) * self.page_size
|
||||
last_item = min((self.page.data) * self.page_size, self.nb_items)
|
||||
self.items_slice = self.items[first_item:last_item]
|
||||
|
||||
page = wtforms.IntegerField(default=1)
|
||||
query = wtforms.StringField(default="")
|
||||
|
||||
def validate_page(self, field):
|
||||
if field.data < 1 or field.data > self.page_max:
|
||||
raise wtforms.validators.ValidationError(_("The page number is not valid"))
|
|
@ -1,4 +1,4 @@
|
|||
from canaille.apputils import validate_uri
|
||||
from canaille.utils import validate_uri
|
||||
|
||||
|
||||
def test_validate_uri():
|
||||
|
|
|
@ -4,7 +4,7 @@ import ldap
|
|||
import pytest
|
||||
import toml
|
||||
from canaille import create_app
|
||||
from canaille.flaskutils import set_parameter_in_url_query
|
||||
from canaille.utils.flask import set_parameter_in_url_query
|
||||
from flask import g
|
||||
from flask_webtest import TestApp
|
||||
|
||||
|
|
Loading…
Reference in a new issue