diff --git a/readthedocs/quick-references/client-reference.rst b/readthedocs/quick-references/client-reference.rst index 8ecc70dc..9bbbbd63 100644 --- a/readthedocs/quick-references/client-reference.rst +++ b/readthedocs/quick-references/client-reference.rst @@ -98,6 +98,7 @@ Dialogs iter_dialogs get_dialogs + archive iter_drafts get_drafts conversation diff --git a/telethon/client/dialogs.py b/telethon/client/dialogs.py index 420e96ac..c9ff0a92 100644 --- a/telethon/client/dialogs.py +++ b/telethon/client/dialogs.py @@ -1,3 +1,4 @@ +import asyncio import itertools import typing @@ -222,6 +223,82 @@ class DialogMethods(UserMethods): """ return await self.iter_drafts().collect() + async def archive( + self: 'TelegramClient', + entity: 'hints.EntitiesLike' = None, + folder: typing.Union[int, typing.Sequence[int]] = 1, + *, + unpack=None + ) -> types.Updates: + """ + Archives (or un-archives) one or more dialogs. + + Args: + entity (entities): + The entity or list of entities to move to the desired + archive folder. + + folder (`int`, optional): + The folder to which the dialog should be archived to. + + If you want to "un-archive" it, use ``folder=0``. + + You may also pass a list with the same length as + `entities` if you want to control where each entity + will go. + + unpack (`int`, optional): + If you want to unpack an archived folder, set this + parameter to the folder number that you want to + delete. + + When you unpack a folder, all the dialogs inside are + moved to the folder number 0. + + You can only use this parameter if the other two + are not set. + + Returns: + The :tl:`Updates` object that the request produces. + + Example: + + .. code-block:: python + + # Archiving the first 5 dialogs + dialogs = client.get_dialogs(5) + client.archive(dialogs) + + # Un-archiving the third dialog (archiving to folder 0) + client.archive(dialog[2], 0) + + # Un-archiving all dialogs + client.archive(unpack=1) + """ + if (entity is None) == (unpack is None): + raise ValueError('You can only set either entities or unpack, not both') + + if unpack is not None: + return await self(functions.folders.DeleteFolderRequest( + folder_id=unpack + )) + + if not utils.is_list_like(entity): + entities = [await self.get_input_entity(entity)] + else: + entities = await asyncio.gather( + *(self.get_input_entity(x) for x in entity), loop=self.loop) + + if not utils.is_list_like(folder): + folder = [folder] * len(entities) + elif len(entities) != len(folder): + raise ValueError('Number of folders does not match number of entities') + + return await self(functions.folders.EditPeerFoldersRequest([ + types.InputFolderPeer(x, folder_id=y) + for x, y in zip(entities, folder) + ])) + def conversation( self: 'TelegramClient', entity: 'hints.EntityLike', diff --git a/telethon/tl/custom/dialog.py b/telethon/tl/custom/dialog.py index 404dba94..99d01ebf 100644 --- a/telethon/tl/custom/dialog.py +++ b/telethon/tl/custom/dialog.py @@ -17,6 +17,12 @@ class Dialog: pinned (`bool`): Whether this dialog is pinned to the top or not. + folder_id (`folder_id`): + The folder ID that this dialog belongs to. + + archived (`bool`): + Whether this dialog is archived or not (``folder_id is None``). + message (`Message `): The last message sent on this dialog. Note that this member will not be updated when new messages arrive, it's only set @@ -68,6 +74,8 @@ class Dialog: self._client = client self.dialog = dialog self.pinned = bool(dialog.pinned) + self.folder_id = dialog.folder_id + self.archived = dialog.folder_id is not None self.message = messages.get(dialog.top_message, None) self.date = getattr(self.message, 'date', None) @@ -111,6 +119,33 @@ class Dialog: await self._client(functions.messages.DeleteHistoryRequest( self.input_entity, 0)) + async def archive(self, folder=1): + """ + Archives (or un-archives) this dialog. + + Args: + folder (`int`, optional): + The folder to which the dialog should be archived to. + + If you want to "un-archive" it, use ``folder=0``. + + Returns: + The :tl:`Updates` object that the request produces. + + Example: + + .. code-block:: python + + # Archiving + dialog.archive() + + # Un-archiving + dialog.archive(0) + """ + return await self._client(functions.folders.EditPeerFoldersRequest([ + types.InputFolderPeer(self.input_entity, folder_id=folder) + ])) + def to_dict(self): return { '_': 'Dialog', diff --git a/telethon_generator/data/errors.csv b/telethon_generator/data/errors.csv index 7ef1b0da..6439ea53 100644 --- a/telethon_generator/data/errors.csv +++ b/telethon_generator/data/errors.csv @@ -97,6 +97,8 @@ FILEREF_UPGRADE_NEEDED,406,The file reference needs to be refreshed before being FIRSTNAME_INVALID,400,The first name is invalid FLOOD_TEST_PHONE_WAIT_X,420,A wait of {seconds} seconds is required in the test servers FLOOD_WAIT_X,420,A wait of {seconds} seconds is required +FOLDER_ID_EMPTY,400,The folder you tried to delete was already empty +FOLDER_ID_INVALID,400,The folder you tried to use was not valid FRESH_RESET_AUTHORISATION_FORBIDDEN,406,The current session is too new and cannot be used to reset other authorisations yet GIF_ID_INVALID,400,The provided GIF ID is invalid GROUPED_MEDIA_INVALID,400,Invalid grouped media diff --git a/telethon_generator/data/methods.csv b/telethon_generator/data/methods.csv index 65d1cf6f..b5ef6b48 100644 --- a/telethon_generator/data/methods.csv +++ b/telethon_generator/data/methods.csv @@ -114,6 +114,8 @@ contacts.search,user,QUERY_TOO_SHORT SEARCH_QUERY_EMPTY Timeout contacts.toggleTopPeers,user, contacts.unblock,user,CONTACT_ID_INVALID contest.saveDeveloperInfo,both, +folders.deleteFolder,user,FOLDER_ID_EMPTY +folders.editPeerFolders,user,FOLDER_ID_INVALID help.acceptTermsOfService,user, help.editUserInfo,user,USER_INVALID help.getAppChangelog,user,