From b38926b79b1b37ef88eba4c17192b77a00ce965a Mon Sep 17 00:00:00 2001 From: yupix Date: Mon, 4 Dec 2023 17:30:22 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=E3=83=A6=E3=83=BC=E3=82=B6?= =?UTF-8?q?=E3=83=BC=E3=81=AE=E5=9E=8B=E3=82=92=E5=86=8D=E5=AE=9A=E7=BE=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mipac/types/user.py | 247 ++++++++++++++++++++------------------------ 1 file changed, 113 insertions(+), 134 deletions(-) diff --git a/mipac/types/user.py b/mipac/types/user.py index 65d1d4c..f9379f8 100644 --- a/mipac/types/user.py +++ b/mipac/types/user.py @@ -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