updated auth token handling using new users api.

This commit is contained in:
Yoshihiro OKUMURA 2023-12-07 14:46:57 +09:00
parent ac34a26b02
commit f10b42a1f2
Signed by: orrisroot
GPG Key ID: 470AA444C92904B2
9 changed files with 73 additions and 37 deletions

View File

@ -1,10 +1,15 @@
{ {
"version": "0.2", "version": "0.2",
"language": "en,en-gb", "language": "en,en-gb",
"ignoreWords": ["getframe", "pydantic", "UNLCK"], "ignoreWords": ["getframe", "pycache", "pydantic", "UNLCK"],
"words": ["chacl", "mdrs", "mdrsclient", "neurodata", "Neuroinformatics", "RIKEN"], "words": [
"ignorePaths": [ "chacl",
".env", "kikan",
"__pycache__" "mdrs",
] "mdrsclient",
"neurodata",
"Neuroinformatics",
"RIKEN"
],
"ignorePaths": [".env", "__pycache__"]
} }

View File

@ -1 +1 @@
1.2.0 1.3.0

View File

@ -1,11 +1,11 @@
from mdrsclient.api.file import FileApi from mdrsclient.api.file import FileApi
from mdrsclient.api.folder import FolderApi from mdrsclient.api.folder import FolderApi
from mdrsclient.api.laboratory import LaboratoryApi from mdrsclient.api.laboratory import LaboratoryApi
from mdrsclient.api.user import UserApi from mdrsclient.api.users import UsersApi
__all__ = [ __all__ = [
"FileApi", "FileApi",
"FolderApi", "FolderApi",
"LaboratoryApi", "LaboratoryApi",
"UserApi", "UsersApi",
] ]

View File

@ -16,27 +16,55 @@ class UserAuthResponse(Token):
laboratories: list[Laboratory] = field(default_factory=list) laboratories: list[Laboratory] = field(default_factory=list)
class UserApi(BaseApi): @dataclass(frozen=True)
class UsersCurrentResponseLaboratory:
id: int
name: str
role: int
@dataclass(frozen=True)
class UsersCurrentResponse:
id: int
username: str
full_name: str
email: str
laboratories: list[UsersCurrentResponseLaboratory]
is_staff: bool
is_active: bool
is_superuser: bool
is_reviewer: bool
last_login: str # ISO8601
date_joined: str # ISO8601
class UsersApi(BaseApi):
ENTRYPOINT: Final[str] = "v2/" ENTRYPOINT: Final[str] = "v2/"
def auth(self, username: str, password: str) -> tuple[User, Token]: def current(self) -> User:
# print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name) # print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name)
url = self.ENTRYPOINT + "auth/" url = self.ENTRYPOINT + "users/current/"
response = self.connection.get(url)
self._raise_response_error(response)
obj = TypeAdapter(UsersCurrentResponse).validate_python(response.json())
laboratory_ids = list(map(lambda x: x.id, obj.laboratories))
user = User(id=obj.id, username=obj.username, laboratory_ids=laboratory_ids, is_reviewer=obj.is_reviewer)
return user
def token(self, username: str, password: str) -> Token:
# print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name)
url = self.ENTRYPOINT + "users/token/"
data: dict[str, str | int] = {"username": username, "password": password} data: dict[str, str | int] = {"username": username, "password": password}
response = self.connection.post(url, data=data) response = self.connection.post(url, data=data)
if response.status_code == requests.codes.unauthorized: if response.status_code == requests.codes.unauthorized:
raise UnauthorizedException("Invalid username or password.") raise UnauthorizedException("Invalid username or password.")
self._raise_response_error(response) self._raise_response_error(response)
obj = TypeAdapter(UserAuthResponse).validate_python(response.json()) token = TypeAdapter(Token).validate_python(response.json())
token = Token(access=obj.access, refresh=obj.refresh) return token
laboratory_ids = list(map(lambda x: x.id, obj.laboratories))
is_reviewer = obj.is_reviewer if obj.is_reviewer is not None else False
user = User(id=token.user_id, username=username, laboratory_ids=laboratory_ids, is_reviewer=is_reviewer)
return (user, token)
def refresh(self, token: Token) -> Token: def tokenRefresh(self, token: Token) -> Token:
# print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name) # print(self.__class__.__name__ + "::" + sys._getframe().f_code.co_name)
url = self.ENTRYPOINT + "refresh/" url = self.ENTRYPOINT + "users/token/refresh/"
data: dict[str, str | int] = {"refresh": token.refresh} data: dict[str, str | int] = {"refresh": token.refresh}
response = self.connection.post(url, data=data) response = self.connection.post(url, data=data)
if response.status_code == requests.codes.unauthorized: if response.status_code == requests.codes.unauthorized:

