feat: add models and partially custom error messages
This commit is contained in:
264
itd/client.py
264
itd/client.py
@@ -1,3 +1,4 @@
|
|||||||
|
from uuid import UUID
|
||||||
from _io import BufferedReader
|
from _io import BufferedReader
|
||||||
from typing import cast
|
from typing import cast
|
||||||
|
|
||||||
@@ -14,7 +15,14 @@ from itd.routes.search import search
|
|||||||
from itd.routes.files import upload_file
|
from itd.routes.files import upload_file
|
||||||
from itd.routes.auth import refresh_token, change_password, logout
|
from itd.routes.auth import refresh_token, change_password, logout
|
||||||
from itd.routes.verification import verificate, get_verification_status
|
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.request import set_cookies
|
||||||
|
from itd.exceptions import NoCookie, NoAuthData, SamePassword, InvalidOldPassword, UserNotFound, InvalidProfileData, UserBanned, PendingRequestExists
|
||||||
|
|
||||||
|
|
||||||
def refresh_on_error(func):
|
def refresh_on_error(func):
|
||||||
@@ -39,79 +47,261 @@ class Client:
|
|||||||
set_cookies(self.cookies)
|
set_cookies(self.cookies)
|
||||||
self.refresh_auth()
|
self.refresh_auth()
|
||||||
else:
|
else:
|
||||||
raise ValueError('Provide token or cookie')
|
raise NoAuthData()
|
||||||
|
|
||||||
def refresh_auth(self):
|
def refresh_auth(self) -> str:
|
||||||
if self.cookies:
|
"""Обновить access token
|
||||||
self.token = refresh_token(self.cookies)
|
|
||||||
|
Raises:
|
||||||
|
NoCookie: Нет cookie
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Токен
|
||||||
|
"""
|
||||||
|
print('refresh token')
|
||||||
|
if not self.cookies:
|
||||||
|
raise NoCookie()
|
||||||
|
|
||||||
|
res = refresh_token(self.cookies)
|
||||||
|
res.raise_for_status()
|
||||||
|
|
||||||
|
self.token = res.json()['accessToken']
|
||||||
return self.token
|
return self.token
|
||||||
else:
|
|
||||||
print('no cookies')
|
|
||||||
|
|
||||||
@refresh_on_error
|
@refresh_on_error
|
||||||
def change_password(self, old: str, new: str):
|
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:
|
if not self.cookies:
|
||||||
print('no cookies')
|
raise NoCookie()
|
||||||
return
|
|
||||||
return change_password(self.cookies, self.token, old, new)
|
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
|
@refresh_on_error
|
||||||
def logout(self):
|
def logout(self) -> dict:
|
||||||
|
"""Выход из аккаунта
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NoCookie: Нет cookie
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Ответ API
|
||||||
|
"""
|
||||||
if not self.cookies:
|
if not self.cookies:
|
||||||
print('no cookies')
|
raise NoCookie()
|
||||||
return
|
|
||||||
return logout(self.cookies)
|
|
||||||
|
|
||||||
|
res = logout(self.cookies)
|
||||||
|
res.raise_for_status()
|
||||||
|
|
||||||
|
return res.json()
|
||||||
|
|
||||||
@refresh_on_error
|
@refresh_on_error
|
||||||
def get_user(self, username: str) -> dict:
|
def get_user(self, username: str) -> User:
|
||||||
return get_user(self.token, username)
|
"""Получить пользователя
|
||||||
|
|
||||||
|
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
|
@refresh_on_error
|
||||||
def get_me(self) -> dict:
|
def get_me(self) -> User:
|
||||||
|
"""Получить текущего пользователя (me)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
User: Пользователь
|
||||||
|
"""
|
||||||
return self.get_user('me')
|
return self.get_user('me')
|
||||||
|
|
||||||
@refresh_on_error
|
@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:
|
def update_profile(self, username: str | None = None, display_name: str | None = None, bio: str | None = None, banner_id: UUID | None = None) -> UserProfileUpdate:
|
||||||
return update_profile(self.token, bio, display_name, username, banner_id)
|
"""Обновить профиль
|
||||||
|
|
||||||
|
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
|
@refresh_on_error
|
||||||
def update_privacy(self, wall_closed: bool = False, private: bool = False):
|
def update_privacy(self, wall_closed: bool = False, private: bool = False) -> UserPrivacy:
|
||||||
return update_privacy(self.token, wall_closed, private)
|
"""Обновить настройки приватности
|
||||||
|
|
||||||
|
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
|
@refresh_on_error
|
||||||
def follow(self, username: str) -> dict:
|
def follow(self, username: str) -> int:
|
||||||
return follow(self.token, username)
|
"""Подписаться на пользователя
|
||||||
|
|
||||||
|
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
|
@refresh_on_error
|
||||||
def unfollow(self, username: str) -> dict:
|
def unfollow(self, username: str) -> int:
|
||||||
return unfollow(self.token, username)
|
"""Отписаться от пользователя
|
||||||
|
|
||||||
|
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
|
@refresh_on_error
|
||||||
def get_followers(self, username: str) -> dict:
|
def get_followers(self, username: str, limit: int = 30, page: int = 1) -> tuple[list[UserFollower], Pagination]:
|
||||||
return get_followers(self.token, username)
|
"""Получить подписчиков пользователя
|
||||||
|
|
||||||
|
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
|
@refresh_on_error
|
||||||
def get_following(self, username: str) -> dict:
|
def get_following(self, username: str, limit: int = 30, page: int = 1) -> tuple[list[UserFollower], Pagination]:
|
||||||
return get_following(self.token, username)
|
"""Получить подписки пользователя
|
||||||
|
|
||||||
|
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
|
@refresh_on_error
|
||||||
def verificate(self, file_url: str):
|
def verificate(self, file_url: str) -> Verification:
|
||||||
return verificate(self.token, file_url)
|
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
|
@refresh_on_error
|
||||||
def get_verification_status(self):
|
def get_verification_status(self) -> VerificationStatus:
|
||||||
return get_verification_status(self.token)
|
res = get_verification_status(self.token)
|
||||||
|
res.raise_for_status()
|
||||||
|
|
||||||
|
return VerificationStatus.model_validate(res.json())
|
||||||
|
|
||||||
|
|
||||||
@refresh_on_error
|
@refresh_on_error
|
||||||
def get_who_to_follow(self) -> dict:
|
def get_who_to_follow(self) -> list[UserWhoToFollow]:
|
||||||
return get_who_to_follow(self.token)
|
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
|
@refresh_on_error
|
||||||
def get_top_clans(self) -> dict:
|
def get_top_clans(self) -> list[Clan]:
|
||||||
return get_top_clans(self.token)
|
res = get_top_clans(self.token)
|
||||||
|
res.raise_for_status()
|
||||||
|
|
||||||
|
return [Clan.model_validate(clan) for clan in res.json()['clans']]
|
||||||
|
|
||||||
@refresh_on_error
|
@refresh_on_error
|
||||||
def get_platform_status(self) -> dict:
|
def get_platform_status(self) -> dict:
|
||||||
|
|||||||
43
itd/exceptions.py
Normal file
43
itd/exceptions.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
class NoCookie(Exception):
|
||||||
|
def __str__(self):
|
||||||
|
return 'No cookie for refresh-token required action'
|
||||||
|
|
||||||
|
class NoAuthData(Exception):
|
||||||
|
def __str__(self):
|
||||||
|
return 'No auth data. Provide token or cookies'
|
||||||
|
|
||||||
|
class InvalidCookie(Exception):
|
||||||
|
def __str__(self):
|
||||||
|
return f'Invalid cookie data'
|
||||||
|
|
||||||
|
class InvalidToken(Exception):
|
||||||
|
def __str__(self):
|
||||||
|
return f'Invalid access token'
|
||||||
|
|
||||||
|
|
||||||
|
class SamePassword(Exception):
|
||||||
|
def __str__(self):
|
||||||
|
return 'Old and new password must not equals'
|
||||||
|
|
||||||
|
class InvalidOldPassword(Exception):
|
||||||
|
def __str__(self):
|
||||||
|
return 'Old password is incorrect'
|
||||||
|
|
||||||
|
class UserNotFound(Exception):
|
||||||
|
def __str__(self):
|
||||||
|
return 'User not found'
|
||||||
|
|
||||||
|
class UserBanned(Exception):
|
||||||
|
def __str__(self):
|
||||||
|
return 'User banned'
|
||||||
|
|
||||||
|
class InvalidProfileData(Exception):
|
||||||
|
def __init__(self, name: str, value: str):
|
||||||
|
self.name = name
|
||||||
|
self.value = value
|
||||||
|
def __str__(self):
|
||||||
|
return f'Invalid update profile data {self.name}: "{self.value}"'
|
||||||
|
|
||||||
|
class PendingRequestExists(Exception):
|
||||||
|
def __str__(self):
|
||||||
|
return 'Pending verifiaction request already exists'
|
||||||
@@ -6,7 +6,7 @@ from pydantic import BaseModel, Field
|
|||||||
from itd.models.user import UserPost
|
from itd.models.user import UserPost
|
||||||
|
|
||||||
|
|
||||||
class _TextObject(BaseModel):
|
class TextObject(BaseModel):
|
||||||
id: UUID
|
id: UUID
|
||||||
content: str
|
content: str
|
||||||
author: UserPost
|
author: UserPost
|
||||||
|
|||||||
6
itd/models/clan.py
Normal file
6
itd/models/clan.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
|
class Clan(BaseModel):
|
||||||
|
avatar: str
|
||||||
|
member_count: int = Field(0, alias='memberCount')
|
||||||
@@ -1,12 +1,9 @@
|
|||||||
from uuid import UUID
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
|
|
||||||
from itd.models._text import _TextObject
|
from itd.models._text import TextObject
|
||||||
|
|
||||||
|
|
||||||
class CommentShort(_TextObject):
|
class CommentShort(TextObject):
|
||||||
likes_count: int = Field(0, alias='likesCount')
|
likes_count: int = Field(0, alias='likesCount')
|
||||||
replies_count: int = Field(0, alias='repliesCount')
|
replies_count: int = Field(0, alias='repliesCount')
|
||||||
is_liked: bool = Field(False, alias='isLiked')
|
is_liked: bool = Field(False, alias='isLiked')
|
||||||
|
|||||||
7
itd/models/pagination.py
Normal file
7
itd/models/pagination.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
class Pagination(BaseModel):
|
||||||
|
page: int = 1
|
||||||
|
limit: int = 20
|
||||||
|
total: int | None = None
|
||||||
|
has_more: bool = Field(True, alias='hasMore')
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
|
|
||||||
from itd.models.user import UserPost
|
from itd.models.user import UserPost
|
||||||
from itd.models._text import _TextObject
|
from itd.models._text import TextObject
|
||||||
|
|
||||||
|
|
||||||
class PostShort(_TextObject):
|
class PostShort(TextObject):
|
||||||
likes_count: int = Field(0, alias='likesCount')
|
likes_count: int = Field(0, alias='likesCount')
|
||||||
comments_count: int = Field(0, alias='commentsCount')
|
comments_count: int = Field(0, alias='commentsCount')
|
||||||
reposts_count: int = Field(0, alias='repostsCount')
|
reposts_count: int = Field(0, alias='repostsCount')
|
||||||
|
|||||||
@@ -3,6 +3,25 @@ from datetime import datetime
|
|||||||
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
|
class UserPrivacy(BaseModel):
|
||||||
|
private: bool | None = Field(None, alias='isPrivate') # none for not me
|
||||||
|
wall_closed: bool = Field(False, alias='wallClosed')
|
||||||
|
|
||||||
|
model_config = {'populate_by_name': True}
|
||||||
|
|
||||||
|
|
||||||
|
class UserProfileUpdate(BaseModel):
|
||||||
|
id: UUID
|
||||||
|
username: str
|
||||||
|
display_name: str = Field(alias='displayName')
|
||||||
|
bio: str | None = None
|
||||||
|
|
||||||
|
updated_at: datetime | None = Field(None, alias='updatedAt')
|
||||||
|
|
||||||
|
model_config = {'populate_by_name': True}
|
||||||
|
|
||||||
|
|
||||||
class UserNotification(BaseModel):
|
class UserNotification(BaseModel):
|
||||||
id: UUID
|
id: UUID
|
||||||
username: str
|
username: str
|
||||||
@@ -16,22 +35,26 @@ class UserPost(UserNotification):
|
|||||||
verified: bool = False
|
verified: bool = False
|
||||||
|
|
||||||
|
|
||||||
class UserSearch(UserPost):
|
class UserWhoToFollow(UserPost):
|
||||||
followers_count: int = Field(0, alias='followersCount')
|
followers_count: int = Field(0, alias='followersCount')
|
||||||
|
|
||||||
|
|
||||||
class User(UserSearch):
|
class UserFollower(UserPost):
|
||||||
|
is_following: bool = Field(False, alias='isFollowing') # none for me
|
||||||
|
|
||||||
|
|
||||||
|
class UserSearch(UserFollower, UserWhoToFollow):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class User(UserSearch, UserPrivacy):
|
||||||
banner: str | None = None
|
banner: str | None = None
|
||||||
bio: str | None = None
|
bio: str | None = None
|
||||||
pinned_post_id: UUID | None
|
pinned_post_id: UUID | None = Field(None, alias='pinnedPostId')
|
||||||
|
|
||||||
private: bool | None = Field(None, alias='isPrivate') # none for not me
|
|
||||||
wall_closed: bool = Field(False, alias='wallClosed')
|
|
||||||
|
|
||||||
following_count: int = Field(0, alias='followingCount')
|
following_count: int = Field(0, alias='followingCount')
|
||||||
posts_count: int = Field(0, alias='postsCount')
|
posts_count: int = Field(0, alias='postsCount')
|
||||||
|
|
||||||
is_following: bool | None = Field(None, alias='isFollowing') # none for me
|
|
||||||
is_followed: bool | None = Field(None, alias='isFollowedBy') # none for me
|
is_followed: bool | None = Field(None, alias='isFollowedBy') # none for me
|
||||||
|
|
||||||
created_at: datetime = Field(alias='createdAt')
|
created_at: datetime = Field(alias='createdAt')
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ from _io import BufferedReader
|
|||||||
|
|
||||||
from requests import Session
|
from requests import Session
|
||||||
|
|
||||||
|
from itd.exceptions import InvalidToken, InvalidCookie
|
||||||
|
|
||||||
s = Session()
|
s = Session()
|
||||||
|
|
||||||
|
|
||||||
@@ -29,8 +31,9 @@ def fetch(token: str, method: str, url: str, params: dict = {}, files: dict[str,
|
|||||||
else:
|
else:
|
||||||
res = s.request(method.upper(), base, timeout=20, json=params, headers=headers, files=files)
|
res = s.request(method.upper(), base, timeout=20, json=params, headers=headers, files=files)
|
||||||
|
|
||||||
res.raise_for_status()
|
print(res.text)
|
||||||
return res.json()
|
return res
|
||||||
|
|
||||||
|
|
||||||
def set_cookies(cookies: str):
|
def set_cookies(cookies: str):
|
||||||
for cookie in cookies.split('; '):
|
for cookie in cookies.split('; '):
|
||||||
@@ -65,5 +68,11 @@ def auth_fetch(cookies: str, method: str, url: str, params: dict = {}, token: st
|
|||||||
res = s.get(f'https://xn--d1ah4a.com/api/{url}', timeout=20, params=params, headers=headers)
|
res = s.get(f'https://xn--d1ah4a.com/api/{url}', timeout=20, params=params, headers=headers)
|
||||||
else:
|
else:
|
||||||
res = s.request(method, f'https://xn--d1ah4a.com/api/{url}', timeout=20, json=params, headers=headers)
|
res = s.request(method, f'https://xn--d1ah4a.com/api/{url}', timeout=20, json=params, headers=headers)
|
||||||
res.raise_for_status()
|
|
||||||
return res.json()
|
# print(res.text)
|
||||||
|
if res.text == 'UNAUTHORIZED':
|
||||||
|
raise InvalidToken()
|
||||||
|
if res.json().get('error', {}).get('code') in ('SESSION_NOT_FOUND', 'REFRESH_TOKEN_MISSING'):
|
||||||
|
raise InvalidCookie()
|
||||||
|
|
||||||
|
return res
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
|
from requests import Response
|
||||||
|
|
||||||
from itd.request import auth_fetch
|
from itd.request import auth_fetch
|
||||||
|
|
||||||
def refresh_token(cookies: str):
|
def refresh_token(cookies: str) -> Response:
|
||||||
return auth_fetch(cookies, 'post', 'v1/auth/refresh')['accessToken']
|
return auth_fetch(cookies, 'post', 'v1/auth/refresh')
|
||||||
|
|
||||||
def change_password(cookies: str, token: str, old: str, new: str):
|
def change_password(cookies: str, token: str, old: str, new: str) -> Response:
|
||||||
return auth_fetch(cookies, 'post', 'v1/auth/change-password', {'newPassword': new, 'oldPassword': old}, token)
|
return auth_fetch(cookies, 'post', 'v1/auth/change-password', {'newPassword': new, 'oldPassword': old}, token)
|
||||||
|
|
||||||
def logout(cookies: str):
|
def logout(cookies: str) -> Response:
|
||||||
return auth_fetch(cookies, 'post', 'v1/auth/logout')
|
return auth_fetch(cookies, 'post', 'v1/auth/logout')
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ def add_comment(token: str, post_id: str, content: str, reply_comment_id: str |
|
|||||||
return fetch(token, 'post', f'posts/{post_id}/comments', data)
|
return fetch(token, 'post', f'posts/{post_id}/comments', data)
|
||||||
|
|
||||||
def get_comments(token: str, post_id: str, limit: int = 20, cursor: int = 0, sort: str = 'popular'):
|
def get_comments(token: str, post_id: str, limit: int = 20, cursor: int = 0, sort: str = 'popular'):
|
||||||
return fetch(token, 'get', f'posts/{post_id}/comments', {'limit': limit, 'sort': sort, 'cursor': cursor})['data']
|
return fetch(token, 'get', f'posts/{post_id}/comments', {'limit': limit, 'sort': sort, 'cursor': cursor})
|
||||||
|
|
||||||
def like_comment(token: str, comment_id: str):
|
def like_comment(token: str, comment_id: str):
|
||||||
return fetch(token, 'post', f'comments/{comment_id}/like')
|
return fetch(token, 'post', f'comments/{comment_id}/like')
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from itd.request import fetch
|
from itd.request import fetch
|
||||||
|
|
||||||
def get_hastags(token: str, limit: int = 10):
|
def get_hastags(token: str, limit: int = 10):
|
||||||
return fetch(token, 'get', 'hashtags/trending', {'limit': limit})['data']
|
return fetch(token, 'get', 'hashtags/trending', {'limit': limit})
|
||||||
|
|
||||||
def get_posts_by_hastag(token: str, hashtag: str, limit: int = 20, cursor: int = 0):
|
def get_posts_by_hastag(token: str, hashtag: str, limit: int = 20, cursor: int = 0):
|
||||||
return fetch(token, 'get', f'hashtags/{hashtag}/posts', {'limit': limit, 'cursor': cursor})
|
return fetch(token, 'get', f'hashtags/{hashtag}/posts', {'limit': limit, 'cursor': cursor})
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ def get_posts(token: str, username: str | None = None, limit: int = 20, cursor:
|
|||||||
if tab:
|
if tab:
|
||||||
data['tab'] = tab
|
data['tab'] = tab
|
||||||
|
|
||||||
return fetch(token, 'get', 'posts', data)['data']
|
return fetch(token, 'get', 'posts', data)
|
||||||
|
|
||||||
def get_post(token: str, id: str):
|
def get_post(token: str, id: str):
|
||||||
return fetch(token, 'get', f'posts/{id}')
|
return fetch(token, 'get', f'posts/{id}')
|
||||||
@@ -43,3 +43,5 @@ def view_post(token: str, id: str):
|
|||||||
|
|
||||||
def get_liked_posts(token: str, username: str, limit: int = 20, cursor: int = 0):
|
def get_liked_posts(token: str, username: str, limit: int = 20, cursor: int = 0):
|
||||||
return fetch(token, 'get', f'posts/user/{username}/liked', {'limit': limit, 'cursor': cursor})
|
return fetch(token, 'get', f'posts/user/{username}/liked', {'limit': limit, 'cursor': cursor})
|
||||||
|
|
||||||
|
# todo post restore
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
|
from uuid import UUID
|
||||||
|
|
||||||
from itd.request import fetch
|
from itd.request import fetch
|
||||||
|
|
||||||
|
|
||||||
def get_user(token: str, username: str):
|
def get_user(token: str, username: str):
|
||||||
return fetch(token, 'get', f'users/{username}')
|
return fetch(token, 'get', f'users/{username}')
|
||||||
|
|
||||||
def update_profile(token: str, bio: str | None = None, display_name: str | None = None, username: str | None = None, banner_id: str | None = None):
|
def update_profile(token: str, bio: str | None = None, display_name: str | None = None, username: str | None = None, banner_id: UUID | None = None):
|
||||||
data = {}
|
data = {}
|
||||||
if bio:
|
if bio:
|
||||||
data['bio'] = bio
|
data['bio'] = bio
|
||||||
@@ -13,14 +15,14 @@ def update_profile(token: str, bio: str | None = None, display_name: str | None
|
|||||||
if username:
|
if username:
|
||||||
data['username'] = username
|
data['username'] = username
|
||||||
if banner_id:
|
if banner_id:
|
||||||
data['bannerId'] = banner_id
|
data['bannerId'] = str(banner_id)
|
||||||
return fetch(token, 'put', 'users/me', data)
|
return fetch(token, 'put', 'users/me', data)
|
||||||
|
|
||||||
def update_privacy(token: str, wall_closed: bool = False, private: bool = False):
|
def update_privacy(token: str, wall_closed: bool = False, private: bool = False):
|
||||||
data = {}
|
data = {}
|
||||||
if wall_closed:
|
if wall_closed is not None:
|
||||||
data['wallClosed'] = wall_closed
|
data['wallClosed'] = wall_closed
|
||||||
if private:
|
if private is not None:
|
||||||
data['isPrivate'] = private
|
data['isPrivate'] = private
|
||||||
return fetch(token, 'put', 'users/me/privacy', data)
|
return fetch(token, 'put', 'users/me/privacy', data)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user