adding commit
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -154,3 +154,6 @@ out/
|
||||
|
||||
# nix
|
||||
result
|
||||
|
||||
# for local dev might dump cred stuff here
|
||||
cred/
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
[general_config]
|
||||
backend_base_url = "http://localhost:8080"
|
||||
backend_user = "test@example.com"
|
||||
backend_pw = "test"
|
||||
|
||||
12
scripts/simple_create_user.sh
Executable file
12
scripts/simple_create_user.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuox pipefail
|
||||
|
||||
banner() {
|
||||
echo "========================================================"
|
||||
echo " $*"
|
||||
echo "========================================================"
|
||||
}
|
||||
|
||||
# utility script for easy testing
|
||||
|
||||
uv run taco register --display-name "Display Test" --email "test@example.com" --password "test"
|
||||
@@ -22,7 +22,6 @@ def parse_args():
|
||||
trygo_py_cliclient.cli.register.setup_parser(subparsers)
|
||||
trygo_py_cliclient.cli.login.setup_parser(subparsers)
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
@@ -38,4 +37,6 @@ def main():
|
||||
_logger.info(f"Got args {args=}")
|
||||
_logger.info(f"Loaded config {config=}")
|
||||
|
||||
args.func(args)
|
||||
# TODO is there a clean way to hang on to a session for a bit when the cli command has run?
|
||||
# i guess realistically we don't want that
|
||||
args.func(config, args)
|
||||
|
||||
@@ -2,6 +2,7 @@ import argparse
|
||||
import logging
|
||||
import typing
|
||||
|
||||
import trygo_py_cliclient.config
|
||||
import trygo_py_cliclient.client
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
@@ -16,13 +17,13 @@ else:
|
||||
def setup_parser(subparsers: _SubparserType) -> None:
|
||||
parser = subparsers.add_parser("login")
|
||||
|
||||
parser.add_argument("--email", type=str, help="config file location", default="")
|
||||
parser.add_argument("--password", type=str, help="config file location", default="")
|
||||
parser.add_argument("--email", type=str, help="The email to log in with ", default="")
|
||||
parser.add_argument("--password", type=str, help="Password", default="")
|
||||
parser.set_defaults(func=run)
|
||||
|
||||
def run(args):
|
||||
|
||||
clnt = trygo_py_cliclient.client.TryGoAPIClient("http://localhost:8080/")
|
||||
|
||||
|
||||
def run(config: trygo_py_cliclient.config.Config, args):
|
||||
clnt = trygo_py_cliclient.client.BackendService(config)
|
||||
|
||||
response = clnt.login(args.email, args.password)
|
||||
_logger.info(response)
|
||||
|
||||
@@ -23,8 +23,8 @@ def setup_parser(subparsers: _SubparserType) -> None:
|
||||
parser.add_argument("--password", type=str, help="config file location", default="")
|
||||
parser.set_defaults(func=run)
|
||||
|
||||
|
||||
def run(args):
|
||||
|
||||
clnt = trygo_py_cliclient.client.TryGoAPIClient("http://localhost:8080/")
|
||||
response = clnt.register(args.email, args.password, args.display_name)
|
||||
_logger.info(response)
|
||||
|
||||
@@ -2,8 +2,10 @@ import requests
|
||||
import logging
|
||||
from typing import Optional, Dict, Any
|
||||
from dataclasses import asdict
|
||||
from pathlib import Path
|
||||
|
||||
from trygo_py_cliclient.models import User, RegisterRequest, LoginRequest, AuthResponse
|
||||
from trygo_py_cliclient.models import RegisterRequest, LoginRequest, AuthResponse
|
||||
from trygo_py_cliclient.config import Config
|
||||
from trygo_py_cliclient.exceptions import (
|
||||
TryGoAPIError,
|
||||
AuthenticationError,
|
||||
@@ -15,17 +17,14 @@ from trygo_py_cliclient.exceptions import (
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TryGoAPIClient:
|
||||
"""HTTP client for TryGo webapp REST API"""
|
||||
|
||||
def __init__(self, base_url: str, timeout: int = 30):
|
||||
self.base_url = base_url.rstrip("/")
|
||||
self.timeout = timeout
|
||||
class BackendService:
|
||||
def __init__(self, config: Config):
|
||||
self.base_url = config.general_config.backend_base_url.rstrip("/")
|
||||
self.timeout = 30
|
||||
self.session = requests.Session()
|
||||
self.session.headers.update(
|
||||
{"Content-Type": "application/json", "User-Agent": "trygo-py-client/0.1.0"}
|
||||
)
|
||||
self._auth_token: Optional[str] = None
|
||||
|
||||
def _make_request(
|
||||
self, method: str, endpoint: str, data: Optional[Dict[str, Any]] = None
|
||||
@@ -82,6 +81,7 @@ class TryGoAPIClient:
|
||||
except ValueError as e:
|
||||
raise TryGoAPIError(f"Invalid JSON response: {e}")
|
||||
|
||||
# claude really fucked this
|
||||
except requests.exceptions.Timeout:
|
||||
raise NetworkError("Request timeout")
|
||||
except requests.exceptions.ConnectionError:
|
||||
@@ -92,18 +92,6 @@ class TryGoAPIClient:
|
||||
def register(self, email: str, password: str, display_name: str) -> AuthResponse:
|
||||
"""
|
||||
Register a new user account
|
||||
|
||||
Args:
|
||||
email: User's email address
|
||||
password: User's password
|
||||
display_name: User's display name
|
||||
|
||||
Returns:
|
||||
AuthResponse with registration result
|
||||
|
||||
Raises:
|
||||
ValidationError: If registration data is invalid
|
||||
TryGoAPIError: If registration fails
|
||||
"""
|
||||
request_data = RegisterRequest(
|
||||
email=email, password=password, display_name=display_name
|
||||
@@ -117,42 +105,16 @@ class TryGoAPIClient:
|
||||
|
||||
# Parse response and create AuthResponse
|
||||
auth_response = AuthResponse(
|
||||
success=response_data.get("success", False),
|
||||
message=response_data.get("message", ""),
|
||||
token=response_data.get("token"),
|
||||
user=None,
|
||||
email=response_data.get("email", ""),
|
||||
id=response_data.get("id", ""),
|
||||
)
|
||||
|
||||
# Parse user data if present
|
||||
if "user" in response_data and response_data["user"]:
|
||||
user_data = response_data["user"]
|
||||
auth_response.user = User(
|
||||
email=user_data.get("email", ""),
|
||||
password="", # Never store password in response
|
||||
display_name=user_data.get("display_name", ""),
|
||||
id=user_data.get("id"),
|
||||
)
|
||||
|
||||
# Store auth token on successful registration
|
||||
if auth_response.success and auth_response.token:
|
||||
self.set_auth_token(auth_response.token)
|
||||
|
||||
return auth_response
|
||||
|
||||
def login(self, email: str, password: str) -> AuthResponse:
|
||||
def login(self, email: str, password: str) -> str:
|
||||
"""
|
||||
Authenticate user and get auth token
|
||||
|
||||
Args:
|
||||
email: User's email address
|
||||
password: User's password
|
||||
|
||||
Returns:
|
||||
AuthResponse with login result and token
|
||||
|
||||
Raises:
|
||||
AuthenticationError: If login credentials are invalid
|
||||
TryGoAPIError: If login fails
|
||||
"""
|
||||
request_data = LoginRequest(email=email, password=password)
|
||||
|
||||
@@ -162,39 +124,10 @@ class TryGoAPIClient:
|
||||
_logger.info(response_data)
|
||||
|
||||
# Parse response and create AuthResponse
|
||||
auth_response = AuthResponse(
|
||||
success=response_data.get("success", False),
|
||||
message=response_data.get("message", ""),
|
||||
token=response_data.get("token"),
|
||||
user=None,
|
||||
)
|
||||
token = response_data.get("token", "")
|
||||
self._store_credential(token)
|
||||
|
||||
# Parse user data if present
|
||||
if "user" in response_data and response_data["user"]:
|
||||
user_data = response_data["user"]
|
||||
auth_response.user = User(
|
||||
email=user_data.get("email", ""),
|
||||
password="", # Never store password in response
|
||||
display_name=user_data.get("display_name", ""),
|
||||
id=user_data.get("id"),
|
||||
)
|
||||
|
||||
# Store auth token on successful login
|
||||
if auth_response.success and auth_response.token:
|
||||
self.set_auth_token(auth_response.token)
|
||||
|
||||
return auth_response
|
||||
|
||||
def set_auth_token(self, token: str) -> None:
|
||||
"""
|
||||
Set authentication token for subsequent requests
|
||||
|
||||
Args:
|
||||
token: JWT or session token for authentication
|
||||
"""
|
||||
self._auth_token = token
|
||||
self.session.headers["Authorization"] = f"Bearer {token}"
|
||||
_logger.debug("Authentication token set")
|
||||
return token
|
||||
|
||||
def logout(self) -> None:
|
||||
"""
|
||||
@@ -205,16 +138,12 @@ class TryGoAPIClient:
|
||||
_logger.info("Logging out user")
|
||||
|
||||
# Try to call logout endpoint if we have a token
|
||||
if self._auth_token:
|
||||
try:
|
||||
self._make_request("POST", "/auth/logout")
|
||||
_logger.debug("Server logout successful")
|
||||
except Exception as e:
|
||||
_logger.warning(f"Server logout failed (continuing anyway): {e}")
|
||||
|
||||
# Clear local auth state
|
||||
self._auth_token = None
|
||||
if "Authorization" in self.session.headers:
|
||||
del self.session.headers["Authorization"]
|
||||
|
||||
_logger.debug("Local authentication cleared")
|
||||
|
||||
def _store_credential(self, token: str) -> None:
|
||||
|
||||
token_path = Path("cred/token")
|
||||
token_path.parent.mkdir(parents=True,exist_ok=True)
|
||||
with token_path.open(mode="w") as tokenf:
|
||||
tokenf.write(token)
|
||||
|
||||
@@ -8,6 +8,10 @@ class GeneralConfig:
|
||||
log_pattern: str = "%(asctime)s | %(process)d | %(levelname)-7s | %(name)s:%(lineno)d | %(message)s"
|
||||
log_file: Optional[str] = None
|
||||
log_stream: bool = True
|
||||
backend_base_url: str = ""
|
||||
# obviously bad, but for now just keep it
|
||||
backend_user: str = ""
|
||||
backend_pw: str = ""
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
||||
@@ -42,31 +42,7 @@ def serialize_config(config_dict: dict) -> Config:
|
||||
Converts a dictionary to a Config object
|
||||
|
||||
Makes assumptions about structure of the config_dict, so validation should happen here too if needed.
|
||||
|
||||
:param config_dict: dictionary containing config values
|
||||
:return: Config object
|
||||
"""
|
||||
# generation_config = GenerationConfig(**config_dict["generation_config"])
|
||||
|
||||
# general_config_dict = config_dict["general_config"]
|
||||
# general_config = GeneralConfig(
|
||||
# root_directory=general_config_dict["root_directory"],
|
||||
# out_dir_name=general_config_dict["out_dir_name"],
|
||||
# dots_json_name=general_config_dict["dots_json_name"],
|
||||
# mega_merged_name=general_config_dict["mega_merged_name"],
|
||||
# mega_merged_inferenced_name=general_config_dict["mega_merged_inferenced_name"],
|
||||
# skip_to_stage=general_config_dict["skip_to_stage"],
|
||||
# measurement_type=MeasurementTypeEnum(general_config_dict["measurement_type"]),
|
||||
# indexes_json_name=general_config_dict["indexes_json_name"],
|
||||
# log_pattern=general_config_dict["log_pattern"],
|
||||
# )
|
||||
|
||||
# deepdog_config = DeepdogConfig(**config_dict["deepdog_config"])
|
||||
# config = Config(
|
||||
# generation_config=generation_config,
|
||||
# general_config=general_config,
|
||||
# deepdog_config=deepdog_config,
|
||||
# )
|
||||
config = dacite.from_dict(
|
||||
data_class=Config,
|
||||
data=config_dict,
|
||||
|
||||
@@ -33,7 +33,6 @@ class LoginRequest:
|
||||
class AuthResponse:
|
||||
"""Response from authentication endpoints"""
|
||||
|
||||
success: bool
|
||||
message: str
|
||||
user: Optional[User] = None
|
||||
token: Optional[str] = None
|
||||
email: Optional[str] = None
|
||||
id: Optional[str] = None
|
||||
|
||||
Reference in New Issue
Block a user