diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index ecb72116ddc..47b1f17e24b 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -248,7 +248,6 @@ def get_title_list(s: str) -> list: toggle_forum_topics delete_folder export_folder_link - get_folder get_folders update_folder """, diff --git a/pyrogram/methods/chats/__init__.py b/pyrogram/methods/chats/__init__.py index 4615adcc029..46c7ee1ed64 100644 --- a/pyrogram/methods/chats/__init__.py +++ b/pyrogram/methods/chats/__init__.py @@ -40,7 +40,6 @@ from .get_chat_online_count import GetChatOnlineCount from .get_dialogs import GetDialogs from .get_dialogs_count import GetDialogsCount -from .get_folder import GetFolder from .get_folders import GetFolders from .get_forum_topics import GetForumTopics from .get_forum_topics_by_id import GetForumTopicsByID @@ -96,7 +95,6 @@ class Chats( SetChatUsername, SetChatPermissions, GetDialogsCount, - GetFolder, GetFolders, GetForumTopics, GetForumTopicsByID, diff --git a/pyrogram/methods/chats/export_folder_link.py b/pyrogram/methods/chats/export_folder_link.py index aae806704ad..ce5023a4ebe 100644 --- a/pyrogram/methods/chats/export_folder_link.py +++ b/pyrogram/methods/chats/export_folder_link.py @@ -43,15 +43,22 @@ async def export_folder_link( if not folder: return + peers = [] + + if folder.included_chats: + peers.extend(iter(folder.included_chats)) + + if folder.excluded_chats: + peers.extend(iter(folder.included_chats)) + + if folder.pinned_chats: + peers.extend(iter(folder.included_chats)) + r = await self.invoke( raw.functions.chatlists.ExportChatlistInvite( - chatlist=raw.types.InputChatlistDialogFilter( - filter_id=folder_id - ), + chatlist=raw.types.InputChatlistDialogFilter(filter_id=folder_id), title=folder.title, - peers=[await self.resolve_peer(i.id) for i in folder.pinned_peers] if folder.pinned_peers else [] - + [await self.resolve_peer(i.id) for i in folder.included_peers] if folder.included_peers else [] - + [await self.resolve_peer(i.id) for i in folder.excluded_peers] if folder.excluded_peers else [], + peers=[await self.resolve_peer(i.id) for i in peers], ) ) diff --git a/pyrogram/methods/chats/get_folder.py b/pyrogram/methods/chats/get_folder.py deleted file mode 100644 index 3cdba4c3c0f..00000000000 --- a/pyrogram/methods/chats/get_folder.py +++ /dev/null @@ -1,45 +0,0 @@ -# Pyrogram - Telegram MTProto API Client Library for Python -# Copyright (C) 2017-present Dan -# -# This file is part of Pyrogram. -# -# Pyrogram is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pyrogram is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Pyrogram. If not, see . - -from typing import Optional - -import pyrogram -from pyrogram import types - - -class GetFolder: - async def get_folder( - self: "pyrogram.Client", - folder_id: int - ) -> Optional["types.Folder"]: - """Get a user's folder by id. - - .. include:: /_includes/usable-by/users.rst - - Returns: - :obj:`~pyrogram.types.Folder`: On success, the user's folder is returned. - - Example: - .. code-block:: python - - # Get folder by id - await app.get_folder(123456789) - """ - async for folder in self.get_folders(): - if folder.id == folder_id: - return folder diff --git a/pyrogram/methods/chats/get_folders.py b/pyrogram/methods/chats/get_folders.py index acd3628fcb7..50d394180e8 100644 --- a/pyrogram/methods/chats/get_folders.py +++ b/pyrogram/methods/chats/get_folders.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from typing import AsyncGenerator, Optional +from typing import Union, List, Iterable import pyrogram from pyrogram import types, raw @@ -25,21 +25,37 @@ class GetFolders: async def get_folders( self: "pyrogram.Client", - ) -> AsyncGenerator["types.Folder", None]: - """Get a user's folders with chats sequentially. + folder_ids: Union[int, Iterable[int]] = None, + ) -> Union["types.Folder", List["types.Folder"]]: + """Get one or more folders by using folder identifiers. .. include:: /_includes/usable-by/users.rst + Parameters: + folder_ids (``int`` | Iterable of ``int``, *optional*): + Pass a single folder identifier or an iterable of folder ids (as integers) to get the content of the + folders themselves. + By default all folders are returned. + Returns: - ``Generator``: A generator yielding :obj:`~pyrogram.types.Folder` objects. + :obj:`~pyrogram.types.Folder` | List of :obj:`~pyrogram.types.Folder`: In case *folder_ids* was not + a list, a single folder is returned, otherwise a list of folders is returned. Example: .. code-block:: python - # Iterate through all folders - async for folder in app.get_folders(): - print(folder.title) + # Get one folder + await app.get_folders(12345) + + # Get more than one folders (list of folders) + await app.get_folders([12345, 12346]) + + # Get all folders + await app.get_folders() """ + is_iterable = hasattr(folder_ids, "__iter__") + ids = list(folder_ids) if is_iterable else [ids] + raw_folders = await self.invoke(raw.functions.messages.GetDialogFilters()) dialog_peers = [] @@ -49,13 +65,13 @@ async def get_folders( peers = folder.pinned_peers + folder.include_peers + getattr(folder, "exclude_peers", []) input_peers = [raw.types.InputDialogPeer(peer=peer) for peer in peers] + [raw.types.InputDialogPeerFolder(folder_id=folder.id)] + dialog_peers.extend(input_peers) r = await self.invoke(raw.functions.messages.GetPeerDialogs(peers=dialog_peers)) users = {i.id: i for i in r.users} chats = {i.id: i for i in r.chats} - peers = {**users, **chats} folders = [] @@ -63,10 +79,15 @@ async def get_folders( if not isinstance(folder, (raw.types.DialogFilter, raw.types.DialogFilterChatlist)): continue - folders.append(types.Folder._parse(self, folder, peers)) + folders.append(types.Folder._parse(self, folder, users, chats)) if not folders: return - for folder in folders: - yield folder + if is_iterable: + return [folder for folder in folders if folder.id in ids] or None + + if not folder_ids: + return folders + + return folders[0] diff --git a/pyrogram/methods/chats/update_folder.py b/pyrogram/methods/chats/update_folder.py index 1b6d3b260e8..34631862379 100644 --- a/pyrogram/methods/chats/update_folder.py +++ b/pyrogram/methods/chats/update_folder.py @@ -26,14 +26,14 @@ class UpdateFolder: async def update_folder( self: "pyrogram.Client", folder_id: int, - title: str, - pinned_peers: Union[Union[int, str], List[Union[int, str]]], - included_peers: Union[Union[int, str], List[Union[int, str]]], - excluded_peers: Union[Union[int, str], List[Union[int, str]]], + included_chats: Union[Union[int, str], List[Union[int, str]]] = None, + excluded_chats: Union[Union[int, str], List[Union[int, str]]] = None, + pinned_chats: Union[Union[int, str], List[Union[int, str]]] = None, + title: str = None, contacts: bool = None, non_contacts: bool = None, groups: bool = None, - broadcasts: bool = None, + channels: bool = None, bots: bool = None, exclude_muted: bool = None, exclude_read: bool = None, @@ -44,6 +44,53 @@ async def update_folder( .. include:: /_includes/usable-by/users.rst + Parameters: + folder_id (``int``): + Unique folder identifier. + + included_chats (``int`` | ``str`` | List of ``int`` or ``str``, *optional*): + Users or chats that should added in the folder + You can pass an ID (int), username (str) or phone number (str). + Multiple users can be added by passing a list of IDs, usernames or phone numbers. + + excluded_chats (``int`` | ``str`` | List of ``int`` or ``str``, *optional*): + Users or chats that should excluded from the folder + You can pass an ID (int), username (str) or phone number (str). + Multiple users can be added by passing a list of IDs, usernames or phone numbers. + + pinned_chats (``int`` | ``str`` | List of ``int`` or ``str``, *optional*): + Users or chats that should pinned in the folder + You can pass an ID (int), username (str) or phone number (str). + Multiple users can be added by passing a list of IDs, usernames or phone numbers. + + title (``str``, *optional*): + A folder title was changed to this value. + + contacts (``bool``, *optional*): + Pass True if folder should contain contacts. + + non_contacts (``bool``, *optional*): + Pass True if folder should contain non contacts. + + groups (``bool``, *optional*): + Pass True if folder should contain groups. + + channels (``bool``, *optional*): + Pass True if folder should contain channels. + + bots (``bool``, *optional*): + Pass True if folder should contain bots. + + exclude_muted (``bool``, *optional*): + Pass True if folder should exclude muted users. + + exclude_archived (``bool``, *optional*): + Pass True if folder should exclude archived users. + + emoji (``str``, *optional*): + Folder emoji. + Pass None to leave the folder icon as default. + Returns: ``bool``: True, on success. @@ -51,14 +98,14 @@ async def update_folder( .. code-block:: python # Delete folder - app.delete_folder(folder_id) + app.update_folder(folder_id, title="New folder", included_chats=["me"]) """ - if not isinstance(pinned_peers, list): - pinned_peers = [pinned_peers] - if not isinstance(included_peers, list): - included_peers = [included_peers] - if not isinstance(excluded_peers, list): - excluded_peers = [excluded_peers] + if not isinstance(included_chats, list): + included_peers = [included_chats] + if not isinstance(excluded_chats, list): + excluded_peers = [excluded_chats] + if not isinstance(pinned_chats, list): + pinned_peers = [pinned_chats] r = await self.invoke( raw.functions.messages.UpdateDialogFilter( @@ -81,7 +128,7 @@ async def update_folder( contacts=contacts, non_contacts=non_contacts, groups=groups, - broadcasts=broadcasts, + broadcasts=channels, bots=bots, exclude_muted=exclude_muted, exclude_read=exclude_read, diff --git a/pyrogram/types/user_and_chats/folder.py b/pyrogram/types/user_and_chats/folder.py index 15b3876d927..8ea0c350d73 100644 --- a/pyrogram/types/user_and_chats/folder.py +++ b/pyrogram/types/user_and_chats/folder.py @@ -22,7 +22,6 @@ from pyrogram import raw from pyrogram import types from ..object import Object -from ... import utils class Folder(Object): @@ -35,15 +34,15 @@ class Folder(Object): title (``str``): The folder title. - pinned_peers (List of :obj:`~pyrogram.types.Chat`): - A list of pinned chats in folder. - - included_peers (List of :obj:`~pyrogram.types.Chat`): + included_chats (List of :obj:`~pyrogram.types.Chat`, *optional*): A list of included chats in folder. - excluded_peers (List of :obj:`~pyrogram.types.Chat`, *optional*): + excluded_chats (List of :obj:`~pyrogram.types.Chat`, *optional*): A list of excluded chats in folder. + pinned_chats (List of :obj:`~pyrogram.types.Chat`, *optional*): + A list of pinned chats in folder. + contacts (``bool``, *optional*): True, if the folder includes contacts. @@ -53,8 +52,8 @@ class Folder(Object): groups (``bool``, *optional*): True, if the folder includes groups. - broadcasts (``bool``, *optional*): - True, if the folder includes broadcasts. + channels (``bool``, *optional*): + True, if the folder includes channels. bots (``bool``, *optional*): True, if the folder includes bots. @@ -78,13 +77,13 @@ def __init__( client: "pyrogram.Client" = None, id: int, title: str, - pinned_peers: List["types.Chat"] = None, - included_peers: List["types.Chat"] = None, - excluded_peers: List["types.Chat"] = None, + included_chats: List["types.Chat"] = None, + excluded_chats: List["types.Chat"] = None, + pinned_chats: List["types.Chat"] = None, contacts: bool = None, non_contacts: bool = None, groups: bool = None, - broadcasts: bool = None, + channels: bool = None, bots: bool = None, exclude_muted: bool = None, exclude_read: bool = None, @@ -96,13 +95,13 @@ def __init__( self.id = id self.title = title - self.pinned_peers = pinned_peers - self.included_peers = included_peers - self.excluded_peers = excluded_peers + self.included_chats = included_chats or [] + self.excluded_chats = excluded_chats or [] + self.pinned_chats = pinned_chats or [] self.contacts = contacts self.non_contacts = non_contacts self.groups = groups - self.broadcasts = broadcasts + self.channels = channels self.bots = bots self.exclude_muted = exclude_muted self.exclude_read = exclude_read @@ -110,21 +109,32 @@ def __init__( self.emoji = emoji self.has_my_invites = has_my_invites - @staticmethod - def _parse(client, folder: "raw.types.DialogFilter", peers) -> "Folder": - # TODO: Change types.Chat._parse to types.Dialog._parse + def _parse(client, folder: "raw.types.DialogFilter", users, chats) -> "Folder": + included_chats = [] + excluded_chats = [] + pinned_chats = [] + + for peer in folder.include_peers: + included_chats.append(types.Chat._parse_dialog(client, peer, users, chats)) + + if getattr(folder, "exclude_peers", None): + for peer in folder.exclude_peers: + excluded_chats.append(types.Chat._parse_dialog(client, peer, users, chats)) + + for peer in folder.pinned_peers: + pinned_chats.append(types.Chat._parse_dialog(client, peer, users, chats)) return Folder( id=folder.id, title=folder.title, - pinned_peers=types.List(types.Chat._parse_chat(client, peers.get(utils.get_input_peer_id(i), None)) for i in folder.pinned_peers) or None, - included_peers=types.List(types.Chat._parse_chat(client, peers.get(utils.get_input_peer_id(i), None)) for i in folder.include_peers) or None, - excluded_peers=types.List(types.Chat._parse_chat(client, peers.get(utils.get_input_peer_id(i), None)) for i in folder.exclude_peers) or None if getattr(folder, "exclude_peers", None) else None, + included_chats=types.List(included_chats) or None, + excluded_chats=types.List(excluded_chats) or None, + pinned_chats=types.List(pinned_chats) or None, contacts=getattr(folder, "contacts", None), non_contacts=getattr(folder, "non_contacts", None), groups=getattr(folder, "groups", None), - broadcasts=getattr(folder, "broadcasts", None), + channels=getattr(folder, "broadcasts", None), bots=getattr(folder, "bots", None), exclude_muted=getattr(folder, "exclude_muted", None), exclude_read=getattr(folder, "exclude_read", None), @@ -154,19 +164,82 @@ async def delete(self): return await self._client.delete_folder(self.id) - async def update_peers(self, pinned_peers: List[Union[int, str]], included_peers: List[Union[int, str]], excluded_peers: List[Union[int, str]]): + async def update( + self, + included_chats: List[Union[int, str]] = None, + excluded_chats: List[Union[int, str]] = None, + pinned_chats: List[Union[int, str]] = None, + title: str = None, + contacts: bool = None, + non_contacts: bool = None, + groups: bool = None, + channels: bool = None, + bots: bool = None, + exclude_muted: bool = None, + exclude_read: bool = None, + exclude_archived: bool = None, + emoji: str = None + ): """Bound method *update_peers* of :obj:`~pyrogram.types.Folder`. Use as a shortcut for: .. code-block:: python - await client.update_folder(123456789, ...) + await client.update_folder( + folder_id, + title="New folder", + included_chats=["me"] + ) Example: .. code-block:: python - await folder.update_peers(...) + await folder.update(included_chats=["me"]) + + Parameters: + included_chats (``int`` | ``str`` | List of ``int`` or ``str``, *optional*): + Users or chats that should added in the folder + You can pass an ID (int), username (str) or phone number (str). + Multiple users can be added by passing a list of IDs, usernames or phone numbers. + + excluded_chats (``int`` | ``str`` | List of ``int`` or ``str``, *optional*): + Users or chats that should excluded from the folder + You can pass an ID (int), username (str) or phone number (str). + Multiple users can be added by passing a list of IDs, usernames or phone numbers. + + pinned_chats (``int`` | ``str`` | List of ``int`` or ``str``, *optional*): + Users or chats that should pinned in the folder + You can pass an ID (int), username (str) or phone number (str). + Multiple users can be added by passing a list of IDs, usernames or phone numbers. + + title (``str``, *optional*): + A folder title was changed to this value. + + contacts (``bool``, *optional*): + Pass True if folder should contain contacts. + + non_contacts (``bool``, *optional*): + Pass True if folder should contain non contacts. + + groups (``bool``, *optional*): + Pass True if folder should contain groups. + + channels (``bool``, *optional*): + Pass True if folder should contain channels. + + bots (``bool``, *optional*): + Pass True if folder should contain bots. + + exclude_muted (``bool``, *optional*): + Pass True if folder should exclude muted users. + + exclude_archived (``bool``, *optional*): + Pass True if folder should exclude archived users. + + emoji (``str``, *optional*): + Folder emoji. + Pass None to leave the folder icon as default. Returns: True on success. @@ -174,91 +247,121 @@ async def update_peers(self, pinned_peers: List[Union[int, str]], included_peers return await self._client.update_folder( folder_id=self.id, - title=self.title, - pinned_peers=pinned_peers, - included_peers=included_peers, - excluded_peers=excluded_peers, - contacts=self.contacts, - non_contacts=self.non_contacts, - groups=self.groups, - broadcasts=self.broadcasts, - bots=self.bots, - exclude_muted=self.exclude_muted, - exclude_read=self.exclude_read, - exclude_archived=self.exclude_archived, - emoji=self.emoji + title=title or self.title, + included_chats=included_chats or self.included_chats, + excluded_chats=excluded_chats or self.excluded_chats, + pinned_chats=pinned_chats or self.pinned_chats, + contacts=contacts or self.contacts, + non_contacts=non_contacts or self.non_contacts, + groups=groups or self.groups, + channels=channels or self.channels, + bots=bots or self.bots, + exclude_muted=exclude_muted or self.exclude_muted, + exclude_read=exclude_read or self.exclude_read, + exclude_archived=exclude_archived or self.exclude_archived, + emoji=emoji or self.emoji ) - async def pin_chat(self, chat_id: Union[int, str]): - """Bound method *pin_chat* of :obj:`~pyrogram.types.Folder`. + async def include_chat(self, chat_id: Union[int, str]): + """Bound method *include_chat* of :obj:`~pyrogram.types.Folder`. Use as a shortcut for: .. code-block:: python - await client.update_folder(123456789, ...) + await client.update_folder( + folder_id=123456789, + included_chats=[chat_id], + excluded_chats=[...], + pinned_chats=[...] + ) Example: .. code-block:: python - await folder.pin_chat(chat_id) + await folder.include_chat(chat_id) + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier for the target chat or username of the target user/channel/supergroup + (in the format @username). Returns: True on success. """ - return await self.update_peers( - pinned_peers=[i.id for i in self.pinned_peers] if self.pinned_peers else [] + [chat_id], - included_peers=[i.id for i in self.included_peers] if self.included_peers else [] + [chat_id], - excluded_peers=[i.id for i in self.excluded_peers] if self.excluded_peers else [], + return await self.update( + included_chats=[i.id for i in self.included_chats] + [chat_id], + excluded_chats=[i.id for i in self.excluded_chats], + pinned_chats=[i.id for i in self.pinned_chats] ) - async def include_chat(self, chat_id: Union[int, str]): - """Bound method *include_chat* of :obj:`~pyrogram.types.Folder`. + async def exclude_chat(self, chat_id: Union[int, str]): + """Bound method *exclude_chat* of :obj:`~pyrogram.types.Folder`. Use as a shortcut for: .. code-block:: python - await client.update_folder(123456789, ...) + await client.update_folder( + folder_id=123456789, + included_chats=[...], + excluded_chats=[chat_id], + pinned_chats=[...] + ) Example: .. code-block:: python - await folder.include_chat(chat_id) + await folder.exclude_chat(chat_id) + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier for the target chat or username of the target user/channel/supergroup + (in the format @username). Returns: True on success. """ - return await self.update_peers( - pinned_peers=[i.id for i in self.pinned_peers] if self.pinned_peers else [], - included_peers=[i.id for i in self.included_peers] if self.included_peers else [] + [chat_id], - excluded_peers=[i.id for i in self.excluded_peers] if self.excluded_peers else [], + return await self.update( + included_chats=[i.id for i in self.included_chats], + excluded_chats=[i.id for i in self.excluded_chats] + [chat_id], + pinned_chats=[i.id for i in self.pinned_chats], ) - async def exclude_chat(self, chat_id: Union[int, str]): - """Bound method *exclude_chat* of :obj:`~pyrogram.types.Folder`. + async def pin_chat(self, chat_id: Union[int, str]): + """Bound method *pin_chat* of :obj:`~pyrogram.types.Folder`. Use as a shortcut for: .. code-block:: python - await client.update_folder(123456789, ...) + await client.update_folder( + folder_id=123456789, + included_chats=[chat_id], + excluded_chats=[chat_id], + pinned_chats=[...] + ) Example: .. code-block:: python - await folder.exclude_chat(chat_id) + await folder.pin_chat(chat_id) + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier for the target chat or username of the target user/channel/supergroup + (in the format @username). Returns: True on success. """ - return await self.update_peers( - pinned_peers=[i.id for i in self.pinned_peers] if self.pinned_peers else [], - included_peers=[i.id for i in self.included_peers] if self.included_peers else [], - excluded_peers=[i.id for i in self.excluded_peers] if self.excluded_peers else [] + [chat_id], + return await self.update( + included_chats=[i.id for i in self.included_chats] + [chat_id], + excluded_chats=[i.id for i in self.excluded_chats], + pinned_chats=[i.id for i in self.pinned_chats] + [chat_id] ) async def export_link(self): @@ -268,12 +371,12 @@ async def export_link(self): .. code-block:: python - await client.export_link(123456789) + await client.export_folder_link(123456789) Example: .. code-block:: python - await folder.export_folder_link(chat_id) + await folder.export_link() Returns: ``str``: On success, a link to the folder as string is returned.