add Quart utilities add_i18n(), negotiate() add_rest()
This commit is contained in:
parent
5bdf13b104
commit
a23cad2e45
4 changed files with 95 additions and 2 deletions
|
|
@ -11,6 +11,7 @@
|
||||||
+ Add `redact` module with `redact_url_password()`
|
+ Add `redact` module with `redact_url_password()`
|
||||||
+ Add more exceptions: `NotFoundError()`, `BabelTowerError()`
|
+ Add more exceptions: `NotFoundError()`, `BabelTowerError()`
|
||||||
+ Add `sass` module
|
+ Add `sass` module
|
||||||
|
+ Add `quart` module with `negotiate()`, `add_rest()`, `add_i18n()`, `WantsContentType`
|
||||||
|
|
||||||
## 0.4.0
|
## 0.4.0
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,10 +67,11 @@ def get_flask_conf(key: str, default = None, *, app: Flask | None = None) -> Any
|
||||||
app = current_app
|
app = current_app
|
||||||
return app.config.get(key, default)
|
return app.config.get(key, default)
|
||||||
|
|
||||||
## XXX UNTESTED!
|
|
||||||
def harden(app: Flask):
|
def harden(app: Flask):
|
||||||
"""
|
"""
|
||||||
Make common "dork" endpoints unavailable
|
Make common "dork" endpoints unavailable
|
||||||
|
|
||||||
|
XXX UNTESTED!
|
||||||
"""
|
"""
|
||||||
i = 1
|
i = 1
|
||||||
for ep in SENSITIVE_ENDPOINTS:
|
for ep in SENSITIVE_ENDPOINTS:
|
||||||
|
|
@ -81,6 +82,7 @@ def harden(app: Flask):
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
||||||
|
|
||||||
# Optional dependency: do not import into __init__.py
|
# Optional dependency: do not import into __init__.py
|
||||||
__all__ = ('add_context_from_config', 'add_i18n', 'get_flask_conf', 'harden')
|
__all__ = ('add_context_from_config', 'add_i18n', 'get_flask_conf', 'harden')
|
||||||
|
|
||||||
|
|
|
||||||
24
src/suou/http.py
Normal file
24
src/suou/http.py
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
"""
|
||||||
|
Framework-agnostic utilities for web app development.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Copyright (c) 2025 Sakuragasaki46.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
See LICENSE for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
This software is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
import enum
|
||||||
|
|
||||||
|
class WantsContentType(enum.Enum):
|
||||||
|
PLAIN = 'text/plain'
|
||||||
|
JSON = 'application/json'
|
||||||
|
HTML = 'text/html'
|
||||||
|
|
||||||
|
|
@ -14,4 +14,70 @@ This software is distributed on an "AS IS" BASIS,
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# TODO everything
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from flask import current_app
|
||||||
|
from quart import Quart, request, g
|
||||||
|
from quart_schema import QuartSchema
|
||||||
|
|
||||||
|
from suou.http import WantsContentType
|
||||||
|
|
||||||
|
from .i18n import I18n
|
||||||
|
from .itertools import makelist
|
||||||
|
|
||||||
|
def add_i18n(app: Quart, i18n: I18n, var_name: str = 'T', *,
|
||||||
|
query_arg: str = 'lang', default_lang = 'en'):
|
||||||
|
'''
|
||||||
|
Integrate a I18n() object with a Quart application:
|
||||||
|
- set g.lang
|
||||||
|
- add T() to Jinja templates
|
||||||
|
|
||||||
|
XXX UNTESTED
|
||||||
|
'''
|
||||||
|
def _get_lang():
|
||||||
|
lang = request.args.get(query_arg)
|
||||||
|
if not lang:
|
||||||
|
for lp in request.headers.get('accept-language', 'en').split(','):
|
||||||
|
l = lp.split(';')[0]
|
||||||
|
lang = l
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
lang = default_lang
|
||||||
|
return lang
|
||||||
|
|
||||||
|
@app.context_processor
|
||||||
|
def _add_i18n():
|
||||||
|
return {var_name: i18n.lang(_get_lang()).t}
|
||||||
|
|
||||||
|
@app.before_request
|
||||||
|
def _add_language_code():
|
||||||
|
g.lang = _get_lang()
|
||||||
|
|
||||||
|
return app
|
||||||
|
|
||||||
|
|
||||||
|
def negotiate() -> WantsContentType:
|
||||||
|
"""
|
||||||
|
Return an appropriate MIME type for content negotiation.
|
||||||
|
"""
|
||||||
|
if 'application/json' in request.accept_mimetypes or any(request.path.startswith(f'/{p.strip('/')}/') for p in current_app.config.get('REST_PATHS')):
|
||||||
|
return WantsContentType.JSON
|
||||||
|
elif request.user_agent.string.startswith('Mozilla/'):
|
||||||
|
return WantsContentType.HTML
|
||||||
|
else:
|
||||||
|
return WantsContentType.PLAIN
|
||||||
|
|
||||||
|
|
||||||
|
def add_rest(app: Quart, *bases: str, **kwargs) -> QuartSchema:
|
||||||
|
"""
|
||||||
|
Construct a REST ...
|
||||||
|
|
||||||
|
The rest of ...
|
||||||
|
"""
|
||||||
|
|
||||||
|
schema = QuartSchema(app, **kwargs)
|
||||||
|
app.config['REST_PATHS'] = makelist(bases, wrap=False)
|
||||||
|
return schema
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ('add_i18n', 'negotiate', 'add_rest')
|
||||||
Loading…
Add table
Add a link
Reference in a new issue