View File

@ -1,4 +1,4 @@
from mdrsclient.api.user import UserApi from mdrsclient.api.users import UsersApi
from mdrsclient.connection import MDRSConnection from mdrsclient.connection import MDRSConnection
from mdrsclient.exceptions import UnauthorizedException from mdrsclient.exceptions import UnauthorizedException
@ -8,9 +8,9 @@ def token_check(connection: MDRSConnection) -> None:
connection.lock.acquire() connection.lock.acquire()
if connection.token is not None: if connection.token is not None:
if connection.token.is_refresh_required: if connection.token.is_refresh_required:
user_api = UserApi(connection) user_api = UsersApi(connection)
try: try:
connection.token = user_api.refresh(connection.token) connection.token = user_api.tokenRefresh(connection.token)
except UnauthorizedException: except UnauthorizedException:
connection.logout() connection.logout()
elif connection.token.is_expired: elif connection.token.is_expired:

View File

@ -2,7 +2,7 @@ import getpass
from argparse import Namespace from argparse import Namespace
from typing import Any from typing import Any
from mdrsclient.api import UserApi from mdrsclient.api import UsersApi
from mdrsclient.commands.base import BaseCommand from mdrsclient.commands.base import BaseCommand
from mdrsclient.config import ConfigFile from mdrsclient.config import ConfigFile
from mdrsclient.connection import MDRSConnection from mdrsclient.connection import MDRSConnection
@ -30,8 +30,10 @@ class LoginCommand(BaseCommand):
if config.url is None: if config.url is None:
raise MissingConfigurationException(f"Remote host `{remote}` is not found.") raise MissingConfigurationException(f"Remote host `{remote}` is not found.")
connection = MDRSConnection(config.remote, config.url) connection = MDRSConnection(config.remote, config.url)
user_api = UserApi(connection) user_api = UsersApi(connection)
(user, token) = user_api.auth(username, password) token = user_api.token(username, password)
print("Login Successful")
connection.user = user
connection.token = token connection.token = token
user = user_api.current()
connection.user = user
print(user)
print("Login Successful")

View File

