Source code for feretui.actions

# This file is a part of the FeretUI project
#
#    Copyright (C) 2024 Jean-Sebastien SUZANNE <js.suzanne@gmail.com>
#
# This Source Code Form is subject to the terms of the Mozilla Public License,
# v. 2.0. If a copy of the MPL was not distributed with this file,You can
# obtain one at http://mozilla.org/MPL/2.0/.
"""Module feretui.actions.

The actions is called by the :meth:`feretui.feretui.FeretUI.execute_action`.

The availlable actions are:

* :func:`.goto`.
* :func:`.login_password`.
* :func:`.login_signup`.
* :func:`.logout`.
"""

from typing import TYPE_CHECKING

from markupsafe import Markup

from feretui.exceptions import ActionError, ResourceError
from feretui.helper import (
    action_for_authenticated_user,
    action_for_unauthenticated_user,
    action_validator,
)
from feretui.pages import login, signup
from feretui.request import Request
from feretui.response import Response

if TYPE_CHECKING:
    from feretui.feretui import FeretUI


[docs] @action_validator(methods=[Request.GET]) def goto( feretui: "FeretUI", request: Request, ) -> str: """Render the page and change the url in the browser. the page is an entry in the query string of the request. If *in-aside* is in the querystring, It is mean that the page is rendering inside the page aside-menu and the url to push have to keep this information. :param feretui: The feretui client :type feretui: :class:`feretui.feretui.FeretUI` :param request: The request :type request: :class:`feretui.request.Request` :return: The page to display :rtype: :class:`feretui.response.Response` """ options = request.query.copy() if "page" not in options: raise ActionError("page in the query string is missing") page = options["page"][0] # WARN: options can be modified by the page body = feretui.get_page(page)(feretui, request.session, options) base_url = request.get_base_url_from_current_url() if options.get("in-aside"): options.update( { "in-aside": [], "page": ["aside-menu"], "aside": options["in-aside"], "aside_page": [page], }, ) url = request.get_url_from_dict(base_url=base_url, querystring=options) return Response( Markup.unescape(body), headers={ "HX-Push-Url": url, }, )
[docs] @action_validator(methods=[Request.POST]) @action_for_unauthenticated_user def login_password( feretui: "FeretUI", request: Request, ) -> str: """Login the user. Used the LoginForm passed in the request.session. :param feretui: The feretui client :type feretui: :class:`feretui.feretui.FeretUI` :param request: The request :type request: :class:`feretui.request.Request` :return: The page to display :rtype: :class:`feretui.response.Response` """ form = request.session.LoginForm(request.form) if form.validate(): try: request.session.login(form) except Exception as e: return Response( login( feretui, request.session, {"form": form, "error": str(e)}, ), ) qs = request.get_query_string_from_current_url() if qs.get("page") == ["login"]: base_url = request.get_base_url_from_current_url() headers = { "HX-Redirect": f"{base_url}?page=homepage", } else: headers = { "HX-Refresh": "true", } return Response("", headers=headers) return Response(login(feretui, request.session, {"form": form}))
[docs] @action_validator(methods=[Request.POST]) @action_for_unauthenticated_user def login_signup( feretui: "FeretUI", request: Request, ) -> str: """Signup actions. Used the SignUpForm passed in the request.session. :param feretui: The feretui client :type feretui: :class:`feretui.feretui.FeretUI` :param request: The request :type request: :class:`feretui.request.Request` :return: The page to display :rtype: :class:`feretui.response.Response` """ form = request.session.SignUpForm(request.form) if form.validate(): try: redirect = request.session.signup(form) except Exception as e: return Response( signup( feretui, request.session, {"form": form, "error": str(e)}, ), ) if redirect: qs = request.get_query_string_from_current_url() if qs.get("page") == ["signup"]: base_url = request.get_base_url_from_current_url() headers = { "HX-Redirect": f"{base_url}?page=homepage", } else: headers = { "HX-Refresh": "true", } return Response("", headers=headers) return Response(signup(feretui, request.session, {"form": form}))
[docs] @action_validator(methods=[Request.POST]) @action_for_authenticated_user def logout( feretui: "FeretUI", # noqa: ARG001 request: Request, ) -> str: """Logout actions. Used the SignUpForm passed in the request.session. :param feretui: The feretui client :type feretui: :class:`feretui.feretui.FeretUI` :param request: The request :type request: :class:`feretui.request.Request` :return: The page to display :rtype: :class:`feretui.response.Response` """ request.session.logout() base_url = request.get_base_url_from_current_url() url = request.get_url_from_dict(base_url=base_url, querystring={}) return Response("", headers={"HX-Redirect": url})
[docs] @action_validator() def resource( feretui: "FeretUI", request: Request, ) -> str: """Resource entry point actions. Used the SignUpForm passed in the request.session. :param feretui: The feretui client :type feretui: :class:`feretui.feretui.FeretUI` :param request: The request :type request: :class:`feretui.request.Request` :return: The page to display :rtype: :class:`feretui.response.Response` """ qs = request.get_query_string_from_current_url() code = qs.get("resource", [None])[0] if not code: raise ResourceError("No resource in the query string") resource = feretui.get_resource(code) return resource.router(feretui, request)