Взаимодействие с API для конкурса разработчиков под Android

Подробно узнать о задачах конкурса можно на этой странице.

Запрет на пересылку сообщений

Изменения в схеме:

chat flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat;

channel flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat;

channelAdminLogEventActionToggleNoForwards new_value:Bool = ChannelAdminLogEventAction;

---functions---

messages.toggleNoForwards peer:InputPeer enabled:Bool = Updates;

В группах и каналах появляется флаг об отключенной возможности пересылки сообщений и сохранения файлов на устройство: chat.noforwards:flags.25?true и channel.noforwards:flags.27?true для базовых групп и супергрупп/каналов соответственно. При наличии этого флага предлагается спрятать или деактивировать некоторые возможности в интерфейсе чата. Флаг channel.noforwards не является приватным, его наличие или отсутствие можно применять и при наличии min-флага, аналогично, например, флагу verified.

При попытке пересылки сообщений из чата, в котором запрещена пересылка, метод messages.forwardMessages вернёт ошибку 400 CHAT_FORWARDS_RESTRICTED. В нормальной работе клиента такой ситуации происходить не должно, но если она вернулась, это значит, что была изменена настройка чата и информация на клиенте устарела. Необходимо показать ошибку в интерфейсе и обновить информацию о чате с помощью messages.getFullChat / channels.getFullChannel.

Пересылка уже существующих пересланных копий сообщений осуществляется по правилам того канала, где была опубликована копия сообщения, с которой взаимодействует пользователь.

Аналогично ошибка 400 CHAT_FORWARDS_RESTRICTED может вернуться, если использовать inputMediaPhoto или inputMediaDocument с медиаконтентом из чата, в котором запрещена пересылка. При этом такой проблемы не будет у самого автора сообщения, он сможет переиспользовать медиа в других чатах (именно через InputMedia, а не вызовом messages.forwardMessages). Это сделано для того, чтобы не сломать логику, при которой повторная отправка одного и того же файла одним пользователем не вызывает повторную загрузку байтов файла, а использует только InputMedia со ссылкой на первоначальную копию.

Управление настройкой чата происходит с помощью метода messages.toggleNoForwards. Здесь параметр peer задаёт группу или канал, в которых изменяется настройка, а enabled управляет тем, включена ли защита от пересылки (boolTrue) или выключена (boolFalse). По умолчанию у всех существующих чатов защита выключена. Изменять эту настройку имеет право только владелец группы/канала. При попытке изменить на текущее значение вернётся ошибка 400 CHAT_NOT_MODIFIED.

При изменении этой настройки в группе/канале его участникам может приходить обновление updateChat / updateChannel. Необходимо обрабатывать изменение флага noforwards в этом и любом другом месте, где приходит chat/channel, чтобы обновить элементы UI в реальном времени.

Также при изменении настройки в логе недавних событий у администраторов канала или супергруппы появится новое событие channelAdminLogEventActionToggleNoForwards. Необходимо поддержать этот тип события аналогично, например, channelAdminLogEventActionToggleSignatures.

Очистка истории в диапазоне дат

Изменения схемы:

messages.deleteHistory flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory;

Новые параметры min_date:flags.2?int max_date:flags.3?int позволяют ограничить диапазон дат, за которые будет выполнена очистка истории.

Такая очистка истории поддерживается только в личных сообщениях. В группах и каналах UI не изменяется.

UPD (Nov 14): Дополнение

messages.searchResultsCalendar flags:# inexact:flags.0?true count:int min_date:int min_msg_id:int offset_id_offset:flags.1?int periods:Vector<SearchResultsCalendarPeriod> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.SearchResultsCalendar;

Отображение и подгрузка календаря с медиа уже реализована в приложение. Можно полагаться на то, что messages.searchResultsCalendar.min_date:int содержит минимально доступную дату по всему чату, а не только по выбранному медиа-фильтру.

Для отображения превью переписки за выбранный день, когда сообщений нету в локальной базе приложения, предлагается использовать запрос messages.getHistory с параметром offset_date равным началу выбранных суток и отрицательным add_offset. В случае, если все вернувшиеся сообщения входят в эти же сутки, необходимо выполнить второй запрос messages.getHistory с параметром offset_date равным окончанию выбранных суток и limit=1. Тогда число сообщений в выбранные сутки будет равно разнице между значениями offset_id_offset в ответах на эти два запроса.

