refactor: ユーザーの型を再定義

pull/110/head
yupix 10 months ago
parent b59eab9807
commit b38926b79b
No known key found for this signature in database
GPG Key ID: 2FF705F5C56D9C06

@ -2,6 +2,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING, Literal, NotRequired, TypedDict, TypeGuard
from mipac.types.meta import IPolicies
from mipac.types.roles import IPartialRole
if TYPE_CHECKING:
@ -13,6 +14,11 @@ if TYPE_CHECKING:
IUserOnlineStatus = Literal["online", "active", "offline", "unknown"]
IFfVisibility = Literal["public", "followers", "private"]
IUserNotify = Literal["normal", "none"]
ITwoFactoryBackupCodesStock = Literal["full", "partial", "none"]
NotificationRecieveConfigOption = Literal[
"all", "following", "follower", "mutualFollow", "list", "never"
] # Misskey側が間違っている(Receiveのミススペル?)ので混乱を招かないようにこっちも統一してある
EmailNotificationTypes = Literal["mention", "reply", "quote", "follow", "receiveFollowRequest"]
class IUserField(TypedDict):
@ -70,33 +76,69 @@ class IUserRequired(TypedDict):
avatar_blurhash: str
class IAvatarDecoration(TypedDict):
id: str
angle: NotRequired[int]
flip_h: NotRequired[bool]
url: str
class NotificationRecieveConfigType(TypedDict):
type: NotificationRecieveConfigOption
class NotificationRecieveConfig(TypedDict):
app: NotificationRecieveConfigType
quote: NotificationRecieveConfigType
reply: NotificationRecieveConfigType
follow: NotificationRecieveConfigType
renote: NotificationRecieveConfigType
mention: NotificationRecieveConfigType
reaction: NotificationRecieveConfigType
pollEnded: NotificationRecieveConfigType
achievementEarned: NotificationRecieveConfigType
receiveFollowRequest: NotificationRecieveConfigType
followRequestAccepted: NotificationRecieveConfigType
class IUserSecurityKey(TypedDict):
id: str
name: str
last_used: str
class IPartialUser(TypedDict):
"""
Misskey Schema: `packedUserLiteSchema`
"""
id: str
name: str | None
username: str
host: str | None
avatar_url: str
avatar_blurhash: str
is_bot: bool
is_cat: bool
avatar_url: str | None
avatar_blurhash: str | None
avatar_decorations: list[IAvatarDecoration]
is_bot: NotRequired[bool]
is_cat: NotRequired[bool]
instance: NotRequired[IInstanceLite] # ローカルユーザーの場合はキーが無い
emojis: dict[str, str]
online_status: IUserOnlineStatus
badge_roles: NotRequired[list[IBadgeRole]] # リモートユーザーの場合はキーが無い
class IUserDetailedNotLogined(IPartialUser):
class IUserDetailedNotMeOnlySchema(TypedDict):
"""
ログイン無し
Misskey Schema: `packedUserDetailedNotMeOnlySchema`
"""
url: str | None # ローカルユーザーには無い
uri: str | None # # ローカルユーザーには無い
moved_to: str | None # ユーザーのID
url: str | None
uri: str | None
moved_to: str | None
also_known_as: list[str] | None
created_at: str
updated_at: str | None
last_fetched_at: str | None # ローカルユーザーには無い
last_fetched_at: str | None
banner_url: str | None
banner_blurhash: str | None
is_locked: bool
@ -107,7 +149,7 @@ class IUserDetailedNotLogined(IPartialUser):
birthday: str | None
lang: str | None
fields: list[IUserField]
verified_links: list[str]
verified_linlks: list[str]
followers_count: int
following_count: int
notes_count: int
@ -122,39 +164,24 @@ class IUserDetailedNotLogined(IPartialUser):
security_keys: bool
roles: list[IPartialRole]
memo: str | None
class IUserDetailed(IUserDetailedNotLogined):
"""
主に自分から見た相手の情報が追加される
ログイン済み
モデレーターではない
"""
is_following: bool
is_followed: bool
has_pending_follow_request_from_you: bool
has_pending_follow_request_to_you: bool
is_blocking: bool
is_blocked: bool
is_muted: bool
is_renote_muted: bool
notify: IUserNotify
class IUserDetailedModerator(IUserDetailed):
"""モデレーターから見たユーザー"""
moderation_note: str
class IMeDetailed(IUserDetailed):
"""自分自身"""
avatar_id: str
banner_id: None
is_moderator: bool
is_admin: bool
moderation_note: NotRequired[str]
is_following: NotRequired[bool]
is_followed: NotRequired[bool]
has_pending_follow_request_from_you: NotRequired[bool]
has_pending_follow_request_to_you: NotRequired[bool]
is_blocking: NotRequired[bool]
is_blocked: NotRequired[bool]
is_muted: NotRequired[bool]
is_renote_muted: NotRequired[bool]
notify: NotRequired[IUserNotify]
with_replies: NotRequired[bool]
class IMeDetailedOnlySchema(TypedDict):
avatar_id: str | None
banner_id: str | None
is_moderator: bool | None # entities/UserEntityService.ts で roleServiceを用いて判断してるからNoneの場合がある?
is_admin: bool | None
inject_featured_note: bool
receive_announcement_email: bool
always_mark_nsfw: bool
@ -165,125 +192,77 @@ class IMeDetailed(IUserDetailed):
prevent_ai_learning: bool
is_explorable: bool
is_deleted: bool
two_factor_backup_codes_stock: str
two_factory_backup_codes_stock: ITwoFactoryBackupCodesStock
hide_online_status: bool
has_unread_specified_notes: bool
has_unread_mentions: bool
has_unread_announcement: bool
unread_announcements: IAnnouncement
unread_announcements: list[IAnnouncement]
has_unread_antenna: bool
has_unread_channel: bool
has_unread_notification: bool
has_pending_received_follow_request: bool
muted_words: list[str]
muted_instances: dict
muting_notification_types: dict
notification_recieve_config: dict
email_notification_types: dict
achievements: dict
unread_notifications_count: bool
muted_words: list[list[str]]
hard_muted_words: list[list[str]]
muted_instances: list[str]
notification_recieve_config: NotificationRecieveConfig
email_notification_types: list[EmailNotificationTypes]
achievements: list[IAchievement]
logged_in_days: int
policies: dict
policies: IPolicies
email: NotRequired[str | None]
email_verified: NotRequired[bool]
security_keys_list: NotRequired[list[IUserSecurityKey]] # セキュリティー
class IMeDetailedModerator(IMeDetailed):
"""自分自身でモデレーター"""
class IUserDetailedNotMeSchema(IPartialUser, IUserDetailedNotMeOnlySchema):
pass
moderation_note: str
class IMeDetailedSchema(IUserDetailedNotMeSchema, IMeDetailedOnlySchema):
pass
# 型が不明確になるため、基本的にはこの共用体は使わないでください。基本的にAPIなどのレスポンスに使うことを想定しています。
IUser = (
IPartialUser
| IUserDetailedNotLogined
| IUserDetailed
| IUserDetailedModerator
| IMeDetailed
| IMeDetailedModerator
)
IUserDetailed = IUserDetailedNotMeSchema | IMeDetailedSchema
class IFollowRequest(TypedDict):
id: str
follower: IPartialUser
followee: IPartialUser
IUser = IPartialUser | IUserDetailed | IUserDetailedNotMeSchema | IMeDetailedSchema
def is_partial_user(user: IUser) -> TypeGuard[IPartialUser]:
return user.get("created_at") is None
def is_me_detailed(user: IUser, me_id: str) -> TypeGuard[IMeDetailed]:
return user.get("avatar_id") is not None and user.get("id") == me_id
def is_user_detailed_not_logined(user: IUser) -> TypeGuard[IUserDetailedNotLogined]:
"""
渡されたユーザーがログイン無しで取得された情報か確認しますまたこれは自分自身ではないです
Parameters
----------
user : IUser
user information
Returns
-------
TypeGuard[IUserDetailedNotLogined]
他のUser型は全て IUserDetailedNotMeSchema 経由で IUserDetailedNotMeOnlySchema を継承しているため
url が無いことを確認し区別する
"""
return (
user.get("is_following", "d3ee116d-1ee7-4a35-b277-0e22d541912e")
== "d3ee116d-1ee7-4a35-b277-0e22d541912e"
)
if "url" not in user:
return True
return False
def is_user_detailed(user: IUser) -> TypeGuard[IUserDetailed]:
def is_user_detailed_not_me(user: IUser) -> TypeGuard[IUserDetailedNotMeSchema]:
"""
渡されたユーザーがログイン済みで自分自身ではないかを判定します
Parameters
----------
user : IUser
user information
Returns
-------
TypeGuard[IUserDetailed]
IUserDetailedNotMeSchemaが持つ url が有ることを確認し
IMeDetailedOnlySchema が持つ avatar_id が無いことを確認する
こうすることで IMeDetailedSchema と区別する
"""
return (
user.get("avatar_id", "61a0dc68-bf6f-4947-9e9a-348db9c7de08")
== "61a0dc68-bf6f-4947-9e9a-348db9c7de08"
)
if "avatar_id" not in user and "url" in user:
return True
return False
def is_user_detailed_moderator(user: IUser) -> TypeGuard[IUserDetailedModerator]:
def is_me_detailed(user: IUser) -> TypeGuard[IMeDetailedSchema]:
"""
渡されたユーザーがモデレーターから見たユーザーかを判定します
Parameters
----------
user : IUser
user information
Returns
-------
TypeGuard[IUserDetailedModerator]
IMeDetailedOnlySchemaで avatar_id
IUserDetailedNotMeOnlySchemaで url
を持っているのでどちらともを満たしたものがIMeDetailedSchema
"""
return user.get("moderation_note") is not None
if "avatar_id" in user and "url" in user:
return True
return False
def is_me_detailed_moderator(user: IUser, me_id: str) -> TypeGuard[IMeDetailedModerator]:
"""
渡されたユーザーが自分自身克モデレーターかを判定します
Parameters
----------
user : IUser
user information
Returns
-------
TypeGuard[IMeDetailedModerator]
"""
return user.get("moderation_note") is not None and user.get("id") == me_id
def is_user_detailed(user: IUser) -> TypeGuard[IUserDetailed]:
if is_user_detailed_not_me(user) or is_me_detailed(user):
return True
return False

Loading…
Cancel
Save