apache-airflow-providers-fab 3.0.1__py3-none-any.whl → 3.1.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- airflow/providers/fab/__init__.py +1 -1
- airflow/providers/fab/auth_manager/api_endpoints/user_endpoint.py +2 -2
- airflow/providers/fab/auth_manager/api_fastapi/datamodels/login.py +0 -7
- airflow/providers/fab/auth_manager/api_fastapi/datamodels/roles.py +63 -0
- airflow/providers/fab/auth_manager/api_fastapi/openapi/v2-fab-auth-manager-generated.yaml +416 -16
- airflow/providers/fab/auth_manager/api_fastapi/parameters.py +55 -0
- airflow/providers/fab/auth_manager/api_fastapi/routes/login.py +37 -5
- airflow/providers/fab/auth_manager/api_fastapi/routes/roles.py +137 -0
- airflow/providers/fab/auth_manager/api_fastapi/security.py +32 -0
- airflow/providers/fab/auth_manager/api_fastapi/services/login.py +12 -25
- airflow/providers/fab/auth_manager/api_fastapi/services/roles.py +158 -0
- airflow/providers/fab/auth_manager/api_fastapi/sorting.py +49 -0
- airflow/providers/fab/auth_manager/fab_auth_manager.py +33 -3
- airflow/providers/fab/auth_manager/models/__init__.py +3 -8
- airflow/providers/fab/auth_manager/models/db.py +1 -1
- airflow/providers/fab/auth_manager/security_manager/override.py +52 -9
- airflow/providers/fab/www/api_connexion/parameters.py +1 -46
- airflow/providers/fab/www/app.py +13 -10
- airflow/providers/fab/www/extensions/init_appbuilder.py +5 -2
- airflow/providers/fab/www/extensions/init_security.py +1 -1
- airflow/providers/fab/www/package-lock.json +315 -217
- airflow/providers/fab/www/package.json +9 -9
- airflow/providers/fab/www/session.py +5 -8
- airflow/providers/fab/www/static/dist/{743.935ed3d26e56ed8f63d3.js → 743.0c0bf201ae17e66a9a3f.js} +1 -1
- airflow/providers/fab/www/static/dist/{main.3cf3be1a0c5439bb640d.js → main.bc1f701c3d133e2a3bab.js} +1 -1
- airflow/providers/fab/www/static/dist/manifest.json +13 -13
- airflow/providers/fab/www/views.py +18 -14
- {apache_airflow_providers_fab-3.0.1.dist-info → apache_airflow_providers_fab-3.1.0rc1.dist-info}/METADATA +15 -14
- {apache_airflow_providers_fab-3.0.1.dist-info → apache_airflow_providers_fab-3.1.0rc1.dist-info}/RECORD +48 -42
- /airflow/providers/fab/migrations/versions/{0001_1_4_0_create_ab_tables_if_missing.py → 0000_1_4_0_create_ab_tables_if_missing.py} +0 -0
- /airflow/providers/fab/www/static/dist/{743.935ed3d26e56ed8f63d3.js.LICENSE.txt → 743.0c0bf201ae17e66a9a3f.js.LICENSE.txt} +0 -0
- /airflow/providers/fab/www/static/dist/{airflowDefaultTheme.ff5a35f322070b094aa2.css → airflowDefaultTheme.ef6fc04c9b6920cd75c9.css} +0 -0
- /airflow/providers/fab/www/static/dist/{airflowDefaultTheme.ff5a35f322070b094aa2.js → airflowDefaultTheme.ef6fc04c9b6920cd75c9.js} +0 -0
- /airflow/providers/fab/www/static/dist/{flash.5583a9e0cf11f2be93da.css → flash.eaaf777ec1b3628cf7be.css} +0 -0
- /airflow/providers/fab/www/static/dist/{flash.5583a9e0cf11f2be93da.js → flash.eaaf777ec1b3628cf7be.js} +0 -0
- /airflow/providers/fab/www/static/dist/{loadingDots.2e5f555f0753107b0300.css → loadingDots.76f4332c0a932c3dc08f.css} +0 -0
- /airflow/providers/fab/www/static/dist/{loadingDots.2e5f555f0753107b0300.js → loadingDots.76f4332c0a932c3dc08f.js} +0 -0
- /airflow/providers/fab/www/static/dist/{main.3cf3be1a0c5439bb640d.css → main.bc1f701c3d133e2a3bab.css} +0 -0
- /airflow/providers/fab/www/static/dist/{main.3cf3be1a0c5439bb640d.js.LICENSE.txt → main.bc1f701c3d133e2a3bab.js.LICENSE.txt} +0 -0
- /airflow/providers/fab/www/static/dist/{materialIcons.3e67dd6fbfcc4f3b5105.css → materialIcons.ad07a489b2f0fc1a96bf.css} +0 -0
- /airflow/providers/fab/www/static/dist/{materialIcons.3e67dd6fbfcc4f3b5105.js → materialIcons.ad07a489b2f0fc1a96bf.js} +0 -0
- /airflow/providers/fab/www/static/dist/{moment.9baee5ec3d7639a10897.js → moment.5b85b4f6be2fe9c405ac.js} +0 -0
- /airflow/providers/fab/www/static/dist/{runtime.6ad9da077ea169d60db9.js → runtime.254c277d91ce3ac79c64.js} +0 -0
- {apache_airflow_providers_fab-3.0.1.dist-info → apache_airflow_providers_fab-3.1.0rc1.dist-info}/WHEEL +0 -0
- {apache_airflow_providers_fab-3.0.1.dist-info → apache_airflow_providers_fab-3.1.0rc1.dist-info}/entry_points.txt +0 -0
- {apache_airflow_providers_fab-3.0.1.dist-info → apache_airflow_providers_fab-3.1.0rc1.dist-info}/licenses/3rd-party-licenses/LICENSES-ui.txt +0 -0
- {airflow/providers/fab → apache_airflow_providers_fab-3.1.0rc1.dist-info/licenses}/LICENSE +0 -0
- {apache_airflow_providers_fab-3.0.1.dist-info → apache_airflow_providers_fab-3.1.0rc1.dist-info}/licenses/NOTICE +0 -0
|
@@ -17,21 +17,16 @@
|
|
|
17
17
|
from __future__ import annotations
|
|
18
18
|
|
|
19
19
|
import logging
|
|
20
|
-
from collections.abc import Callable
|
|
20
|
+
from collections.abc import Callable
|
|
21
21
|
from functools import wraps
|
|
22
22
|
from typing import TYPE_CHECKING, Any, TypeVar, cast
|
|
23
23
|
|
|
24
|
-
from pendulum.parsing import ParserError
|
|
25
|
-
from sqlalchemy import text
|
|
26
|
-
|
|
27
24
|
from airflow.configuration import conf
|
|
28
25
|
from airflow.providers.fab.www.api_connexion.exceptions import BadRequest
|
|
29
|
-
from airflow.utils import timezone
|
|
30
26
|
|
|
31
27
|
if TYPE_CHECKING:
|
|
32
28
|
from datetime import datetime
|
|
33
29
|
|
|
34
|
-
from sqlalchemy.sql import Select
|
|
35
30
|
|
|
36
31
|
log = logging.getLogger(__name__)
|
|
37
32
|
|
|
@@ -42,24 +37,6 @@ def validate_istimezone(value: datetime) -> None:
|
|
|
42
37
|
raise BadRequest("Invalid datetime format", detail="Naive datetime is disallowed")
|
|
43
38
|
|
|
44
39
|
|
|
45
|
-
def format_datetime(value: str) -> datetime:
|
|
46
|
-
"""
|
|
47
|
-
Format datetime objects.
|
|
48
|
-
|
|
49
|
-
Datetime format parser for args since connexion doesn't parse datetimes
|
|
50
|
-
https://github.com/zalando/connexion/issues/476
|
|
51
|
-
|
|
52
|
-
This should only be used within connection views because it raises 400
|
|
53
|
-
"""
|
|
54
|
-
value = value.strip()
|
|
55
|
-
if value[-1] != "Z":
|
|
56
|
-
value = value.replace(" ", "+")
|
|
57
|
-
try:
|
|
58
|
-
return timezone.parse(value)
|
|
59
|
-
except (ParserError, TypeError) as err:
|
|
60
|
-
raise BadRequest("Incorrect datetime argument", detail=str(err))
|
|
61
|
-
|
|
62
|
-
|
|
63
40
|
def check_limit(value: int) -> int:
|
|
64
41
|
"""
|
|
65
42
|
Check the limit does not exceed configured value.
|
|
@@ -107,25 +84,3 @@ def format_parameters(params_formatters: dict[str, Callable[[Any], Any]]) -> Cal
|
|
|
107
84
|
return cast("T", wrapped_function)
|
|
108
85
|
|
|
109
86
|
return format_parameters_decorator
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def apply_sorting(
|
|
113
|
-
query: Select,
|
|
114
|
-
order_by: str,
|
|
115
|
-
to_replace: dict[str, str] | None = None,
|
|
116
|
-
allowed_attrs: Container[str] | None = None,
|
|
117
|
-
) -> Select:
|
|
118
|
-
"""Apply sorting to query."""
|
|
119
|
-
lstriped_orderby = order_by.lstrip("-")
|
|
120
|
-
if allowed_attrs and lstriped_orderby not in allowed_attrs:
|
|
121
|
-
raise BadRequest(
|
|
122
|
-
detail=f"Ordering with '{lstriped_orderby}' is disallowed or "
|
|
123
|
-
f"the attribute does not exist on the model"
|
|
124
|
-
)
|
|
125
|
-
if to_replace:
|
|
126
|
-
lstriped_orderby = to_replace.get(lstriped_orderby, lstriped_orderby)
|
|
127
|
-
if order_by[0] == "-":
|
|
128
|
-
order_by = f"{lstriped_orderby} desc"
|
|
129
|
-
else:
|
|
130
|
-
order_by = f"{lstriped_orderby} asc"
|
|
131
|
-
return query.order_by(text(order_by))
|
airflow/providers/fab/www/app.py
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
20
|
from datetime import timedelta
|
|
21
|
+
from functools import cache
|
|
21
22
|
from os.path import isabs
|
|
22
23
|
|
|
23
24
|
from flask import Flask
|
|
@@ -30,7 +31,7 @@ from airflow.api_fastapi.app import get_auth_manager
|
|
|
30
31
|
from airflow.configuration import conf
|
|
31
32
|
from airflow.exceptions import AirflowConfigException
|
|
32
33
|
from airflow.logging_config import configure_logging
|
|
33
|
-
from airflow.providers.fab.www.extensions.init_appbuilder import
|
|
34
|
+
from airflow.providers.fab.www.extensions.init_appbuilder import AirflowAppBuilder
|
|
34
35
|
from airflow.providers.fab.www.extensions.init_jinja_globals import init_jinja_globals
|
|
35
36
|
from airflow.providers.fab.www.extensions.init_manifest_files import configure_manifest_files
|
|
36
37
|
from airflow.providers.fab.www.extensions.init_security import init_api_auth
|
|
@@ -44,8 +45,6 @@ from airflow.providers.fab.www.extensions.init_views import (
|
|
|
44
45
|
from airflow.providers.fab.www.extensions.init_wsgi_middlewares import init_wsgi_middleware
|
|
45
46
|
from airflow.providers.fab.www.utils import get_session_lifetime_config
|
|
46
47
|
|
|
47
|
-
app: Flask | None = None
|
|
48
|
-
|
|
49
48
|
# Initializes at the module level, so plugins can access it.
|
|
50
49
|
# See: /docs/plugins.rst
|
|
51
50
|
csrf = CSRFProtect()
|
|
@@ -85,6 +84,8 @@ def create_app(enable_plugins: bool):
|
|
|
85
84
|
csrf.init_app(flask_app)
|
|
86
85
|
|
|
87
86
|
db = SQLAlchemy(flask_app)
|
|
87
|
+
if settings.Session is None:
|
|
88
|
+
raise RuntimeError("Session not configured. Call configure_orm() first.")
|
|
88
89
|
db.session = settings.Session
|
|
89
90
|
|
|
90
91
|
configure_logging()
|
|
@@ -92,7 +93,12 @@ def create_app(enable_plugins: bool):
|
|
|
92
93
|
init_api_auth(flask_app)
|
|
93
94
|
|
|
94
95
|
with flask_app.app_context():
|
|
95
|
-
|
|
96
|
+
AirflowAppBuilder(
|
|
97
|
+
app=flask_app,
|
|
98
|
+
session=db.session(),
|
|
99
|
+
base_template="airflow/main.html",
|
|
100
|
+
enable_plugins=enable_plugins,
|
|
101
|
+
)
|
|
96
102
|
init_error_handlers(flask_app)
|
|
97
103
|
# In two scenarios a Flask application can be created:
|
|
98
104
|
# - To support Airflow 2 plugins relying on Flask (``enable_plugins`` is True)
|
|
@@ -112,15 +118,12 @@ def create_app(enable_plugins: bool):
|
|
|
112
118
|
return flask_app
|
|
113
119
|
|
|
114
120
|
|
|
121
|
+
@cache
|
|
115
122
|
def cached_app():
|
|
116
123
|
"""Return cached instance of Airflow WWW app."""
|
|
117
|
-
|
|
118
|
-
if not app:
|
|
119
|
-
app = create_app()
|
|
120
|
-
return app
|
|
124
|
+
return create_app()
|
|
121
125
|
|
|
122
126
|
|
|
123
127
|
def purge_cached_app():
|
|
124
128
|
"""Remove the cached version of the app in global state."""
|
|
125
|
-
|
|
126
|
-
app = None
|
|
129
|
+
cached_app.cache_clear()
|
|
@@ -42,7 +42,7 @@ from airflow import settings
|
|
|
42
42
|
from airflow.api_fastapi.app import create_auth_manager, get_auth_manager
|
|
43
43
|
from airflow.configuration import conf
|
|
44
44
|
from airflow.providers.fab.www.security_manager import AirflowSecurityManagerV2
|
|
45
|
-
from airflow.providers.fab.www.views import FabIndexView
|
|
45
|
+
from airflow.providers.fab.www.views import FabIndexView, redirect
|
|
46
46
|
|
|
47
47
|
if TYPE_CHECKING:
|
|
48
48
|
from flask import Flask
|
|
@@ -216,6 +216,7 @@ class AirflowAppBuilder:
|
|
|
216
216
|
from airflow.providers.fab.www.views import get_safe_url
|
|
217
217
|
|
|
218
218
|
fab_sec_views.get_safe_redirect = get_safe_url
|
|
219
|
+
fab_sec_views.redirect = redirect
|
|
219
220
|
|
|
220
221
|
def _init_extension(self, app):
|
|
221
222
|
app.appbuilder = self
|
|
@@ -473,7 +474,7 @@ class AirflowAppBuilder:
|
|
|
473
474
|
baseview=baseview,
|
|
474
475
|
cond=cond,
|
|
475
476
|
)
|
|
476
|
-
if
|
|
477
|
+
if current_app:
|
|
477
478
|
self._add_permissions_menu(name)
|
|
478
479
|
if category:
|
|
479
480
|
self._add_permissions_menu(category)
|
|
@@ -592,6 +593,8 @@ class AirflowAppBuilder:
|
|
|
592
593
|
|
|
593
594
|
def init_appbuilder(app: Flask, enable_plugins: bool) -> AirflowAppBuilder:
|
|
594
595
|
"""Init `Flask App Builder <https://flask-appbuilder.readthedocs.io/en/latest/>`__."""
|
|
596
|
+
if settings.Session is None:
|
|
597
|
+
raise RuntimeError("Session not configured. Call configure_orm() first.")
|
|
595
598
|
return AirflowAppBuilder(
|
|
596
599
|
app=app,
|
|
597
600
|
session=settings.Session(),
|
|
@@ -20,7 +20,7 @@ import logging
|
|
|
20
20
|
from importlib import import_module
|
|
21
21
|
|
|
22
22
|
from airflow.configuration import conf
|
|
23
|
-
from airflow.
|
|
23
|
+
from airflow.providers.common.compat.sdk import AirflowException
|
|
24
24
|
|
|
25
25
|
log = logging.getLogger(__name__)
|
|
26
26
|
|