feat: add pins

This commit is contained in:
firedotguy
2026-02-07 17:47:09 +03:00
parent 506e6a5d09
commit 8aef43e11d
5 changed files with 63 additions and 7 deletions

View File

@@ -17,6 +17,7 @@ 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 verify, get_verification_status from itd.routes.verification import verify, get_verification_status
from itd.routes.pins import get_pins, remove_pin, set_pin
from itd.models.comment import Comment from itd.models.comment import Comment
from itd.models.notification import Notification from itd.models.notification import Notification
@@ -28,13 +29,14 @@ from itd.models.pagination import Pagination, PostsPagintaion, LikedPostsPaginta
from itd.models.verification import Verification, VerificationStatus from itd.models.verification import Verification, VerificationStatus
from itd.models.report import NewReport from itd.models.report import NewReport
from itd.models.file import File from itd.models.file import File
from itd.models.pin import Pin
from itd.enums import PostsTab, ReportTargetType, ReportTargetReason from itd.enums import PostsTab, ReportTargetType, ReportTargetReason
from itd.request import set_cookies from itd.request import set_cookies
from itd.exceptions import ( from itd.exceptions import (
NoCookie, NoAuthData, SamePassword, InvalidOldPassword, NotFound, ValidationError, UserBanned, NoCookie, NoAuthData, SamePassword, InvalidOldPassword, NotFound, ValidationError, UserBanned,
PendingRequestExists, Forbidden, UsernameTaken, CantFollowYourself, Unauthorized, PendingRequestExists, Forbidden, UsernameTaken, CantFollowYourself, Unauthorized,
CantRepostYourPost, AlreadyReposted, AlreadyReported, TooLarge CantRepostYourPost, AlreadyReposted, AlreadyReported, TooLarge, PinNotOwned
) )
@@ -52,7 +54,7 @@ def refresh_on_error(func):
class Client: class Client:
def __init__(self, token: str | None, cookies: str | None = None): def __init__(self, token: str | None = None, cookies: str | None = None):
self.cookies = cookies self.cookies = cookies
if token: if token:
@@ -984,3 +986,35 @@ class Client:
raise NotFound("Post not found") raise NotFound("Post not found")
return res.json()['likesCount'] return res.json()['likesCount']
@refresh_on_error
def get_pins(self) -> tuple[list[Pin], str]:
"""Список пинов
Returns:
list[Pin]: Список пинов
str: Активный пин
"""
res = get_pins(self.token)
res.raise_for_status()
data = res.json()['data']
return [Pin.model_validate(pin) for pin in data['pins']], data['activePin']
@refresh_on_error
def remove_pin(self):
"""Снять пин"""
res = remove_pin(self.token)
res.raise_for_status()
@refresh_on_error
def set_pin(self, slug: str):
res = set_pin(self.token, slug)
if res.status_code == 422 and 'found' in res.json():
raise ValidationError(*list(res.json()['found'].items())[0])
if res.json().get('error', {}).get('code') == 'PIN_NOT_OWNED':
raise PinNotOwned(slug)
res.raise_for_status()
return res.json()['pin']

View File

@@ -93,3 +93,9 @@ class AlreadyReported(Exception):
class TooLarge(Exception): class TooLarge(Exception):
def __str__(self): def __str__(self):
return 'Search query too large' return 'Search query too large'
class PinNotOwned(Exception):
def __init__(self, pin: str) -> None:
self.pin = pin
def __str__(self):
return f'You do not own "{self.pin}" pin'

View File

@@ -1,6 +1,12 @@
from pydantic import BaseModel from datetime import datetime
class Pin(BaseModel): from pydantic import BaseModel, Field
class ShortPin(BaseModel):
slug: str slug: str
name: str name: str
description: str description: str
class Pin(ShortPin):
granted_at: datetime = Field(alias='grantedAt')

View File

@@ -3,7 +3,7 @@ from datetime import datetime
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from itd.models.pin import Pin from itd.models.pin import ShortPin
class UserPrivacy(BaseModel): class UserPrivacy(BaseModel):
@@ -26,7 +26,7 @@ class UserNewPost(BaseModel):
username: str | None = None username: str | None = None
display_name: str = Field(alias='displayName') display_name: str = Field(alias='displayName')
avatar: str avatar: str
pin: Pin | None = None pin: ShortPin | None = None
verified: bool = False verified: bool = False

10
itd/routes/pins.py Normal file
View File

@@ -0,0 +1,10 @@
from itd.request import fetch
def get_pins(token: str):
return fetch(token, 'get', 'users/me/pins')
def remove_pin(token: str):
return fetch(token, 'delete', 'users/me/pin')
def set_pin(token: str, slug: str):
return fetch(token, 'put', 'users/me/pin', {'slug': slug})