first commit
This commit is contained in:
16
mdrsclient/models/__init__.py
Normal file
16
mdrsclient/models/__init__.py
Normal file
@ -0,0 +1,16 @@
|
||||
from mdrsclient.models.error import DRFStandardizedErrors
|
||||
from mdrsclient.models.file import File
|
||||
from mdrsclient.models.folder import Folder, FolderSimple
|
||||
from mdrsclient.models.laboratory import Laboratories, Laboratory
|
||||
from mdrsclient.models.user import Token, User
|
||||
|
||||
__all__ = [
|
||||
"DRFStandardizedErrors",
|
||||
"File",
|
||||
"Folder",
|
||||
"FolderSimple",
|
||||
"Laboratories",
|
||||
"Laboratory",
|
||||
"Token",
|
||||
"User",
|
||||
]
|
14
mdrsclient/models/error.py
Normal file
14
mdrsclient/models/error.py
Normal file
@ -0,0 +1,14 @@
|
||||
from pydantic.dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class DRFStandardizedError:
|
||||
code: str
|
||||
detail: str
|
||||
attr: str | None
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class DRFStandardizedErrors:
|
||||
type: str
|
||||
errors: list[DRFStandardizedError]
|
25
mdrsclient/models/file.py
Normal file
25
mdrsclient/models/file.py
Normal file
@ -0,0 +1,25 @@
|
||||
from pydantic.dataclasses import dataclass
|
||||
|
||||
from mdrsclient.models.utils import iso8601_to_user_friendly
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class File:
|
||||
id: str
|
||||
name: str
|
||||
type: str
|
||||
size: int
|
||||
thumbnail: str | None
|
||||
description: str
|
||||
metadata: dict
|
||||
download_url: str
|
||||
created_at: str
|
||||
updated_at: str
|
||||
|
||||
@property
|
||||
def created_at_name(self) -> str:
|
||||
return iso8601_to_user_friendly(self.created_at)
|
||||
|
||||
@property
|
||||
def updated_at_name(self) -> str:
|
||||
return iso8601_to_user_friendly(self.updated_at)
|
58
mdrsclient/models/folder.py
Normal file
58
mdrsclient/models/folder.py
Normal file
@ -0,0 +1,58 @@
|
||||
from typing import Final
|
||||
|
||||
from pydantic.dataclasses import dataclass
|
||||
|
||||
from mdrsclient.models import File
|
||||
from mdrsclient.models.utils import iso8601_to_user_friendly
|
||||
|
||||
ACCESS_LEVEL_NAMES: Final[dict[int, str]] = {
|
||||
-1: "Storage",
|
||||
0: "Private",
|
||||
1: "CBS Open",
|
||||
2: "PW Open",
|
||||
3: "Public",
|
||||
}
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class FolderSimple:
|
||||
id: str
|
||||
pid: str | None
|
||||
name: str
|
||||
access_level: int
|
||||
lock: bool
|
||||
lab_id: int
|
||||
description: str
|
||||
created_at: str
|
||||
updated_at: str
|
||||
restrict_opened_at: str | None
|
||||
|
||||
@property
|
||||
def access_level_name(self) -> str:
|
||||
return ACCESS_LEVEL_NAMES[self.access_level]
|
||||
|
||||
@property
|
||||
def lock_name(self) -> str:
|
||||
return "locked" if self.lock else "unlocked"
|
||||
|
||||
@property
|
||||
def created_at_name(self) -> str:
|
||||
return iso8601_to_user_friendly(self.created_at)
|
||||
|
||||
@property
|
||||
def updated_at_name(self) -> str:
|
||||
return iso8601_to_user_friendly(self.updated_at)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Folder(FolderSimple):
|
||||
metadata: list[dict]
|
||||
sub_folders: list[FolderSimple]
|
||||
files: list[File]
|
||||
path: str
|
||||
|
||||
def find_sub_folder(self, name: str) -> FolderSimple | None:
|
||||
return next((x for x in self.sub_folders if x.name == name), None)
|
||||
|
||||
def find_file(self, name: str) -> File | None:
|
||||
return next((x for x in self.files if x.name == name), None)
|
34
mdrsclient/models/laboratory.py
Normal file
34
mdrsclient/models/laboratory.py
Normal file
@ -0,0 +1,34 @@
|
||||
from typing import Generator
|
||||
|
||||
from pydantic.dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Laboratory:
|
||||
id: int
|
||||
name: str
|
||||
pi_name: str
|
||||
full_name: str
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Laboratories:
|
||||
items: list[Laboratory]
|
||||
|
||||
def __iter__(self) -> Generator[Laboratory, None, None]:
|
||||
yield from self.items
|
||||
|
||||
def empty(self) -> bool:
|
||||
return len(self.items) == 0
|
||||
|
||||
def clear(self) -> None:
|
||||
self.items.clear()
|
||||
|
||||
def append(self, item: Laboratory) -> None:
|
||||
self.items.append(item)
|
||||
|
||||
def find_by_id(self, id: int) -> Laboratory | None:
|
||||
return next((x for x in self.items if x.id == id), None)
|
||||
|
||||
def find_by_name(self, name: str) -> Laboratory | None:
|
||||
return next((x for x in self.items if x.name == name), None)
|
50
mdrsclient/models/user.py
Normal file
50
mdrsclient/models/user.py
Normal file
@ -0,0 +1,50 @@
|
||||
import time
|
||||
|
||||
import jwt
|
||||
from pydantic import parse_obj_as
|
||||
from pydantic.dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class DecodedJWT:
|
||||
token_type: str
|
||||
exp: int
|
||||
iat: int
|
||||
jti: str
|
||||
user_id: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Token:
|
||||
access: str
|
||||
refresh: str
|
||||
|
||||
@property
|
||||
def user_id(self) -> int:
|
||||
access_decoded = self.__decode(self.access)
|
||||
return access_decoded.user_id
|
||||
|
||||
@property
|
||||
def is_expired(self) -> bool:
|
||||
now = int(time.time()) + 10
|
||||
refresh_decoded = self.__decode(self.refresh)
|
||||
return now > refresh_decoded.exp
|
||||
|
||||
@property
|
||||
def is_refresh_required(self) -> bool:
|
||||
now = int(time.time()) + 10
|
||||
access_decoded = self.__decode(self.access)
|
||||
refresh_decoded = self.__decode(self.refresh)
|
||||
return now > access_decoded.exp and now < refresh_decoded.exp
|
||||
|
||||
def __decode(self, token: str) -> DecodedJWT:
|
||||
data = jwt.decode(token, options={"verify_signature": False})
|
||||
return parse_obj_as(DecodedJWT, data)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class User:
|
||||
id: int
|
||||
username: str
|
||||
laboratory_id: int
|
||||
laboratory: str
|
5
mdrsclient/models/utils.py
Normal file
5
mdrsclient/models/utils.py
Normal file
@ -0,0 +1,5 @@
|
||||
import datetime
|
||||
|
||||
|
||||
def iso8601_to_user_friendly(text: str) -> str:
|
||||
return datetime.datetime.fromisoformat(text).strftime("%Y/%m/%d %H:%M:%S")
|
Reference in New Issue
Block a user