Отправка от имени канала

Изменения схемы:

channels.sendAsPeers peers:Vector<Peer> chats:Vector<Chat> users:Vector<User> = channels.SendAsPeers;

channelFull flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.20?true can_set_location:flags.16?true has_scheduled:flags.19?true blocked:flags.22?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> default_send_as:flags.29?Peer = ChatFull;

---functions---

messages.sendMessage flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;
messages.sendMedia flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;

messages.sendInlineBotResult flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;

messages.sendMultiMedia flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector<InputSingleMedia> schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;

messages.forwardMessages flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer schedule_date:flags.10?int send_as:flags.13?InputPeer = Updates;

messages.saveDefaultSendAs peer:InputPeer send_as:InputPeer = Bool;

channels.getSendAs peer:InputPeer = channels.SendAsPeers;

Появляется возможность отправки сообщения от имени канала.

В публичных супергруппах (channel.megagroup + channel.username или channel.has_geo), а также в дискуссионных группах (channel.megagroup + channel.has_link) можно выбрать, от кого будет отправлено сообщение.

Для того чтобы появилась возможность выбора (слева от поля ввода в интерфейсе чата группы), необходимо, чтобы у пользователя были публичные каналы. В таком случае в channelFull.flags будет установлен 29-й бит, а в самом поле channelFull.default_send_as:flags.29?Peer будет текущий автор сообщения по умолчанию.

При открытии меню автора сообщения отображается список доступных авторов. Для получения этого списка необходимо использовать метод channels.getSendAs со значением peer, равным id группы, для которой этот список требуется. Он вернёт список Peer-объектов, который формируется следующим образом:
- Если пользователь является анонимным администратором (channel.admin_rights.anonymous), то в начале списка будет сама группа. В противном случае там будет текущий пользователь.
- Далее, если пользователь является владельцем публичных каналов, то они будут перечислены в этом списке, при условии, что никакой из каналов не был забанен в текущей группе.

Пользователь может изменить автора на любой из предложенных каналов. В этом случае рекомендуется сразу вызвать новый метод messages.saveDefaultSendAs, чтобы обновить сохранённое значение на сервере, а также рекомендуется актуализировать значение channelFull.default_send_as:flags.29?Peer в локальном кеше.

Когда пользователь совершает отправку сообщения тем или иным способом с помощью методов messages.sendMessage, messages.sendMedia, messages.sendInlineBotResult, messages.sendMultiMedia и messages.forwardMessages и на клиенте есть информация о наличии channelFull.default_send_as:flags.29?Peer, необходимо передавать в методы параметр send_as:flags.13?InputPeer, заполняя его из текущего автора сообщения в интерфейсе, не забывая про бит 13 для flags. Это нужно, чтобы минимизировать риск неожиданной отправки сообщения от неподходящего автора.

В случае, если было передано недопустимое значение send_as (например, если канал успели забанить в группе), вернётся ошибка 400 SEND_AS_PEER_INVALID на метод отправки. В ответ на эту ошибку предлагается переполучить channels.getFullChannel, при этом должно вернуться обновлённое значение автора по умолчанию, что необходимо отразить в интерфейсе. При вызове повторной отправки сообщения необходимо делать это уже с новым значением send_as.

Если для чата значение автора по умолчанию отличается от текущего пользователя, не нужно вызывать messages.setTyping для этого чата.

Общее замечание: при реализации этой функции имеет смысл оглядываться на реализацию вступления в Video Chat от имени канала (параметр join_as метода phone.joinGroupCall, метод phone.getGroupCallJoinAs и т д).

Тестирование функций

Рекомендуется начать тестирование каждого из нововведений в тестовом окружении. После того как на тестовом датацентре удалось достичь удовлетворительных результатов, стоит переходить к тестированию в основном окружении. Переключение между окружениями осуществляется с помощью функции Switch Backend в дебаг-настройках приложения.

UPD (Nov 6): В настоящий момент в основном окружении отправлять сообщения от имени канала в группы могут только администраторы этих групп (с любыми администраторскими правами). В тестовом окружении этого ограничения нет.

Для регистрации на тестовом сервере можно использовать как свой собственный телефонный номер, так и тестовые учётные записи.