80 lines
2.5 KiB
Python
80 lines
2.5 KiB
Python
import asyncio
|
|
from datetime import datetime, timedelta, timezone
|
|
from http.cookies import SimpleCookie
|
|
from os import PathLike
|
|
from pathlib import Path
|
|
from typing import Callable, List, Optional, TYPE_CHECKING, Union
|
|
from wsgiref.handlers import format_date_time
|
|
|
|
from .globals import current_app
|
|
from .typing import FilePath
|
|
|
|
if TYPE_CHECKING:
|
|
from .wrappers.response import Response # noqa: F401
|
|
|
|
|
|
def redirect(location: str, status_code: int=302) -> 'Response':
|
|
body = f"""
|
|
<!doctype html>
|
|
<title>Redirect</title>
|
|
<h1>Redirect</h1>
|
|
You should be redirected to <a href="{location}">{location}</a>, if not please click the link
|
|
"""
|
|
|
|
return current_app.response_class(
|
|
body, status=status_code, headers={'Location': location},
|
|
)
|
|
|
|
|
|
def create_cookie(
|
|
key: str,
|
|
value: str='',
|
|
max_age: Optional[Union[int, timedelta]]=None,
|
|
expires: Optional[Union[int, float, datetime]]=None,
|
|
path: str='/',
|
|
domain: Optional[str]=None,
|
|
secure: bool=False,
|
|
httponly: bool=False,
|
|
) -> SimpleCookie:
|
|
"""Create a Cookie given the options set
|
|
|
|
The arguments are the standard cookie morsels and this is a
|
|
wrapper around the stdlib SimpleCookie code.
|
|
"""
|
|
cookie = SimpleCookie()
|
|
cookie[key] = value
|
|
cookie[key]['path'] = path
|
|
cookie[key]['httponly'] = httponly # type: ignore
|
|
cookie[key]['secure'] = secure # type: ignore
|
|
if isinstance(max_age, timedelta):
|
|
cookie[key]['max-age'] = f"{max_age.total_seconds():d}"
|
|
if isinstance(max_age, int):
|
|
cookie[key]['max-age'] = str(max_age)
|
|
if expires is not None and isinstance(expires, (int, float)):
|
|
cookie[key]['expires'] = format_date_time(int(expires))
|
|
elif expires is not None and isinstance(expires, datetime):
|
|
cookie[key]['expires'] = format_date_time(expires.replace(tzinfo=timezone.utc).timestamp())
|
|
if domain is not None:
|
|
cookie[key]['domain'] = domain
|
|
return cookie
|
|
|
|
|
|
def ensure_coroutine(func: Callable) -> Callable:
|
|
if asyncio.iscoroutinefunction(func):
|
|
return func
|
|
else:
|
|
async_func = asyncio.coroutine(func)
|
|
async_func._quart_async_wrapper = True # type: ignore
|
|
return async_func
|
|
|
|
|
|
def file_path_to_path(*paths: FilePath) -> Path:
|
|
# Flask supports bytes paths
|
|
safe_paths: List[Union[str, PathLike]] = []
|
|
for path in paths:
|
|
if isinstance(path, bytes):
|
|
safe_paths.append(path.decode())
|
|
else:
|
|
safe_paths.append(path)
|
|
return Path(*safe_paths)
|