feat: add models and partially custom error messages
This commit is contained in:
268
itd/client.py
268
itd/client.py
@@ -1,3 +1,4 @@
|
||||
from uuid import UUID
|
||||
from _io import BufferedReader
|
||||
from typing import cast
|
||||
|
||||
@@ -14,7 +15,14 @@ from itd.routes.search import search
|
||||
from itd.routes.files import upload_file
|
||||
from itd.routes.auth import refresh_token, change_password, logout
|
||||
from itd.routes.verification import verificate, get_verification_status
|
||||
|
||||
from itd.models.clan import Clan
|
||||
from itd.models.user import User, UserProfileUpdate, UserPrivacy, UserFollower, UserWhoToFollow
|
||||
from itd.models.pagination import Pagination
|
||||
from itd.models.verification import Verification, VerificationStatus
|
||||
|
||||
from itd.request import set_cookies
|
||||
from itd.exceptions import NoCookie, NoAuthData, SamePassword, InvalidOldPassword, UserNotFound, InvalidProfileData, UserBanned, PendingRequestExists
|
||||
|
||||
|
||||
def refresh_on_error(func):
|
||||
@@ -39,79 +47,261 @@ class Client:
|
||||
set_cookies(self.cookies)
|
||||
self.refresh_auth()
|
||||
else:
|
||||
raise ValueError('Provide token or cookie')
|
||||
raise NoAuthData()
|
||||
|
||||
def refresh_auth(self):
|
||||
if self.cookies:
|
||||
self.token = refresh_token(self.cookies)
|
||||
return self.token
|
||||
else:
|
||||
print('no cookies')
|
||||
def refresh_auth(self) -> str:
|
||||
"""Обновить access token
|
||||
|
||||
@refresh_on_error
|
||||
def change_password(self, old: str, new: str):
|
||||
Raises:
|
||||
NoCookie: Нет cookie
|
||||
|
||||
Returns:
|
||||
str: Токен
|
||||
"""
|
||||
print('refresh token')
|
||||
if not self.cookies:
|
||||
print('no cookies')
|
||||
return
|
||||
return change_password(self.cookies, self.token, old, new)
|
||||
raise NoCookie()
|
||||
|
||||
res = refresh_token(self.cookies)
|
||||
res.raise_for_status()
|
||||
|
||||
self.token = res.json()['accessToken']
|
||||
return self.token
|
||||
|
||||
@refresh_on_error
|
||||
def logout(self):
|
||||
def change_password(self, old: str, new: str) -> dict:
|
||||
"""Смена пароля
|
||||
|
||||
Args:
|
||||
old (str): Страый пароль
|
||||
new (str): Новый пароль
|
||||
|
||||
Raises:
|
||||
NoCookie: Нет cookie
|
||||
SamePassword: Одинаковые пароли
|
||||
InvalidOldPassword: Старый пароль неверный
|
||||
|
||||
Returns:
|
||||
dict: Ответ API `{'message': 'Password changed successfully'}`
|
||||
"""
|
||||
if not self.cookies:
|
||||
print('no cookies')
|
||||
return
|
||||
return logout(self.cookies)
|
||||
raise NoCookie()
|
||||
|
||||
res = change_password(self.cookies, self.token, old, new)
|
||||
if res.json().get('error', {}).get('code') == 'SAME_PASSWORD':
|
||||
raise SamePassword()
|
||||
if res.json().get('error', {}).get('code') == 'INVALID_OLD_PASSWORD':
|
||||
raise InvalidOldPassword()
|
||||
res.raise_for_status()
|
||||
|
||||
return res.json()
|
||||
|
||||
@refresh_on_error
|
||||
def get_user(self, username: str) -> dict:
|
||||
return get_user(self.token, username)
|
||||
def logout(self) -> dict:
|
||||
"""Выход из аккаунта
|
||||
|
||||
Raises:
|
||||
NoCookie: Нет cookie
|
||||
|
||||
Returns:
|
||||
dict: Ответ API
|
||||
"""
|
||||
if not self.cookies:
|
||||
raise NoCookie()
|
||||
|
||||
res = logout(self.cookies)
|
||||
res.raise_for_status()
|
||||
|
||||
return res.json()
|
||||
|
||||
@refresh_on_error
|
||||
def get_me(self) -> dict:
|
||||
def get_user(self, username: str) -> User:
|
||||
"""Получить пользователя
|
||||
|
||||
Args:
|
||||
username (str): username или "me"
|
||||
|
||||
Raises:
|
||||
UserNotFound: Пользователь не найден
|
||||
UserBanned: Пользователь заблокирован
|
||||
|
||||
Returns:
|
||||
User: Пользователь
|
||||
"""
|
||||
res = get_user(self.token, username)
|
||||
if res.json().get('error', {}).get('code') == 'NOT_FOUND':
|
||||
raise UserNotFound()
|
||||
if res.json().get('error', {}).get('code') == 'USER_BLOCKED':
|
||||
raise UserBanned()
|
||||
res.raise_for_status()
|
||||
|
||||
return User.model_validate(res.json())
|
||||
|
||||
@refresh_on_error
|
||||
def get_me(self) -> User:
|
||||
"""Получить текущего пользователя (me)
|
||||
|
||||
Returns:
|
||||
User: Пользователь
|
||||
"""
|
||||
return self.get_user('me')
|
||||
|
||||
@refresh_on_error
|
||||
def update_profile(self, username: str | None = None, display_name: str | None = None, bio: str | None = None, banner_id: str | None = None) -> dict:
|
||||
return update_profile(self.token, bio, display_name, username, banner_id)
|
||||
def update_profile(self, username: str | None = None, display_name: str | None = None, bio: str | None = None, banner_id: UUID | None = None) -> UserProfileUpdate:
|
||||
"""Обновить профиль
|
||||
|
||||
Args:
|
||||
username (str | None, optional): username. Defaults to None.
|
||||
display_name (str | None, optional): Отображаемое имя. Defaults to None.
|
||||
bio (str | None, optional): Биография (о себе). Defaults to None.
|
||||
banner_id (UUID | None, optional): UUID баннера. Defaults to None.
|
||||
|
||||
Raises:
|
||||
InvalidProfileData: Неправильные данные (валидация не прошла)
|
||||
|
||||
Returns:
|
||||
UserProfileUpdate: Обновленный профиль
|
||||
"""
|
||||
res = update_profile(self.token, bio, display_name, username, banner_id)
|
||||
if res.status_code == 422 and 'found' in res.json():
|
||||
raise InvalidProfileData(*list(res.json()['found'].items())[0])
|
||||
res.raise_for_status()
|
||||
|
||||
return UserProfileUpdate.model_validate(res.json())
|
||||
|
||||
@refresh_on_error
|
||||
def update_privacy(self, wall_closed: bool = False, private: bool = False):
|
||||
return update_privacy(self.token, wall_closed, private)
|
||||
def update_privacy(self, wall_closed: bool = False, private: bool = False) -> UserPrivacy:
|
||||
"""Обновить настройки приватности
|
||||
|
||||
Args:
|
||||
wall_closed (bool, optional): Закрыть стену. Defaults to False.
|
||||
private (bool, optional): Приватность. На данный момент неизвестно, что делает этот параметр. Defaults to False.
|
||||
|
||||
Returns:
|
||||
UserPrivacy: Обновленные данные приватности
|
||||
"""
|
||||
res = update_privacy(self.token, wall_closed, private)
|
||||
res.raise_for_status()
|
||||
|
||||
return UserPrivacy.model_validate(res.json())
|
||||
|
||||
@refresh_on_error
|
||||
def follow(self, username: str) -> dict:
|
||||
return follow(self.token, username)
|
||||
def follow(self, username: str) -> int:
|
||||
"""Подписаться на пользователя
|
||||
|
||||
Args:
|
||||
username (str): username
|
||||
|
||||
Raises:
|
||||
UserNotFound: Пользователь не найден
|
||||
|
||||
Returns:
|
||||
int: Число подписчиков после подписки
|
||||
"""
|
||||
res = follow(self.token, username)
|
||||
if res.json().get('error', {}).get('code') == 'NOT_FOUND':
|
||||
raise UserNotFound()
|
||||
res.raise_for_status()
|
||||
|
||||
return res.json()['followersCount']
|
||||
|
||||
@refresh_on_error
|
||||
def unfollow(self, username: str) -> dict:
|
||||
return unfollow(self.token, username)
|
||||
def unfollow(self, username: str) -> int:
|
||||
"""Отписаться от пользователя
|
||||
|
||||
Args:
|
||||
username (str): username
|
||||
|
||||
Raises:
|
||||
UserNotFound: Пользователь не найден
|
||||
|
||||
Returns:
|
||||
int: Число подписчиков после отписки
|
||||
"""
|
||||
res = unfollow(self.token, username)
|
||||
if res.json().get('error', {}).get('code') == 'NOT_FOUND':
|
||||
raise UserNotFound()
|
||||
res.raise_for_status()
|
||||
|
||||
return res.json()['followersCount']
|
||||
|
||||
@refresh_on_error
|
||||
def get_followers(self, username: str) -> dict:
|
||||
return get_followers(self.token, username)
|
||||
def get_followers(self, username: str, limit: int = 30, page: int = 1) -> tuple[list[UserFollower], Pagination]:
|
||||
"""Получить подписчиков пользователя
|
||||
|
||||
Args:
|
||||
username (str): username
|
||||
limit (int, optional): Лимит. Defaults to 30.
|
||||
page (int, optional): Страница (при дозагрузке, увеличивайте на 1). Defaults to 1.
|
||||
|
||||
Raises:
|
||||
UserNotFound: Пользователь не найден
|
||||
|
||||
Returns:
|
||||
list[UserFollower]: Список подписчиков
|
||||
Pagination: Данные пагинации (лимит, страница, сколько всего, есть ли еще)
|
||||
"""
|
||||
res = get_followers(self.token, username, limit, page)
|
||||
if res.json().get('error', {}).get('code') == 'NOT_FOUND':
|
||||
raise UserNotFound()
|
||||
res.raise_for_status()
|
||||
|
||||
return [UserFollower.model_validate(user) for user in res.json()['data']['users']], Pagination.model_validate(res.json()['data']['pagination'])
|
||||
|
||||
@refresh_on_error
|
||||
def get_following(self, username: str) -> dict:
|
||||
return get_following(self.token, username)
|
||||
def get_following(self, username: str, limit: int = 30, page: int = 1) -> tuple[list[UserFollower], Pagination]:
|
||||
"""Получить подписки пользователя
|
||||
|
||||
Args:
|
||||
username (str): username
|
||||
limit (int, optional): Лимит. Defaults to 30.
|
||||
page (int, optional): Страница (при дозагрузке, увеличивайте на 1). Defaults to 1.
|
||||
|
||||
Raises:
|
||||
UserNotFound: Пользователь не найден
|
||||
|
||||
Returns:
|
||||
list[UserFollower]: Список подписок
|
||||
Pagination: Данные пагинации (лимит, страница, сколько всего, есть ли еще)
|
||||
"""
|
||||
res = get_following(self.token, username, limit, page)
|
||||
if res.json().get('error', {}).get('code') == 'NOT_FOUND':
|
||||
raise UserNotFound()
|
||||
res.raise_for_status()
|
||||
|
||||
return [UserFollower.model_validate(user) for user in res.json()['data']['users']], Pagination.model_validate(res.json()['data']['pagination'])
|
||||
|
||||
|
||||
@refresh_on_error
|
||||
def verificate(self, file_url: str):
|
||||
return verificate(self.token, file_url)
|
||||
def verificate(self, file_url: str) -> Verification:
|
||||
res = verificate(self.token, file_url)
|
||||
if res.json().get('error', {}).get('code') == 'PENDING_REQUEST_EXISTS':
|
||||
raise PendingRequestExists()
|
||||
res.raise_for_status()
|
||||
|
||||
return Verification.model_validate(res.json())
|
||||
|
||||
@refresh_on_error
|
||||
def get_verification_status(self):
|
||||
return get_verification_status(self.token)
|
||||
def get_verification_status(self) -> VerificationStatus:
|
||||
res = get_verification_status(self.token)
|
||||
res.raise_for_status()
|
||||
|
||||
return VerificationStatus.model_validate(res.json())
|
||||
|
||||
|
||||
@refresh_on_error
|
||||
def get_who_to_follow(self) -> dict:
|
||||
return get_who_to_follow(self.token)
|
||||
def get_who_to_follow(self) -> list[UserWhoToFollow]:
|
||||
res = get_who_to_follow(self.token)
|
||||
res.raise_for_status()
|
||||
|
||||
return [UserWhoToFollow.model_validate(user) for user in res.json()['users']]
|
||||
|
||||
@refresh_on_error
|
||||
def get_top_clans(self) -> dict:
|
||||
return get_top_clans(self.token)
|
||||
def get_top_clans(self) -> list[Clan]:
|
||||
res = get_top_clans(self.token)
|
||||
res.raise_for_status()
|
||||
|
||||
return [Clan.model_validate(clan) for clan in res.json()['clans']]
|
||||
|
||||
@refresh_on_error
|
||||
def get_platform_status(self) -> dict:
|
||||
|
||||
Reference in New Issue
Block a user