@ -90,7 +90,7 @@ class LsCommand(BaseCommand):
for key in label.keys(): for key in label.keys():
length[key] = len(label[key]) if not context.is_quick else 0 length[key] = len(label[key]) if not context.is_quick else 0
for sub_folder in folder.sub_folders: for sub_folder in folder.sub_folders:
sub_laboratory = context.connection.laboratories.find_by_id(sub_folder.lab_id) sub_laboratory = context.connection.laboratories.find_by_id(sub_folder.laboratory_id)
sub_laboratory_name = sub_laboratory.name if sub_laboratory is not None else "(invalid)" sub_laboratory_name = sub_laboratory.name if sub_laboratory is not None else "(invalid)"
length["acl"] = max(length["acl"], len(sub_folder.access_level_name)) length["acl"] = max(length["acl"], len(sub_folder.access_level_name))
length["laboratory"] = max(length["laboratory"], len(sub_laboratory_name)) length["laboratory"] = max(length["laboratory"], len(sub_laboratory_name))
@ -118,7 +118,7 @@ class LsCommand(BaseCommand):
print("-" * len(header.expandtabs())) print("-" * len(header.expandtabs()))
for sub_folder in sorted(folder.sub_folders, key=lambda x: x.name): for sub_folder in sorted(folder.sub_folders, key=lambda x: x.name):
sub_laboratory_name = cls._laboratory_name(context, sub_folder.lab_id) sub_laboratory_name = cls._laboratory_name(context, sub_folder.laboratory_id)
print( print(
f"{'[d]':{length['type']}}\t{sub_folder.access_level_name:{length['acl']}}\t" f"{'[d]':{length['type']}}\t{sub_folder.access_level_name:{length['acl']}}\t"
f"{sub_laboratory_name:{length['laboratory']}}\t{sub_folder.lock_name:{length['size']}}\t" f"{sub_laboratory_name:{length['laboratory']}}\t{sub_folder.lock_name:{length['size']}}\t"
@ -151,13 +151,14 @@ class LsCommand(BaseCommand):
"name": folder.name, "name": folder.name,
"access_level": folder.access_level_name, "access_level": folder.access_level_name,
"lock": folder.lock, "lock": folder.lock,
"laboratory": cls._laboratory_name(context, folder.lab_id), "laboratory": cls._laboratory_name(context, folder.laboratory_id),
"description": folder.description, "description": folder.description,
"created_at": folder.created_at, "created_at": folder.created_at,
"updated_at": folder.updated_at, "updated_at": folder.updated_at,
} }
if isinstance(folder, Folder): if isinstance(folder, Folder):
folder_api = FolderApi(context.connection) folder_api = FolderApi(context.connection)
print(folder.name)
data["metadata"] = folder_api.metadata(folder.id) data["metadata"] = folder_api.metadata(folder.id)
if context.is_recursive: if context.is_recursive:
sub_folders: list[dict[str, Any]] = [] sub_folders: list[dict[str, Any]] = []

View File

@ -49,7 +49,7 @@ class FolderSimple:
name: str name: str
access_level: int access_level: int
lock: bool lock: bool
lab_id: int laboratory_id: int
description: str description: str
created_at: str created_at: str
updated_at: str updated_at: str

View File

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "mdrs-client-python" name = "mdrs-client-python"
version = "1.2.0" version = "1.3.0"
description = "The mdrs-client-python is python library and a command-line client for up- and downloading files to and from MDRS based repository." description = "The mdrs-client-python is python library and a command-line client for up- and downloading files to and from MDRS based repository."
authors = ["Yoshihiro OKUMURA <yoshihiro.okumura@riken.jp>"] authors = ["Yoshihiro OKUMURA <yoshihiro.okumura@riken.jp>"]
license = "MIT" license = "MIT"
@ -24,17 +24,17 @@ packages = [
python = "^3.10" python = "^3.10"
requests = "^2.31.0" requests = "^2.31.0"
python-dotenv = "^1.0.0" python-dotenv = "^1.0.0"
pydantic = "^2.4.2" pydantic = "^2.5.2"
pydantic-settings = "^2.0.3" pydantic-settings = "^2.1.0"
PyJWT = "^2.8.0" PyJWT = "^2.8.0"
validators = "^0.22.0" validators = "^0.22.0"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
black = "^23.9.1" black = "^23.11.0"
flake8 = "^6.1.0" flake8 = "^6.1.0"
Flake8-pyproject = "^1.2.3" Flake8-pyproject = "^1.2.3"
isort = "^5.12.0" isort = "^5.12.0"
pyright = "^1.1.329" pyright = "^1.1.339"
[tool.poetry.scripts] [tool.poetry.scripts]
mdrs = 'mdrsclient.__main__:main' mdrs = 'mdrsclient.__main__:main'