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

>Подробно узнать о задачах [конкурса](https://t.me/contest_ru/4) можно на [этой странице](https://contest.com/docs/android-Nov2021-ru).

* [Запрет на пересылку сообщений](#zapret-na-peresilku-soobschenii)
* [Очистка истории в диапазоне дат](#ochistka-istorii-v-diapazone-dat)
* [Отправка от имени канала](#otpravka-ot-imeni-kanala)
* [Тестирование функций](#testirovanie-funktsii)

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

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

```
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-флага](/api/min.md), аналогично, например, флагу `verified`.

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

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

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

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

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

Также при изменении настройки в [логе недавних событий](/api/recent-actions.md) у администраторов канала или супергруппы появится новое событие `channelAdminLogEventActionToggleNoForwards`. Необходимо поддержать этот тип события аналогично, например, [channelAdminLogEventActionToggleSignatures](/constructor/channelAdminLogEventActionToggleSignatures.md).

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

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

```
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](/method/messages.getHistory.md) с параметром `offset_date` равным началу выбранных суток и отрицательным `add_offset`. В случае, если все вернувшиеся сообщения входят в эти же сутки, необходимо выполнить второй запрос [messages.getHistory](/method/messages.getHistory.md) с параметром `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](/method/messages.sendMessage.md), [messages.sendMedia](/method/messages.sendMedia.md), [messages.sendInlineBotResult](/method/messages.sendInlineBotResult.md), [messages.sendMultiMedia](/method/messages.sendMultiMedia.md) и [messages.forwardMessages](/method/messages.forwardMessages.md) и на клиенте есть информация о наличии `channelFull.default_send_as:flags.29?Peer`, необходимо передавать в методы параметр `send_as:flags.13?InputPeer`, заполняя его из текущего автора сообщения в интерфейсе, не забывая про бит 13 для flags. Это нужно, чтобы минимизировать риск неожиданной отправки сообщения от неподходящего автора.

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

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

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

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

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

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

Для регистрации на тестовом сервере можно использовать как свой собственный телефонный номер, так и [тестовые учётные записи](/api/auth.md#test-accounts).

