Changed code to support older Python versions
This commit is contained in:
parent
eb92d2d36f
commit
582458cdd0
5027 changed files with 794942 additions and 4 deletions
|
|
@ -0,0 +1,125 @@
|
|||
import logging
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
import typer
|
||||
from pydantic import BaseModel
|
||||
|
||||
from fastapi_cloud_cli.config import Settings
|
||||
from fastapi_cloud_cli.utils.api import APIClient
|
||||
from fastapi_cloud_cli.utils.auth import (
|
||||
AuthConfig,
|
||||
get_auth_token,
|
||||
is_logged_in,
|
||||
is_token_expired,
|
||||
write_auth_config,
|
||||
)
|
||||
from fastapi_cloud_cli.utils.cli import get_rich_toolkit, handle_http_errors
|
||||
from fastapi_cloud_cli.utils.pydantic_compat import model_validate_json
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AuthorizationData(BaseModel):
|
||||
user_code: str
|
||||
device_code: str
|
||||
verification_uri: str
|
||||
verification_uri_complete: str
|
||||
interval: int = 5
|
||||
|
||||
|
||||
class TokenResponse(BaseModel):
|
||||
access_token: str
|
||||
|
||||
|
||||
def _start_device_authorization(
|
||||
client: httpx.Client,
|
||||
) -> AuthorizationData:
|
||||
settings = Settings.get()
|
||||
|
||||
response = client.post(
|
||||
"/login/device/authorization", data={"client_id": settings.client_id}
|
||||
)
|
||||
|
||||
response.raise_for_status()
|
||||
|
||||
return model_validate_json(AuthorizationData, response.text)
|
||||
|
||||
|
||||
def _fetch_access_token(client: httpx.Client, device_code: str, interval: int) -> str:
|
||||
settings = Settings.get()
|
||||
|
||||
while True:
|
||||
response = client.post(
|
||||
"/login/device/token",
|
||||
data={
|
||||
"device_code": device_code,
|
||||
"client_id": settings.client_id,
|
||||
"grant_type": "urn:ietf:params:oauth:grant-type:device_code",
|
||||
},
|
||||
)
|
||||
|
||||
if response.status_code not in (200, 400):
|
||||
response.raise_for_status()
|
||||
|
||||
if response.status_code == 400:
|
||||
data = response.json()
|
||||
|
||||
if data.get("error") != "authorization_pending":
|
||||
response.raise_for_status()
|
||||
|
||||
if response.status_code == 200:
|
||||
break
|
||||
|
||||
time.sleep(interval)
|
||||
|
||||
response_data = model_validate_json(TokenResponse, response.text)
|
||||
|
||||
return response_data.access_token
|
||||
|
||||
|
||||
def login() -> Any:
|
||||
"""
|
||||
Login to FastAPI Cloud. 🚀
|
||||
"""
|
||||
token = get_auth_token()
|
||||
if token is not None and is_token_expired(token):
|
||||
with get_rich_toolkit(minimal=True) as toolkit:
|
||||
toolkit.print("Your session has expired. Logging in again...")
|
||||
toolkit.print_line()
|
||||
|
||||
if is_logged_in():
|
||||
with get_rich_toolkit(minimal=True) as toolkit:
|
||||
toolkit.print("You are already logged in.")
|
||||
toolkit.print(
|
||||
"Run [bold]fastapi cloud logout[/bold] first if you want to switch accounts."
|
||||
)
|
||||
return
|
||||
|
||||
with get_rich_toolkit() as toolkit, APIClient() as client:
|
||||
toolkit.print_title("Login to FastAPI Cloud", tag="FastAPI")
|
||||
|
||||
toolkit.print_line()
|
||||
|
||||
with toolkit.progress("Starting authorization") as progress:
|
||||
with handle_http_errors(progress):
|
||||
authorization_data = _start_device_authorization(client)
|
||||
|
||||
url = authorization_data.verification_uri_complete
|
||||
|
||||
progress.log(f"Opening [link={url}]{url}[/link]")
|
||||
|
||||
toolkit.print_line()
|
||||
|
||||
with toolkit.progress("Waiting for user to authorize...") as progress:
|
||||
typer.launch(url)
|
||||
|
||||
with handle_http_errors(progress):
|
||||
access_token = _fetch_access_token(
|
||||
client, authorization_data.device_code, authorization_data.interval
|
||||
)
|
||||
|
||||
write_auth_config(AuthConfig(access_token=access_token))
|
||||
|
||||
progress.log("Now you are logged in! 🚀")
|
||||
Loading…
Add table
Add a link
Reference in a new issue