Files
specklepy/src/specklepy/core/api/credentials.py
T
Jedd Morgan 040a4e2553 fixed tests
2024-10-31 14:04:20 +00:00

178 lines
5.3 KiB
Python

import os
from pathlib import Path
from typing import List, Optional
from urllib.parse import urlparse
from pydantic import BaseModel, Field # pylint: disable=no-name-in-module
from specklepy.core.api.models import ServerInfo
from specklepy.core.helpers import speckle_path_provider
from specklepy.logging.exceptions import SpeckleException
from specklepy.transports.sqlite import SQLiteTransport
class UserInfo(BaseModel):
id: Optional[str] = None
name: Optional[str] = None
email: Optional[str] = None
company: Optional[str] = None
avatar: Optional[str] = None
class Account(BaseModel):
isDefault: bool = False
token: Optional[str] = None
refreshToken: Optional[str] = None
serverInfo: ServerInfo = Field(default_factory=ServerInfo)
userInfo: UserInfo = Field(default_factory=UserInfo)
id: Optional[str] = None
def __repr__(self) -> str:
return (
f"Account(email: {self.userInfo.email}, server: {self.serverInfo.url},"
f" isDefault: {self.isDefault})"
)
def __str__(self) -> str:
return self.__repr__()
@classmethod
def from_token(cls, token: str, server_url: str = None):
acct = cls(token=token)
acct.serverInfo.url = server_url
return acct
def get_local_accounts(base_path: Optional[str] = None) -> List[Account]:
"""Gets all the accounts present in this environment
Arguments:
base_path {str} -- custom base path if you are not using the system default
Returns:
List[Account] -- list of all local accounts or an empty list if
no accounts were found
"""
accounts: List[Account] = []
try:
account_storage = SQLiteTransport(scope="Accounts", base_path=base_path)
res = account_storage.get_all_objects()
account_storage.close()
if res:
accounts.extend(Account.model_validate_json(r[1]) for r in res)
except SpeckleException:
# cannot open SQLiteTransport, probably because of the lack
# of disk write permissions
pass
json_acct_files = []
json_path = str(speckle_path_provider.accounts_folder_path())
try:
os.makedirs(json_path, exist_ok=True)
json_acct_files.extend(
file for file in os.listdir(json_path) if file.endswith(".json")
)
except Exception:
# cannot find or get the json account paths
pass
if json_acct_files:
try:
accounts.extend(
Account.model_validate_json(Path(json_path, json_file).read_text())
# Account.parse_file(os.path.join(json_path, json_file))
for json_file in json_acct_files
)
except Exception as ex:
raise SpeckleException(
"Invalid json accounts could not be read. Please fix or remove them.",
ex,
) from ex
return accounts
def get_default_account(base_path: Optional[str] = None) -> Optional[Account]:
"""
Gets this environment's default account if any. If there is no default,
the first found will be returned and set as default.
Arguments:
base_path {str} -- custom base path if you are not using the system default
Returns:
Account -- the default account or None if no local accounts were found
"""
accounts = get_local_accounts(base_path=base_path)
if not accounts:
return None
default = next((acc for acc in accounts if acc.isDefault), None)
if not default:
default = accounts[0]
default.isDefault = True
# metrics.initialise_tracker(default)
return default
def get_account_from_token(token: str, server_url: str = None) -> Account:
"""Gets the local account for the token if it exists
Arguments:
token {str} -- the api token
Returns:
Account -- the local account with this token or a shell account containing
just the token and url if no local account is found
"""
accounts = get_local_accounts()
if not accounts:
return Account.from_token(token, server_url)
acct = next((acc for acc in accounts if acc.token == token), None)
if acct:
return acct
if server_url:
url = server_url.lower()
acct = next(
(acc for acc in accounts if url in acc.serverInfo.url.lower()), None
)
if acct:
return acct
return Account.from_token(token, server_url)
def get_accounts_for_server(host: str) -> List[Account]:
all_accounts = get_local_accounts()
filtered: List[Account] = []
for acc in all_accounts:
moved_from = (
acc.serverInfo.migration.movedFrom if acc.serverInfo.migration else None
)
if moved_from and host == urlparse(moved_from).netloc:
filtered.append(acc)
for acc in all_accounts:
if any([x for x in filtered if x.userInfo.id == acc.userInfo.id]):
continue
if host == urlparse(acc.serverInfo.url).netloc:
filtered.append(acc)
return filtered
class StreamWrapper:
def __init__(self, url: str = None) -> None:
raise SpeckleException(
message=(
"The StreamWrapper has moved as of v2.6.0! Please import from"
" specklepy.api.wrapper"
),
exception=DeprecationWarning(),
)