From b9c64499bdce7ed4423e3613c6892d3e83fcac26 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 24 Nov 2021 07:25:05 +0300 Subject: [PATCH] Moved code for api participants to separated file. --- Telegram/CMakeLists.txt | 2 + .../SourceFiles/api/api_chat_participants.cpp | 659 ++++++++++++++++++ .../SourceFiles/api/api_chat_participants.h | 107 +++ Telegram/SourceFiles/api/api_invite_links.cpp | 3 +- Telegram/SourceFiles/api/api_updates.cpp | 5 +- Telegram/SourceFiles/apiwrap.cpp | 559 +-------------- Telegram/SourceFiles/apiwrap.h | 68 +- .../SourceFiles/boxes/delete_messages_box.cpp | 3 +- .../boxes/peer_list_controllers.cpp | 3 +- .../boxes/peers/add_participants_box.cpp | 7 +- .../boxes/peers/edit_participants_box.cpp | 22 +- .../group/calls_group_invite_controller.cpp | 3 +- .../calls/group/calls_group_panel.cpp | 7 +- .../chat_helpers/field_autocomplete.cpp | 7 +- Telegram/SourceFiles/data/data_channel.cpp | 73 -- Telegram/SourceFiles/data/data_channel.h | 4 - Telegram/SourceFiles/data/data_peer.cpp | 3 +- .../admin_log/history_admin_log_inner.cpp | 3 +- Telegram/SourceFiles/history/history.cpp | 3 +- .../SourceFiles/history/history_widget.cpp | 8 +- .../history_view_compose_controls.cpp | 3 +- .../view/history_view_top_bar_widget.cpp | 3 +- .../profile/profile_block_group_members.cpp | 10 +- .../SourceFiles/window/window_peer_menu.cpp | 5 +- 24 files changed, 840 insertions(+), 730 deletions(-) create mode 100644 Telegram/SourceFiles/api/api_chat_participants.cpp create mode 100644 Telegram/SourceFiles/api/api_chat_participants.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index df6bfd1b5..3dc2e6211 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -112,6 +112,8 @@ PRIVATE api/api_chat_filters.h api/api_chat_invite.cpp api/api_chat_invite.h + api/api_chat_participants.cpp + api/api_chat_participants.h api/api_cloud_password.cpp api/api_cloud_password.h api/api_common.h diff --git a/Telegram/SourceFiles/api/api_chat_participants.cpp b/Telegram/SourceFiles/api/api_chat_participants.cpp new file mode 100644 index 000000000..5a6928513 --- /dev/null +++ b/Telegram/SourceFiles/api/api_chat_participants.cpp @@ -0,0 +1,659 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "api/api_chat_participants.h" + +#include "apiwrap.h" +#include "boxes/add_contact_box.h" // ShowAddParticipantsError +#include "data/data_changes.h" +#include "data/data_channel.h" +#include "data/data_channel_admins.h" +#include "data/data_chat.h" +#include "data/data_histories.h" +#include "data/data_session.h" +#include "data/data_user.h" +#include "history/history.h" +#include "main/main_session.h" +#include "mtproto/mtproto_config.h" + +namespace Api { +namespace { + +constexpr auto kSmallDelayMs = crl::time(5); + +// 1 second wait before reload members in channel after adding. +constexpr auto kReloadChannelMembersTimeout = 1000; + +// Max users in one super group invite request. +constexpr auto kMaxUsersPerInvite = 100; + +// How many messages from chat history server should forward to user, +// that was added to this chat. +constexpr auto kForwardMessagesOnAdd = 100; + +void ApplyMegagroupAdmins( + not_null channel, + const MTPDchannels_channelParticipants &data) { + Expects(channel->isMegagroup()); + + channel->owner().processUsers(data.vusers()); + + const auto &list = data.vparticipants().v; + const auto i = ranges::find( + list, + mtpc_channelParticipantCreator, + &MTPChannelParticipant::type); + if (i != list.end()) { + const auto &data = i->c_channelParticipantCreator(); + const auto userId = data.vuser_id().v; + channel->mgInfo->creator = channel->owner().userLoaded(userId); + channel->mgInfo->creatorRank = qs(data.vrank().value_or_empty()); + } else { + channel->mgInfo->creator = nullptr; + channel->mgInfo->creatorRank = QString(); + } + + auto adding = base::flat_map(); + auto admins = ranges::make_subrange( + list.begin(), list.end() + ) | ranges::views::transform([](const MTPChannelParticipant &p) { + const auto participantId = p.match([]( + const MTPDchannelParticipantBanned &data) { + return peerFromMTP(data.vpeer()); + }, [](const MTPDchannelParticipantLeft &data) { + return peerFromMTP(data.vpeer()); + }, [](const auto &data) { + return peerFromUser(data.vuser_id()); + }); + const auto rank = p.match([](const MTPDchannelParticipantAdmin &data) { + return qs(data.vrank().value_or_empty()); + }, [](const MTPDchannelParticipantCreator &data) { + return qs(data.vrank().value_or_empty()); + }, [](const auto &data) { + return QString(); + }); + return std::make_pair(participantId, rank); + }) | ranges::views::filter([](const auto &pair) { + return peerIsUser(pair.first); + }); + for (const auto &[participantId, rank] : admins) { + Assert(peerIsUser(participantId)); + adding.emplace(peerToUser(participantId), rank); + } + if (channel->mgInfo->creator) { + adding.emplace( + peerToUser(channel->mgInfo->creator->id), + channel->mgInfo->creatorRank); + } + auto removing = channel->mgInfo->admins; + if (removing.empty() && adding.empty()) { + // Add some admin-placeholder so we don't DDOS + // server with admins list requests. + LOG(("API Error: Got empty admins list from server.")); + adding.emplace(0, QString()); + } + + Data::ChannelAdminChanges changes(channel); + for (const auto &[addingId, rank] : adding) { + if (!removing.remove(addingId)) { + changes.add(addingId, rank); + } + } + for (const auto &[removingId, rank] : removing) { + changes.remove(removingId); + } +} + +} // namespace + +ChatParticipants::ChatParticipants(not_null api) +: _session(&api->session()) +, _api(&api->instance()) { +} + +void ChatParticipants::requestForAdd( + not_null channel, + Fn callback) { + _channelMembersForAddCallback = std::move(callback); + if (_channelMembersForAdd == channel) { + return; + } + _api.request(base::take(_channelMembersForAddRequestId)).cancel(); + + const auto offset = 0; + const auto participantsHash = uint64(0); + + _channelMembersForAdd = channel; + _channelMembersForAddRequestId = _api.request(MTPchannels_GetParticipants( + channel->inputChannel, + MTP_channelParticipantsRecent(), + MTP_int(offset), + MTP_int(_session->serverConfig().chatSizeMax), + MTP_long(participantsHash) + )).done([=](const MTPchannels_ChannelParticipants &result) { + base::take(_channelMembersForAddRequestId); + base::take(_channelMembersForAdd); + base::take(_channelMembersForAddCallback)(result); + }).fail([=](const MTP::Error &error) { + base::take(_channelMembersForAddRequestId); + base::take(_channelMembersForAdd); + base::take(_channelMembersForAddCallback); + }).send(); +} + +void ChatParticipants::refreshChannelAdmins( + not_null channel, + const QVector &participants) { + Data::ChannelAdminChanges changes(channel); + for (const auto &p : participants) { + const auto participantId = p.match([]( + const MTPDchannelParticipantBanned &data) { + return peerFromMTP(data.vpeer()); + }, [](const MTPDchannelParticipantLeft &data) { + return peerFromMTP(data.vpeer()); + }, [](const auto &data) { + return peerFromUser(data.vuser_id()); + }); + const auto userId = peerToUser(participantId); + p.match([&](const MTPDchannelParticipantAdmin &data) { + Assert(peerIsUser(participantId)); + changes.add(userId, qs(data.vrank().value_or_empty())); + }, [&](const MTPDchannelParticipantCreator &data) { + Assert(peerIsUser(participantId)); + const auto rank = qs(data.vrank().value_or_empty()); + if (const auto info = channel->mgInfo.get()) { + info->creator = channel->owner().userLoaded(userId); + info->creatorRank = rank; + } + changes.add(userId, rank); + }, [&](const auto &data) { + if (userId) { + changes.remove(userId); + } + }); + } +} + +void ChatParticipants::requestLast(not_null channel) { + if (!channel->isMegagroup() + || _participantsRequests.contains(channel)) { + return; + } + + const auto offset = 0; + const auto participantsHash = uint64(0); + const auto requestId = _api.request(MTPchannels_GetParticipants( + channel->inputChannel, + MTP_channelParticipantsRecent(), + MTP_int(offset), + MTP_int(_session->serverConfig().chatSizeMax), + MTP_long(participantsHash) + )).done([=](const MTPchannels_ChannelParticipants &result) { + _participantsRequests.remove(channel); + parse(channel, result, [&]( + int availableCount, + const QVector &list) { + applyLastList( + channel, + availableCount, + list); + }); + }).fail([this, channel](const MTP::Error &error) { + _participantsRequests.remove(channel); + }).send(); + + _participantsRequests[channel] = requestId; +} + +void ChatParticipants::requestBots(not_null channel) { + if (!channel->isMegagroup() || _botsRequests.contains(channel)) { + return; + } + + const auto offset = 0; + const auto participantsHash = uint64(0); + const auto requestId = _api.request(MTPchannels_GetParticipants( + channel->inputChannel, + MTP_channelParticipantsBots(), + MTP_int(offset), + MTP_int(_session->serverConfig().chatSizeMax), + MTP_long(participantsHash) + )).done([=](const MTPchannels_ChannelParticipants &result) { + _botsRequests.remove(channel); + parse(channel, result, [&]( + int availableCount, + const QVector &list) { + applyBotsList( + channel, + availableCount, + list); + }); + }).fail([=](const MTP::Error &error) { + _botsRequests.remove(channel); + }).send(); + + _botsRequests[channel] = requestId; +} + +void ChatParticipants::requestAdmins(not_null channel) { + if (!channel->isMegagroup() || _adminsRequests.contains(channel)) { + return; + } + + const auto offset = 0; + const auto participantsHash = uint64(0); + const auto requestId = _api.request(MTPchannels_GetParticipants( + channel->inputChannel, + MTP_channelParticipantsAdmins(), + MTP_int(offset), + MTP_int(_session->serverConfig().chatSizeMax), + MTP_long(participantsHash) + )).done([=](const MTPchannels_ChannelParticipants &result) { + _adminsRequests.remove(channel); + result.match([&](const MTPDchannels_channelParticipants &data) { + ApplyMegagroupAdmins(channel, data); + }, [&](const MTPDchannels_channelParticipantsNotModified &) { + LOG(("API Error: channels.channelParticipantsNotModified received!")); + }); + }).fail([=](const MTP::Error &error) { + _adminsRequests.remove(channel); + }).send(); + + _adminsRequests[channel] = requestId; +} + +void ChatParticipants::requestCountDelayed( + not_null channel) { + _participantsCountRequestTimer.call( + kReloadChannelMembersTimeout, + [=] { channel->updateFullForced(); }); +} + +void ChatParticipants::add( + not_null peer, + const std::vector> &users, + Fn done) { + if (const auto chat = peer->asChat()) { + for (const auto &user : users) { + _api.request(MTPmessages_AddChatUser( + chat->inputChat, + user->inputUser, + MTP_int(kForwardMessagesOnAdd) + )).done([=](const MTPUpdates &result) { + _session->api().applyUpdates(result); + if (done) done(true); + }).fail([=](const MTP::Error &error) { + ShowAddParticipantsError(error.type(), peer, { 1, user }); + if (done) done(false); + }).afterDelay(kSmallDelayMs).send(); + } + } else if (const auto channel = peer->asChannel()) { + const auto hasBot = ranges::any_of(users, &UserData::isBot); + if (!peer->isMegagroup() && hasBot) { + ShowAddParticipantsError("USER_BOT", peer, users); + return; + } + auto list = QVector(); + list.reserve(std::min(int(users.size()), int(kMaxUsersPerInvite))); + const auto send = [&] { + const auto callback = base::take(done); + _api.request(MTPchannels_InviteToChannel( + channel->inputChannel, + MTP_vector(list) + )).done([=](const MTPUpdates &result) { + _session->api().applyUpdates(result); + requestCountDelayed(channel); + if (callback) callback(true); + }).fail([=](const MTP::Error &error) { + ShowAddParticipantsError(error.type(), peer, users); + if (callback) callback(false); + }).afterDelay(kSmallDelayMs).send(); + }; + for (const auto &user : users) { + list.push_back(user->inputUser); + if (list.size() == kMaxUsersPerInvite) { + send(); + list.clear(); + } + } + if (!list.empty()) { + send(); + } + } else { + Unexpected("User in ChatParticipants::add."); + } +} + +void ChatParticipants::parseRecent( + not_null channel, + const MTPchannels_ChannelParticipants &result, + Fn &list)> callbackList, + Fn callbackNotModified) { + parse(channel, result, [&]( + int availableCount, + const QVector &list) { + auto applyLast = channel->isMegagroup() + && (channel->mgInfo->lastParticipants.size() <= list.size()); + if (applyLast) { + applyLastList( + channel, + availableCount, + list); + } + if (callbackList) { + callbackList(availableCount, list); + } + }, std::move(callbackNotModified)); +} + +void ChatParticipants::parse( + not_null channel, + const MTPchannels_ChannelParticipants &result, + Fn &list)> callbackList, + Fn callbackNotModified) { + result.match([&](const MTPDchannels_channelParticipants &data) { + _session->data().processUsers(data.vusers()); + if (channel->mgInfo) { + refreshChannelAdmins(channel, data.vparticipants().v); + } + if (callbackList) { + callbackList(data.vcount().v, data.vparticipants().v); + } + }, [&](const MTPDchannels_channelParticipantsNotModified &) { + if (callbackNotModified) { + callbackNotModified(); + } else { + LOG(("API Error: " + "channels.channelParticipantsNotModified received!")); + } + }); +} + +void ChatParticipants::applyLastList( + not_null channel, + int availableCount, + const QVector &list) { + channel->mgInfo->lastAdmins.clear(); + channel->mgInfo->lastRestricted.clear(); + channel->mgInfo->lastParticipants.clear(); + channel->mgInfo->lastParticipantsStatus = MegagroupInfo::LastParticipantsUpToDate + | MegagroupInfo::LastParticipantsOnceReceived; + + auto botStatus = channel->mgInfo->botStatus; + for (const auto &p : list) { + const auto participantId = p.match([]( + const MTPDchannelParticipantBanned &data) { + return peerFromMTP(data.vpeer()); + }, [](const MTPDchannelParticipantLeft &data) { + return peerFromMTP(data.vpeer()); + }, [](const auto &data) { + return peerFromUser(data.vuser_id()); + }); + if (!participantId) { + continue; + } + const auto participant = _session->data().peer(participantId); + const auto user = participant->asUser(); + const auto adminCanEdit = (p.type() == mtpc_channelParticipantAdmin) + ? p.c_channelParticipantAdmin().is_can_edit() + : (p.type() == mtpc_channelParticipantCreator) + ? channel->amCreator() + : false; + const auto adminRights = (p.type() == mtpc_channelParticipantAdmin) + ? ChatAdminRightsInfo(p.c_channelParticipantAdmin().vadmin_rights()) + : (p.type() == mtpc_channelParticipantCreator) + ? ChatAdminRightsInfo(p.c_channelParticipantCreator().vadmin_rights()) + : ChatAdminRightsInfo(); + const auto restrictedRights = (p.type() == mtpc_channelParticipantBanned) + ? ChatRestrictionsInfo( + p.c_channelParticipantBanned().vbanned_rights()) + : ChatRestrictionsInfo(); + if (p.type() == mtpc_channelParticipantCreator) { + Assert(user != nullptr); + const auto &creator = p.c_channelParticipantCreator(); + const auto rank = qs(creator.vrank().value_or_empty()); + channel->mgInfo->creator = user; + channel->mgInfo->creatorRank = rank; + if (!channel->mgInfo->admins.empty()) { + Data::ChannelAdminChanges(channel).add( + peerToUser(participantId), + rank); + } + } + if (user + && !base::contains(channel->mgInfo->lastParticipants, user)) { + channel->mgInfo->lastParticipants.push_back(user); + if (adminRights.flags) { + channel->mgInfo->lastAdmins.emplace( + user, + MegagroupInfo::Admin{ adminRights, adminCanEdit }); + } else if (restrictedRights.flags) { + channel->mgInfo->lastRestricted.emplace( + user, + MegagroupInfo::Restricted{ restrictedRights }); + } + if (user->isBot()) { + channel->mgInfo->bots.insert(user); + if (channel->mgInfo->botStatus != 0 && channel->mgInfo->botStatus < 2) { + channel->mgInfo->botStatus = 2; + } + } + } + } + // + // getParticipants(Recent) sometimes can't return all members, + // only some last subset, size of this subset is availableCount. + // + // So both list size and availableCount have nothing to do with + // the full supergroup members count. + // + //if (list.isEmpty()) { + // channel->setMembersCount(channel->mgInfo->lastParticipants.size()); + //} else { + // channel->setMembersCount(availableCount); + //} + _session->changes().peerUpdated( + channel, + (Data::PeerUpdate::Flag::Members | Data::PeerUpdate::Flag::Admins)); + + channel->mgInfo->botStatus = botStatus; + _session->changes().peerUpdated( + channel, + Data::PeerUpdate::Flag::FullInfo); +} + +void ChatParticipants::applyBotsList( + not_null channel, + int availableCount, + const QVector &list) { + const auto history = _session->data().historyLoaded(channel); + channel->mgInfo->bots.clear(); + channel->mgInfo->botStatus = -1; + + auto needBotsInfos = false; + auto botStatus = channel->mgInfo->botStatus; + auto keyboardBotFound = !history || !history->lastKeyboardFrom; + for (const auto &p : list) { + const auto participantId = p.match([]( + const MTPDchannelParticipantBanned &data) { + return peerFromMTP(data.vpeer()); + }, [](const MTPDchannelParticipantLeft &data) { + return peerFromMTP(data.vpeer()); + }, [](const auto &data) { + return peerFromUser(data.vuser_id()); + }); + if (!participantId) { + continue; + } + + const auto participant = _session->data().peer(participantId); + const auto user = participant->asUser(); + if (user && user->isBot()) { + channel->mgInfo->bots.insert(user); + botStatus = 2;// (botStatus > 0/* || !i.key()->botInfo->readsAllHistory*/) ? 2 : 1; + if (!user->botInfo->inited) { + needBotsInfos = true; + } + } + if (!keyboardBotFound + && participant->id == history->lastKeyboardFrom) { + keyboardBotFound = true; + } + } + if (needBotsInfos) { + _session->api().requestFullPeer(channel); + } + if (!keyboardBotFound) { + history->clearLastKeyboard(); + } + + channel->mgInfo->botStatus = botStatus; + _session->changes().peerUpdated( + channel, + Data::PeerUpdate::Flag::FullInfo); +} + +void ChatParticipants::requestSelf(not_null channel) { + if (_selfParticipantRequests.contains(channel)) { + return; + } + + const auto finalize = [=]( + UserId inviter = -1, + TimeId inviteDate = 0, + bool inviteViaRequest = false) { + channel->inviter = inviter; + channel->inviteDate = inviteDate; + channel->inviteViaRequest = inviteViaRequest; + if (const auto history = _session->data().historyLoaded(channel)) { + if (history->lastMessageKnown()) { + history->checkLocalMessages(); + history->owner().sendHistoryChangeNotifications(); + } else { + history->owner().histories().requestDialogEntry(history); + } + } + }; + _selfParticipantRequests.emplace(channel); + _api.request(MTPchannels_GetParticipant( + channel->inputChannel, + MTP_inputPeerSelf() + )).done([=](const MTPchannels_ChannelParticipant &result) { + _selfParticipantRequests.erase(channel); + result.match([&](const MTPDchannels_channelParticipant &data) { + _session->data().processUsers(data.vusers()); + + const auto &participant = data.vparticipant(); + participant.match([&](const MTPDchannelParticipantSelf &data) { + finalize( + data.vinviter_id().v, + data.vdate().v, + data.is_via_request()); + }, [&](const MTPDchannelParticipantCreator &) { + if (channel->mgInfo) { + channel->mgInfo->creator = _session->user(); + } + finalize(_session->userId(), channel->date); + }, [&](const MTPDchannelParticipantAdmin &data) { + const auto inviter = data.is_self() + ? data.vinviter_id().value_or(-1) + : -1; + finalize(inviter, data.vdate().v); + }, [&](const MTPDchannelParticipantBanned &data) { + LOG(("API Error: Got self banned participant.")); + finalize(); + }, [&](const MTPDchannelParticipant &data) { + LOG(("API Error: Got self regular participant.")); + finalize(); + }, [&](const MTPDchannelParticipantLeft &data) { + LOG(("API Error: Got self left participant.")); + finalize(); + }); + }); + }).fail([=](const MTP::Error &error) { + _selfParticipantRequests.erase(channel); + if (error.type() == qstr("CHANNEL_PRIVATE")) { + channel->privateErrorReceived(); + } + finalize(); + }).afterDelay(kSmallDelayMs).send(); +} + +void ChatParticipants::kick( + not_null chat, + not_null participant) { + Expects(participant->isUser()); + + _api.request(MTPmessages_DeleteChatUser( + MTP_flags(0), + chat->inputChat, + participant->asUser()->inputUser + )).done([=](const MTPUpdates &result) { + _session->api().applyUpdates(result); + }).send(); +} + +void ChatParticipants::kick( + not_null channel, + not_null participant, + ChatRestrictionsInfo currentRights) { + const auto kick = KickRequest(channel, participant); + if (_kickRequests.contains(kick)) return; + + const auto rights = ChannelData::KickedRestrictedRights(participant); + const auto requestId = _api.request(MTPchannels_EditBanned( + channel->inputChannel, + participant->input, + MTP_chatBannedRights( + MTP_flags( + MTPDchatBannedRights::Flags::from_raw(uint32(rights.flags))), + MTP_int(rights.until)) + )).done([=](const MTPUpdates &result) { + _session->api().applyUpdates(result); + + _kickRequests.remove(KickRequest(channel, participant)); + channel->applyEditBanned(participant, currentRights, rights); + }).fail([this, kick](const MTP::Error &error) { + _kickRequests.remove(kick); + }).send(); + + _kickRequests.emplace(kick, requestId); +} + +void ChatParticipants::unblock( + not_null channel, + not_null participant) { + const auto kick = KickRequest(channel, participant); + if (_kickRequests.contains(kick)) { + return; + } + + const auto requestId = _api.request(MTPchannels_EditBanned( + channel->inputChannel, + participant->input, + MTP_chatBannedRights(MTP_flags(0), MTP_int(0)) + )).done([=](const MTPUpdates &result) { + _session->api().applyUpdates(result); + + _kickRequests.remove(KickRequest(channel, participant)); + if (channel->kickedCount() > 0) { + channel->setKickedCount(channel->kickedCount() - 1); + } else { + channel->updateFullForced(); + } + }).fail([=](const MTP::Error &error) { + _kickRequests.remove(kick); + }).send(); + + _kickRequests.emplace(kick, requestId); +} + +} // namespace Api diff --git a/Telegram/SourceFiles/api/api_chat_participants.h b/Telegram/SourceFiles/api/api_chat_participants.h new file mode 100644 index 000000000..6794c4db2 --- /dev/null +++ b/Telegram/SourceFiles/api/api_chat_participants.h @@ -0,0 +1,107 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "mtproto/sender.h" +#include "base/timer.h" + +class ApiWrap; +class ChannelData; + +struct ChatRestrictionsInfo; + +namespace Main { +class Session; +} // namespace Main + +namespace Api { + +class ChatParticipants final { +public: + explicit ChatParticipants(not_null api); + + void requestLast(not_null channel); + void requestBots(not_null channel); + void requestAdmins(not_null channel); + void requestCountDelayed(not_null channel); + + void parse( + not_null channel, + const MTPchannels_ChannelParticipants &result, + Fn &list)> callbackList, + Fn callbackNotModified = nullptr); + void parseRecent( + not_null channel, + const MTPchannels_ChannelParticipants &result, + Fn &list)> callbackList = nullptr, + Fn callbackNotModified = nullptr); + void add( + not_null peer, + const std::vector> &users, + Fn done = nullptr); + + void requestSelf(not_null channel); + + void requestForAdd( + not_null channel, + Fn callback); + + void kick( + not_null chat, + not_null participant); + void kick( + not_null channel, + not_null participant, + ChatRestrictionsInfo currentRights); + void unblock( + not_null channel, + not_null participant); + +private: + void applyLastList( + not_null channel, + int availableCount, + const QVector &list); + void applyBotsList( + not_null channel, + int availableCount, + const QVector &list); + + void refreshChannelAdmins( + not_null channel, + const QVector &participants); + + const not_null _session; + MTP::Sender _api; + + using PeerRequests = base::flat_map; + + PeerRequests _participantsRequests; + PeerRequests _botsRequests; + PeerRequests _adminsRequests; + base::DelayedCallTimer _participantsCountRequestTimer; + + ChannelData *_channelMembersForAdd = nullptr; + mtpRequestId _channelMembersForAddRequestId = 0; + Fn _channelMembersForAddCallback; + + base::flat_set> _selfParticipantRequests; + + using KickRequest = std::pair< + not_null, + not_null>; + base::flat_map _kickRequests; + +}; + +} // namespace Api diff --git a/Telegram/SourceFiles/api/api_invite_links.cpp b/Telegram/SourceFiles/api/api_invite_links.cpp index d3d1d4c85..d53c3857e 100644 --- a/Telegram/SourceFiles/api/api_invite_links.cpp +++ b/Telegram/SourceFiles/api/api_invite_links.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_invite_links.h" +#include "api/api_chat_participants.h" #include "data/data_peer.h" #include "data/data_user.h" #include "data/data_chat.h" @@ -478,7 +479,7 @@ void InviteLinks::processRequest( ++chat->count; } } else if (const auto channel = peer->asChannel()) { - _api->requestParticipantsCountDelayed(channel); + _api->chatParticipants().requestCountDelayed(channel); } _api->applyUpdates(result); if (link.isEmpty() && approved) { diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp index 68701250f..ffefc85de 100644 --- a/Telegram/SourceFiles/api/api_updates.cpp +++ b/Telegram/SourceFiles/api/api_updates.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_updates.h" #include "api/api_authorizations.h" +#include "api/api_chat_participants.h" #include "api/api_text_entities.h" #include "api/api_user_privacy.h" #include "main/main_session.h" @@ -1498,7 +1499,7 @@ void Updates::feedUpdate(const MTPUpdate &update) { if (channel->mgInfo->lastParticipants.size() < _session->serverConfig().chatSizeMax && (channel->mgInfo->lastParticipants.empty() || channel->mgInfo->lastParticipants.size() < channel->membersCount())) { - session().api().requestLastParticipants(channel); + session().api().chatParticipants().requestLast(channel); } } @@ -2127,7 +2128,7 @@ void Updates::feedUpdate(const MTPUpdate &update) { history->owner().histories().requestDialogEntry(history); } if (!channel->amCreator()) { - session().api().requestSelfParticipant(channel); + session().api().chatParticipants().requestSelf(channel); } } } diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 0f2af9379..d5936b946 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_authorizations.h" #include "api/api_attached_stickers.h" #include "api/api_blocked_peers.h" +#include "api/api_chat_participants.h" #include "api/api_cloud_password.h" #include "api/api_hash.h" #include "api/api_invite_links.h" @@ -89,19 +90,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace { -// 1 second wait before reload members in channel after adding. -constexpr auto kReloadChannelMembersTimeout = 1000; - // Save draft to the cloud with 1 sec extra delay. constexpr auto kSaveCloudDraftTimeout = 1000; -// Max users in one super group invite request. -constexpr auto kMaxUsersPerInvite = 100; - -// How many messages from chat history server should forward to user, -// that was added to this chat. -constexpr auto kForwardMessagesOnAdd = 100; - constexpr auto kTopPromotionInterval = TimeId(60 * 60); constexpr auto kTopPromotionMinDelay = TimeId(10); constexpr auto kSmallDelayMs = 5; @@ -150,7 +141,8 @@ ApiWrap::ApiWrap(not_null session) , _views(std::make_unique(this)) , _confirmPhone(std::make_unique(this)) , _peerPhoto(std::make_unique(this)) -, _polls(std::make_unique(this)) { +, _polls(std::make_unique(this)) +, _chatParticipants(std::make_unique(this)) { crl::on_main(session, [=] { // You can't use _session->lifetime() in the constructor, // only queued, because it is not constructed yet. @@ -1390,373 +1382,6 @@ void ApiWrap::requestPeers(const QList &peers) { } } -void ApiWrap::requestLastParticipants(not_null channel) { - if (!channel->isMegagroup() - || _participantsRequests.contains(channel)) { - return; - } - - const auto offset = 0; - const auto participantsHash = uint64(0); - const auto requestId = request(MTPchannels_GetParticipants( - channel->inputChannel, - MTP_channelParticipantsRecent(), - MTP_int(offset), - MTP_int(_session->serverConfig().chatSizeMax), - MTP_long(participantsHash) - )).done([=](const MTPchannels_ChannelParticipants &result) { - _participantsRequests.remove(channel); - parseChannelParticipants(channel, result, [&]( - int availableCount, - const QVector &list) { - applyLastParticipantsList( - channel, - availableCount, - list); - }); - }).fail([this, channel](const MTP::Error &error) { - _participantsRequests.remove(channel); - }).send(); - - _participantsRequests.insert(channel, requestId); -} - -void ApiWrap::requestBots(not_null channel) { - if (!channel->isMegagroup() || _botsRequests.contains(channel)) { - return; - } - - const auto offset = 0; - const auto participantsHash = uint64(0); - const auto requestId = request(MTPchannels_GetParticipants( - channel->inputChannel, - MTP_channelParticipantsBots(), - MTP_int(offset), - MTP_int(_session->serverConfig().chatSizeMax), - MTP_long(participantsHash) - )).done([=](const MTPchannels_ChannelParticipants &result) { - _botsRequests.remove(channel); - parseChannelParticipants(channel, result, [&]( - int availableCount, - const QVector &list) { - applyBotsList( - channel, - availableCount, - list); - }); - }).fail([=](const MTP::Error &error) { - _botsRequests.remove(channel); - }).send(); - - _botsRequests.insert(channel, requestId); -} - -void ApiWrap::requestAdmins(not_null channel) { - if (!channel->isMegagroup() || _adminsRequests.contains(channel)) { - return; - } - - const auto offset = 0; - const auto participantsHash = uint64(0); - const auto requestId = request(MTPchannels_GetParticipants( - channel->inputChannel, - MTP_channelParticipantsAdmins(), - MTP_int(offset), - MTP_int(_session->serverConfig().chatSizeMax), - MTP_long(participantsHash) - )).done([=](const MTPchannels_ChannelParticipants &result) { - _adminsRequests.remove(channel); - result.match([&](const MTPDchannels_channelParticipants &data) { - Data::ApplyMegagroupAdmins(channel, data); - }, [&](const MTPDchannels_channelParticipantsNotModified &) { - LOG(("API Error: channels.channelParticipantsNotModified received!")); - }); - }).fail([=](const MTP::Error &error) { - _adminsRequests.remove(channel); - }).send(); - - _adminsRequests.insert(channel, requestId); -} - -void ApiWrap::applyLastParticipantsList( - not_null channel, - int availableCount, - const QVector &list) { - channel->mgInfo->lastAdmins.clear(); - channel->mgInfo->lastRestricted.clear(); - channel->mgInfo->lastParticipants.clear(); - channel->mgInfo->lastParticipantsStatus = MegagroupInfo::LastParticipantsUpToDate - | MegagroupInfo::LastParticipantsOnceReceived; - - auto botStatus = channel->mgInfo->botStatus; - for (const auto &p : list) { - const auto participantId = p.match([]( - const MTPDchannelParticipantBanned &data) { - return peerFromMTP(data.vpeer()); - }, [](const MTPDchannelParticipantLeft &data) { - return peerFromMTP(data.vpeer()); - }, [](const auto &data) { - return peerFromUser(data.vuser_id()); - }); - if (!participantId) { - continue; - } - const auto participant = _session->data().peer(participantId); - const auto user = participant->asUser(); - const auto adminCanEdit = (p.type() == mtpc_channelParticipantAdmin) - ? p.c_channelParticipantAdmin().is_can_edit() - : (p.type() == mtpc_channelParticipantCreator) - ? channel->amCreator() - : false; - const auto adminRights = (p.type() == mtpc_channelParticipantAdmin) - ? ChatAdminRightsInfo(p.c_channelParticipantAdmin().vadmin_rights()) - : (p.type() == mtpc_channelParticipantCreator) - ? ChatAdminRightsInfo(p.c_channelParticipantCreator().vadmin_rights()) - : ChatAdminRightsInfo(); - const auto restrictedRights = (p.type() == mtpc_channelParticipantBanned) - ? ChatRestrictionsInfo( - p.c_channelParticipantBanned().vbanned_rights()) - : ChatRestrictionsInfo(); - if (p.type() == mtpc_channelParticipantCreator) { - Assert(user != nullptr); - const auto &creator = p.c_channelParticipantCreator(); - const auto rank = qs(creator.vrank().value_or_empty()); - channel->mgInfo->creator = user; - channel->mgInfo->creatorRank = rank; - if (!channel->mgInfo->admins.empty()) { - Data::ChannelAdminChanges(channel).add( - peerToUser(participantId), - rank); - } - } - if (user - && !base::contains(channel->mgInfo->lastParticipants, user)) { - channel->mgInfo->lastParticipants.push_back(user); - if (adminRights.flags) { - channel->mgInfo->lastAdmins.emplace( - user, - MegagroupInfo::Admin{ adminRights, adminCanEdit }); - } else if (restrictedRights.flags) { - channel->mgInfo->lastRestricted.emplace( - user, - MegagroupInfo::Restricted{ restrictedRights }); - } - if (user->isBot()) { - channel->mgInfo->bots.insert(user); - if (channel->mgInfo->botStatus != 0 && channel->mgInfo->botStatus < 2) { - channel->mgInfo->botStatus = 2; - } - } - } - } - // - // getParticipants(Recent) sometimes can't return all members, - // only some last subset, size of this subset is availableCount. - // - // So both list size and availableCount have nothing to do with - // the full supergroup members count. - // - //if (list.isEmpty()) { - // channel->setMembersCount(channel->mgInfo->lastParticipants.size()); - //} else { - // channel->setMembersCount(availableCount); - //} - session().changes().peerUpdated( - channel, - (Data::PeerUpdate::Flag::Members | Data::PeerUpdate::Flag::Admins)); - - channel->mgInfo->botStatus = botStatus; - _session->changes().peerUpdated( - channel, - Data::PeerUpdate::Flag::FullInfo); -} - -void ApiWrap::applyBotsList( - not_null channel, - int availableCount, - const QVector &list) { - const auto history = _session->data().historyLoaded(channel); - channel->mgInfo->bots.clear(); - channel->mgInfo->botStatus = -1; - - auto needBotsInfos = false; - auto botStatus = channel->mgInfo->botStatus; - auto keyboardBotFound = !history || !history->lastKeyboardFrom; - for (const auto &p : list) { - const auto participantId = p.match([]( - const MTPDchannelParticipantBanned &data) { - return peerFromMTP(data.vpeer()); - }, [](const MTPDchannelParticipantLeft &data) { - return peerFromMTP(data.vpeer()); - }, [](const auto &data) { - return peerFromUser(data.vuser_id()); - }); - if (!participantId) { - continue; - } - - const auto participant = _session->data().peer(participantId); - const auto user = participant->asUser(); - if (user && user->isBot()) { - channel->mgInfo->bots.insert(user); - botStatus = 2;// (botStatus > 0/* || !i.key()->botInfo->readsAllHistory*/) ? 2 : 1; - if (!user->botInfo->inited) { - needBotsInfos = true; - } - } - if (!keyboardBotFound - && participant->id == history->lastKeyboardFrom) { - keyboardBotFound = true; - } - } - if (needBotsInfos) { - requestFullPeer(channel); - } - if (!keyboardBotFound) { - history->clearLastKeyboard(); - } - - channel->mgInfo->botStatus = botStatus; - _session->changes().peerUpdated( - channel, - Data::PeerUpdate::Flag::FullInfo); -} - -void ApiWrap::requestSelfParticipant(not_null channel) { - if (_selfParticipantRequests.contains(channel)) { - return; - } - - const auto finalize = [=]( - UserId inviter = -1, - TimeId inviteDate = 0, - bool inviteViaRequest = false) { - channel->inviter = inviter; - channel->inviteDate = inviteDate; - channel->inviteViaRequest = inviteViaRequest; - if (const auto history = _session->data().historyLoaded(channel)) { - if (history->lastMessageKnown()) { - history->checkLocalMessages(); - history->owner().sendHistoryChangeNotifications(); - } else { - history->owner().histories().requestDialogEntry(history); - } - } - }; - _selfParticipantRequests.emplace(channel); - request(MTPchannels_GetParticipant( - channel->inputChannel, - MTP_inputPeerSelf() - )).done([=](const MTPchannels_ChannelParticipant &result) { - _selfParticipantRequests.erase(channel); - result.match([&](const MTPDchannels_channelParticipant &data) { - _session->data().processUsers(data.vusers()); - - const auto &participant = data.vparticipant(); - participant.match([&](const MTPDchannelParticipantSelf &data) { - finalize( - data.vinviter_id().v, - data.vdate().v, - data.is_via_request()); - }, [&](const MTPDchannelParticipantCreator &) { - if (channel->mgInfo) { - channel->mgInfo->creator = _session->user(); - } - finalize(_session->userId(), channel->date); - }, [&](const MTPDchannelParticipantAdmin &data) { - const auto inviter = data.is_self() - ? data.vinviter_id().value_or(-1) - : -1; - finalize(inviter, data.vdate().v); - }, [&](const MTPDchannelParticipantBanned &data) { - LOG(("API Error: Got self banned participant.")); - finalize(); - }, [&](const MTPDchannelParticipant &data) { - LOG(("API Error: Got self regular participant.")); - finalize(); - }, [&](const MTPDchannelParticipantLeft &data) { - LOG(("API Error: Got self left participant.")); - finalize(); - }); - }); - }).fail([=](const MTP::Error &error) { - _selfParticipantRequests.erase(channel); - if (error.type() == qstr("CHANNEL_PRIVATE")) { - channel->privateErrorReceived(); - } - finalize(); - }).afterDelay(kSmallDelayMs).send(); -} - -void ApiWrap::kickParticipant( - not_null chat, - not_null participant) { - Expects(participant->isUser()); - - request(MTPmessages_DeleteChatUser( - MTP_flags(0), - chat->inputChat, - participant->asUser()->inputUser - )).done([=](const MTPUpdates &result) { - applyUpdates(result); - }).send(); -} - -void ApiWrap::kickParticipant( - not_null channel, - not_null participant, - ChatRestrictionsInfo currentRights) { - const auto kick = KickRequest(channel, participant); - if (_kickRequests.contains(kick)) return; - - const auto rights = ChannelData::KickedRestrictedRights(participant); - const auto requestId = request(MTPchannels_EditBanned( - channel->inputChannel, - participant->input, - MTP_chatBannedRights( - MTP_flags( - MTPDchatBannedRights::Flags::from_raw(uint32(rights.flags))), - MTP_int(rights.until)) - )).done([=](const MTPUpdates &result) { - applyUpdates(result); - - _kickRequests.remove(KickRequest(channel, participant)); - channel->applyEditBanned(participant, currentRights, rights); - }).fail([this, kick](const MTP::Error &error) { - _kickRequests.remove(kick); - }).send(); - - _kickRequests.emplace(kick, requestId); -} - -void ApiWrap::unblockParticipant( - not_null channel, - not_null participant) { - const auto kick = KickRequest(channel, participant); - if (_kickRequests.contains(kick)) { - return; - } - - const auto requestId = request(MTPchannels_EditBanned( - channel->inputChannel, - participant->input, - MTP_chatBannedRights(MTP_flags(0), MTP_int(0)) - )).done([=](const MTPUpdates &result) { - applyUpdates(result); - - _kickRequests.remove(KickRequest(channel, participant)); - if (channel->kickedCount() > 0) { - channel->setKickedCount(channel->kickedCount() - 1); - } else { - channel->updateFullForced(); - } - }).fail([=](const MTP::Error &error) { - _kickRequests.remove(kick); - }).send(); - - _kickRequests.emplace(kick, requestId); -} - void ApiWrap::deleteAllFromParticipant( not_null channel, not_null from) { @@ -1792,36 +1417,6 @@ void ApiWrap::deleteAllFromParticipantSend( }).send(); } -void ApiWrap::requestChannelMembersForAdd( - not_null channel, - Fn callback) { - _channelMembersForAddCallback = std::move(callback); - if (_channelMembersForAdd == channel) { - return; - } - request(base::take(_channelMembersForAddRequestId)).cancel(); - - const auto offset = 0; - const auto participantsHash = uint64(0); - - _channelMembersForAdd = channel; - _channelMembersForAddRequestId = request(MTPchannels_GetParticipants( - channel->inputChannel, - MTP_channelParticipantsRecent(), - MTP_int(offset), - MTP_int(_session->serverConfig().chatSizeMax), - MTP_long(participantsHash) - )).done([=](const MTPchannels_ChannelParticipants &result) { - base::take(_channelMembersForAddRequestId); - base::take(_channelMembersForAdd); - base::take(_channelMembersForAddCallback)(result); - }).fail([=](const MTP::Error &error) { - base::take(_channelMembersForAddRequestId); - base::take(_channelMembersForAdd); - base::take(_channelMembersForAddCallback); - }).send(); -} - void ApiWrap::scheduleStickerSetRequest(uint64 setId, uint64 access) { if (!_stickerSetRequests.contains(setId)) { _stickerSetRequests.insert(setId, qMakePair(access, 0)); @@ -2700,13 +2295,6 @@ void ApiWrap::resolveWebPages() { } } -void ApiWrap::requestParticipantsCountDelayed( - not_null channel) { - _participantsCountRequestTimer.call( - kReloadChannelMembersTimeout, - [=] { channel->updateFullForced(); }); -} - template void ApiWrap::requestFileReference( Data::FileOrigin origin, @@ -3220,88 +2808,6 @@ void ApiWrap::readFeaturedSets() { } } -void ApiWrap::parseChannelParticipants( - not_null channel, - const MTPchannels_ChannelParticipants &result, - Fn &list)> callbackList, - Fn callbackNotModified) { - result.match([&](const MTPDchannels_channelParticipants &data) { - _session->data().processUsers(data.vusers()); - if (channel->mgInfo) { - refreshChannelAdmins(channel, data.vparticipants().v); - } - if (callbackList) { - callbackList(data.vcount().v, data.vparticipants().v); - } - }, [&](const MTPDchannels_channelParticipantsNotModified &) { - if (callbackNotModified) { - callbackNotModified(); - } else { - LOG(("API Error: " - "channels.channelParticipantsNotModified received!")); - } - }); -} - -void ApiWrap::refreshChannelAdmins( - not_null channel, - const QVector &participants) { - Data::ChannelAdminChanges changes(channel); - for (const auto &p : participants) { - const auto participantId = p.match([]( - const MTPDchannelParticipantBanned &data) { - return peerFromMTP(data.vpeer()); - }, [](const MTPDchannelParticipantLeft &data) { - return peerFromMTP(data.vpeer()); - }, [](const auto &data) { - return peerFromUser(data.vuser_id()); - }); - const auto userId = peerToUser(participantId); - p.match([&](const MTPDchannelParticipantAdmin &data) { - Assert(peerIsUser(participantId)); - changes.add(userId, qs(data.vrank().value_or_empty())); - }, [&](const MTPDchannelParticipantCreator &data) { - Assert(peerIsUser(participantId)); - const auto rank = qs(data.vrank().value_or_empty()); - if (const auto info = channel->mgInfo.get()) { - info->creator = channel->owner().userLoaded(userId); - info->creatorRank = rank; - } - changes.add(userId, rank); - }, [&](const auto &data) { - if (userId) { - changes.remove(userId); - } - }); - } -} - -void ApiWrap::parseRecentChannelParticipants( - not_null channel, - const MTPchannels_ChannelParticipants &result, - Fn &list)> callbackList, - Fn callbackNotModified) { - parseChannelParticipants(channel, result, [&]( - int availableCount, - const QVector &list) { - auto applyLast = channel->isMegagroup() - && (channel->mgInfo->lastParticipants.size() <= list.size()); - if (applyLast) { - applyLastParticipantsList( - channel, - availableCount, - list); - } - if (callbackList) { - callbackList(availableCount, list); - } - }, std::move(callbackNotModified)); -} - void ApiWrap::jumpToDate(Dialogs::Key chat, const QDate &date) { if (const auto peer = chat.peer()) { jumpToHistoryDate(peer, date); @@ -3439,61 +2945,6 @@ void ApiWrap::checkForUnreadMentions( } } -void ApiWrap::addChatParticipants( - not_null peer, - const std::vector> &users, - Fn done) { - if (const auto chat = peer->asChat()) { - for (const auto &user : users) { - request(MTPmessages_AddChatUser( - chat->inputChat, - user->inputUser, - MTP_int(kForwardMessagesOnAdd) - )).done([=](const MTPUpdates &result) { - applyUpdates(result); - if (done) done(true); - }).fail([=](const MTP::Error &error) { - ShowAddParticipantsError(error.type(), peer, { 1, user }); - if (done) done(false); - }).afterDelay(crl::time(5)).send(); - } - } else if (const auto channel = peer->asChannel()) { - const auto hasBot = ranges::any_of(users, &UserData::isBot); - if (!peer->isMegagroup() && hasBot) { - ShowAddParticipantsError("USER_BOT", peer, users); - return; - } - auto list = QVector(); - list.reserve(qMin(int(users.size()), int(kMaxUsersPerInvite))); - const auto send = [&] { - const auto callback = base::take(done); - request(MTPchannels_InviteToChannel( - channel->inputChannel, - MTP_vector(list) - )).done([=](const MTPUpdates &result) { - applyUpdates(result); - requestParticipantsCountDelayed(channel); - if (callback) callback(true); - }).fail([=](const MTP::Error &error) { - ShowAddParticipantsError(error.type(), peer, users); - if (callback) callback(false); - }).afterDelay(crl::time(5)).send(); - }; - for (const auto &user : users) { - list.push_back(user->inputUser); - if (list.size() == kMaxUsersPerInvite) { - send(); - list.clear(); - } - } - if (!list.empty()) { - send(); - } - } else { - Unexpected("User in ApiWrap::addChatParticipants."); - } -} - void ApiWrap::requestSharedMediaCount( not_null peer, Storage::SharedMediaType type) { @@ -4690,3 +4141,7 @@ Api::PeerPhoto &ApiWrap::peerPhoto() { Api::Polls &ApiWrap::polls() { return *_polls; } + +Api::ChatParticipants &ApiWrap::chatParticipants() { + return *_chatParticipants; +} diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index e9d60ff0a..80d109eff 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -66,6 +66,7 @@ class ViewsManager; class ConfirmPhone; class PeerPhoto; class Polls; +class ChatParticipants; namespace details { @@ -172,10 +173,6 @@ public: void requestPeer(not_null peer); void requestPeers(const QList &peers); void requestPeerSettings(not_null peer); - void requestLastParticipants(not_null channel); - void requestBots(not_null channel); - void requestAdmins(not_null channel); - void requestParticipantsCountDelayed(not_null channel); using UpdatedFileReferences = Data::UpdatedFileReferences; using FileReferencesHandler = FnMut; @@ -204,9 +201,6 @@ public: Fn fail); void importChatInvite(const QString &hash, bool isGroup); - void requestChannelMembersForAdd( - not_null channel, - Fn callback); void processFullPeer( not_null peer, const MTPmessages_ChatFull &result); @@ -219,17 +213,6 @@ public: void markMediaRead(const base::flat_set> &items); void markMediaRead(not_null item); - void requestSelfParticipant(not_null channel); - void kickParticipant( - not_null chat, - not_null participant); - void kickParticipant( - not_null channel, - not_null participant, - ChatRestrictionsInfo currentRights); - void unblockParticipant( - not_null channel, - not_null participant); void deleteAllFromParticipant( not_null channel, not_null from); @@ -292,25 +275,6 @@ public: void readFeaturedSetDelayed(uint64 setId); - void parseChannelParticipants( - not_null channel, - const MTPchannels_ChannelParticipants &result, - Fn &list)> callbackList, - Fn callbackNotModified = nullptr); - void parseRecentChannelParticipants( - not_null channel, - const MTPchannels_ChannelParticipants &result, - Fn &list)> callbackList = nullptr, - Fn callbackNotModified = nullptr); - void addChatParticipants( - not_null peer, - const std::vector> &users, - Fn done = nullptr); - rpl::producer sendActions() const { return _sendActions.events(); } @@ -395,6 +359,7 @@ public: [[nodiscard]] Api::ConfirmPhone &confirmPhone(); [[nodiscard]] Api::PeerPhoto &peerPhoto(); [[nodiscard]] Api::Polls &polls(); + [[nodiscard]] Api::ChatParticipants &chatParticipants(); void updatePrivacyLastSeens(); @@ -458,14 +423,6 @@ private: not_null user, const MTPusers_UserFull &result, mtpRequestId req); - void applyLastParticipantsList( - not_null channel, - int availableCount, - const QVector &list); - void applyBotsList( - not_null channel, - int availableCount, - const QVector &list); void resolveWebPages(); void gotWebPages( ChannelData *channel, @@ -482,10 +439,6 @@ private: void requestSavedGifs(TimeId now); void readFeaturedSets(); - void refreshChannelAdmins( - not_null channel, - const QVector &participants); - void jumpToHistoryDate(not_null peer, const QDate &date); template void requestMessageAfterDate( @@ -576,26 +529,10 @@ private: PeerRequests _peerRequests; base::flat_set> _requestedPeerSettings; - PeerRequests _participantsRequests; - PeerRequests _botsRequests; - PeerRequests _adminsRequests; - base::DelayedCallTimer _participantsCountRequestTimer; - - ChannelData *_channelMembersForAdd = nullptr; - mtpRequestId _channelMembersForAddRequestId = 0; - Fn _channelMembersForAddCallback; base::flat_map< not_null, std::pair>> _historyArchivedRequests; - using KickRequest = std::pair< - not_null, - not_null>; - base::flat_map _kickRequests; - - base::flat_set> _selfParticipantRequests; - QMap _webPagesPending; base::Timer _webPagesTimer; @@ -702,6 +639,7 @@ private: const std::unique_ptr _confirmPhone; const std::unique_ptr _peerPhoto; const std::unique_ptr _polls; + const std::unique_ptr _chatParticipants; mtpRequestId _wallPaperRequestId = 0; QString _wallPaperSlug; diff --git a/Telegram/SourceFiles/boxes/delete_messages_box.cpp b/Telegram/SourceFiles/boxes/delete_messages_box.cpp index bcfd3ae27..30c33f7c6 100644 --- a/Telegram/SourceFiles/boxes/delete_messages_box.cpp +++ b/Telegram/SourceFiles/boxes/delete_messages_box.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/delete_messages_box.h" #include "apiwrap.h" +#include "api/api_chat_participants.h" #include "base/unixtime.h" #include "data/data_channel.h" #include "data/data_chat.h" @@ -478,7 +479,7 @@ void DeleteMessagesBox::deleteAndClear() { } if (_moderateFrom) { if (_banUser && _banUser->checked()) { - _moderateInChannel->session().api().kickParticipant( + _moderateInChannel->session().api().chatParticipants().kick( _moderateInChannel, _moderateFrom, ChatRestrictionsInfo()); diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp index 39aacbd06..2a189f214 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "boxes/peer_list_controllers.h" +#include "api/api_chat_participants.h" #include "base/random.h" #include "ui/boxes/confirm_box.h" #include "ui/widgets/checkbox.h" @@ -71,7 +72,7 @@ void AddBotToGroup(not_null bot, not_null chat) { if (bot->isBot() && !bot->botInfo->startGroupToken.isEmpty()) { chat->session().api().sendBotStart(bot, chat); } else { - chat->session().api().addChatParticipants(chat, { 1, bot }); + chat->session().api().chatParticipants().add(chat, { 1, bot }); } Ui::hideLayer(); Ui::showPeerHistory(chat, ShowAtUnreadMsgId); diff --git a/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp b/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp index aa41ff240..e12ff3d1a 100644 --- a/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "boxes/peers/add_participants_box.h" +#include "api/api_chat_participants.h" #include "boxes/peers/edit_participant_box.h" #include "boxes/peers/edit_peer_type_box.h" #include "ui/boxes/confirm_box.h" @@ -231,7 +232,7 @@ bool AddParticipantsBoxController::inviteSelectedUsers( if (users.empty()) { return false; } - _peer->session().api().addChatParticipants(_peer, users); + _peer->session().api().chatParticipants().add(_peer, users); return true; } @@ -465,7 +466,7 @@ void AddSpecialBoxController::loadMoreRows() { )).done([=](const MTPchannels_ChannelParticipants &result) { _loadRequestId = 0; auto &session = channel->session(); - session.api().parseChannelParticipants(channel, result, [&]( + session.api().chatParticipants().parse(channel, result, [&]( int availableCount, const QVector &list) { for (const auto &data : list) { @@ -977,7 +978,7 @@ void AddSpecialBoxSearchController::searchParticipantsDone( _participantsQueries.erase(it); } }; - channel->session().api().parseChannelParticipants( + channel->session().api().chatParticipants().parse( channel, result, addToCache); diff --git a/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp index dcdb409b1..59b1d0f26 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "boxes/peers/edit_participants_box.h" +#include "api/api_chat_participants.h" #include "boxes/peer_list_controllers.h" #include "boxes/peers/edit_participant_box.h" #include "boxes/peers/add_participants_box.h" @@ -1396,12 +1397,12 @@ void ParticipantsBoxController::loadMoreRows() { && (_role == Role::Members || _role == Role::Profile); auto parseParticipants = [&](auto &&result, auto &&callback) { if (wasRecentRequest) { - channel->session().api().parseRecentChannelParticipants( + channel->session().api().chatParticipants().parseRecent( channel, result, callback); } else { - channel->session().api().parseChannelParticipants( + channel->session().api().chatParticipants().parse( channel, result, callback); @@ -1732,7 +1733,7 @@ void ParticipantsBoxController::unkickParticipant(not_null user) { delegate()->peerListRemoveRow(row); delegate()->peerListRefreshRows(); } - _peer->session().api().addChatParticipants(_peer, { 1, user }); + _peer->session().api().chatParticipants().add(_peer, { 1, user }); } void ParticipantsBoxController::kickParticipantSure( @@ -1750,9 +1751,12 @@ void ParticipantsBoxController::kickParticipantSure( } auto &session = _peer->session(); if (const auto chat = _peer->asChat()) { - session.api().kickParticipant(chat, participant); + session.api().chatParticipants().kick(chat, participant); } else if (const auto channel = _peer->asChannel()) { - session.api().kickParticipant(channel, participant, currentRights); + session.api().chatParticipants().kick( + channel, + participant, + currentRights); } } @@ -1803,7 +1807,9 @@ void ParticipantsBoxController::removeKickedWithRow( void ParticipantsBoxController::removeKicked( not_null participant) { if (const auto channel = _peer->asChannel()) { - channel->session().api().unblockParticipant(channel, participant); + channel->session().api().chatParticipants().unblock( + channel, + participant); } } @@ -2010,7 +2016,7 @@ void ParticipantsBoxController::subscribeToCreatorChange( channel->mgInfo->lastAdmins.clear(); channel->mgInfo->lastRestricted.clear(); channel->mgInfo->lastParticipants.clear(); - api->parseRecentChannelParticipants(channel, result); + api->chatParticipants().parseRecent(channel, result); if (weak) { fullListRefresh(); } @@ -2175,7 +2181,7 @@ void ParticipantsBoxSearchController::searchDone( _queries.erase(it); } }; - _channel->session().api().parseChannelParticipants( + _channel->session().api().chatParticipants().parse( _channel, result, addToCache); diff --git a/Telegram/SourceFiles/calls/group/calls_group_invite_controller.cpp b/Telegram/SourceFiles/calls/group/calls_group_invite_controller.cpp index 74aecd992..d8ed2c237 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_invite_controller.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_invite_controller.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "calls/group/calls_group_invite_controller.h" +#include "api/api_chat_participants.h" #include "calls/group/calls_group_call.h" #include "calls/group/calls_group_menu.h" #include "boxes/peer_lists_box.h" @@ -221,7 +222,7 @@ object_ptr PrepareInviteBox( const std::vector> &users, const std::vector> &nonMembers, Fn finish) { - peer->session().api().addChatParticipants( + peer->session().api().chatParticipants().add( peer, nonMembers, [=](bool) { invite(users); finish(); }); diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp index 870d0c6df..f0248ed7d 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp @@ -49,7 +49,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/unixtime.h" #include "base/qt_signal_producer.h" #include "base/timer_rpl.h" -#include "apiwrap.h" // api().kickParticipant. +#include "apiwrap.h" // api().kick. +#include "api/api_chat_participants.h" // api().kick. #include "webrtc/webrtc_video_track.h" #include "webrtc/webrtc_media_devices.h" // UniqueDesktopCaptureSource. #include "webrtc/webrtc_audio_input_tester.h" @@ -1344,7 +1345,7 @@ void Panel::showBox( void Panel::kickParticipantSure(not_null participantPeer) { if (const auto chat = _peer->asChat()) { - chat->session().api().kickParticipant(chat, participantPeer); + chat->session().api().chatParticipants().kick(chat, participantPeer); } else if (const auto channel = _peer->asChannel()) { const auto currentRestrictedRights = [&] { const auto user = participantPeer->asUser(); @@ -1356,7 +1357,7 @@ void Panel::kickParticipantSure(not_null participantPeer) { ? i->second.rights : ChatRestrictionsInfo(); }(); - channel->session().api().kickParticipant( + channel->session().api().chatParticipants().kick( channel, participantPeer, currentRestrictedRights); diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp index 48ac4888a..39d2a214d 100644 --- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp +++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp @@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "chat_helpers/message_field.h" // PrepareMentionTag. #include "mainwindow.h" #include "apiwrap.h" +#include "api/api_chat_participants.h" #include "main/main_session.h" #include "storage/storage_account.h" #include "core/application.h" @@ -431,7 +432,8 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) { } } else if (_channel && _channel->isMegagroup()) { if (_channel->lastParticipantsRequestNeeded()) { - _channel->session().api().requestLastParticipants(_channel); + _channel->session().api().chatParticipants().requestLast( + _channel); } else { mrows.reserve(mrows.size() + _channel->mgInfo->lastParticipants.size()); for (const auto user : _channel->mgInfo->lastParticipants) { @@ -489,7 +491,8 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) { } else if (_channel && _channel->isMegagroup()) { if (_channel->mgInfo->bots.empty()) { if (!_channel->mgInfo->botStatus) { - _channel->session().api().requestBots(_channel); + _channel->session().api().chatParticipants().requestBots( + _channel); } } else { const auto &commands = _channel->mgInfo->botCommands(); diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp index 1d9b4fce9..4944ebba6 100644 --- a/Telegram/SourceFiles/data/data_channel.cpp +++ b/Telegram/SourceFiles/data/data_channel.cpp @@ -927,77 +927,4 @@ void ApplyChannelUpdate( channel->owner().sendHistoryChangeNotifications(); } -void ApplyMegagroupAdmins( - not_null channel, - const MTPDchannels_channelParticipants &data) { - Expects(channel->isMegagroup()); - - channel->owner().processUsers(data.vusers()); - - const auto &list = data.vparticipants().v; - const auto i = ranges::find( - list, - mtpc_channelParticipantCreator, - &MTPChannelParticipant::type); - if (i != list.end()) { - const auto &data = i->c_channelParticipantCreator(); - const auto userId = data.vuser_id().v; - channel->mgInfo->creator = channel->owner().userLoaded(userId); - channel->mgInfo->creatorRank = qs(data.vrank().value_or_empty()); - } else { - channel->mgInfo->creator = nullptr; - channel->mgInfo->creatorRank = QString(); - } - - auto adding = base::flat_map(); - auto admins = ranges::make_subrange( - list.begin(), list.end() - ) | ranges::views::transform([](const MTPChannelParticipant &p) { - const auto participantId = p.match([]( - const MTPDchannelParticipantBanned &data) { - return peerFromMTP(data.vpeer()); - }, [](const MTPDchannelParticipantLeft &data) { - return peerFromMTP(data.vpeer()); - }, [](const auto &data) { - return peerFromUser(data.vuser_id()); - }); - const auto rank = p.match([](const MTPDchannelParticipantAdmin &data) { - return qs(data.vrank().value_or_empty()); - }, [](const MTPDchannelParticipantCreator &data) { - return qs(data.vrank().value_or_empty()); - }, [](const auto &data) { - return QString(); - }); - return std::make_pair(participantId, rank); - }) | ranges::views::filter([](const auto &pair) { - return peerIsUser(pair.first); - }); - for (const auto &[participantId, rank] : admins) { - Assert(peerIsUser(participantId)); - adding.emplace(peerToUser(participantId), rank); - } - if (channel->mgInfo->creator) { - adding.emplace( - peerToUser(channel->mgInfo->creator->id), - channel->mgInfo->creatorRank); - } - auto removing = channel->mgInfo->admins; - if (removing.empty() && adding.empty()) { - // Add some admin-placeholder so we don't DDOS - // server with admins list requests. - LOG(("API Error: Got empty admins list from server.")); - adding.emplace(0, QString()); - } - - Data::ChannelAdminChanges changes(channel); - for (const auto &[addingId, rank] : adding) { - if (!removing.remove(addingId)) { - changes.add(addingId, rank); - } - } - for (const auto &[removingId, rank] : removing) { - changes.remove(removingId); - } -} - } // namespace Data diff --git a/Telegram/SourceFiles/data/data_channel.h b/Telegram/SourceFiles/data/data_channel.h index ec5a0ff57..e1444813d 100644 --- a/Telegram/SourceFiles/data/data_channel.h +++ b/Telegram/SourceFiles/data/data_channel.h @@ -481,8 +481,4 @@ void ApplyChannelUpdate( not_null channel, const MTPDchannelFull &update); -void ApplyMegagroupAdmins( - not_null channel, - const MTPDchannels_channelParticipants &data); - } // namespace Data diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 112b42636..a99105659 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/crc32hash.h" #include "lang/lang_keys.h" #include "apiwrap.h" +#include "api/api_chat_participants.h" #include "ui/boxes/confirm_box.h" #include "main/main_session.h" #include "main/main_session_settings.h" @@ -644,7 +645,7 @@ void PeerData::updateFullForced() { session().api().requestFullPeer(this); if (const auto channel = asChannel()) { if (!channel->amCreator() && !channel->inviter) { - session().api().requestSelfParticipant(channel); + session().api().chatParticipants().requestSelf(channel); } } } diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp index c8ea855df..2e932c38a 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp @@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mainwidget.h" #include "core/application.h" #include "apiwrap.h" +#include "api/api_chat_participants.h" #include "api/api_attached_stickers.h" #include "window/window_session_controller.h" #include "main/main_session.h" @@ -444,7 +445,7 @@ void InnerWidget::requestAdmins() { MTP_int(kMaxChannelAdmins), MTP_long(participantsHash) )).done([=](const MTPchannels_ChannelParticipants &result) { - session().api().parseChannelParticipants(_channel, result, [&]( + session().api().chatParticipants().parse(_channel, result, [&]( int availableCount, const QVector &list) { auto filtered = ( diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index b1fffd857..81fbd49de 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_histories.h" #include "lang/lang_keys.h" #include "apiwrap.h" +#include "api/api_chat_participants.h" #include "mainwidget.h" #include "mainwindow.h" #include "main/main_session.h" @@ -2587,7 +2588,7 @@ void History::applyDialog( data.vtop_message().v); if (const auto item = owner().message(topMessageId)) { if (item->date() <= channel->date) { - session().api().requestSelfParticipant(channel); + session().api().chatParticipants().requestSelf(channel); } } } diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index fff5b2c9b..8f437ef34 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_editing.h" #include "api/api_bot.h" +#include "api/api_chat_participants.h" #include "api/api_sending.h" #include "api/api_text_entities.h" #include "api/api_send_progress.h" @@ -5675,7 +5676,8 @@ void HistoryWidget::handlePeerMigration() { showHistory( channel->id, (_showAtMsgId > 0) ? (-_showAtMsgId) : _showAtMsgId); - channel->session().api().requestParticipantsCountDelayed(channel); + channel->session().api().chatParticipants().requestCountDelayed( + channel); } else { _migrated = _history->migrateFrom(); _list->notifyMigrateUpdated(); @@ -6737,10 +6739,10 @@ void HistoryWidget::handlePeerUpdate() { session().api().requestFullPeer(_peer); } else if (auto channel = _peer->asMegagroup()) { if (!channel->mgInfo->botStatus) { - session().api().requestBots(channel); + session().api().chatParticipants().requestBots(channel); } if (channel->mgInfo->admins.empty()) { - session().api().requestAdmins(channel); + session().api().chatParticipants().requestAdmins(channel); } } if (!_a_show.animating()) { diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index f4671c7e4..735b4dcc7 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_web_page.h" #include "storage/storage_account.h" #include "apiwrap.h" +#include "api/api_chat_participants.h" #include "ui/boxes/confirm_box.h" #include "history/history.h" #include "history/history_item.h" @@ -672,7 +673,7 @@ void ComposeControls::setHistory(SetHistoryArgs &&args) { session().api().requestFullPeer(peer); } else if (const auto channel = peer->asMegagroup()) { if (!channel->mgInfo->botStatus) { - session().api().requestBots(channel); + session().api().chatParticipants().requestBots(channel); } } else if (hasSilentBroadcastToggle()) { _silent = std::make_unique( diff --git a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp index ea30062bb..bb3682e14 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp @@ -51,6 +51,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/unixtime.h" #include "support/support_helper.h" #include "apiwrap.h" +#include "api/api_chat_participants.h" #include "styles/style_window.h" #include "styles/style_dialogs.h" #include "styles/style_chat.h" @@ -1143,7 +1144,7 @@ void TopBarWidget::updateOnlineDisplay() { && (channel->membersCount() <= channel->session().serverConfig().chatSizeMax)) { if (channel->lastParticipantsRequestNeeded()) { - session().api().requestLastParticipants(channel); + session().api().chatParticipants().requestLast(channel); } const auto self = session().user(); auto online = 0; diff --git a/Telegram/SourceFiles/profile/profile_block_group_members.cpp b/Telegram/SourceFiles/profile/profile_block_group_members.cpp index 16e22304a..707143fd2 100644 --- a/Telegram/SourceFiles/profile/profile_block_group_members.cpp +++ b/Telegram/SourceFiles/profile/profile_block_group_members.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "profile/profile_block_group_members.h" +#include "api/api_chat_participants.h" #include "styles/style_profile.h" #include "ui/widgets/labels.h" #include "ui/boxes/confirm_box.h" @@ -89,10 +90,10 @@ void GroupMembersWidget::removePeer(PeerData *selectedPeer) { const auto callback = [=] { Ui::hideLayer(); if (const auto chat = peer->asChat()) { - chat->session().api().kickParticipant(chat, user); + chat->session().api().chatParticipants().kick(chat, user); Ui::showPeerHistory(chat, ShowAtTheEndMsgId); } else if (const auto channel = peer->asChannel()) { - channel->session().api().kickParticipant( + channel->session().api().chatParticipants().kick( channel, user, currentRestrictedRights); @@ -158,7 +159,7 @@ void GroupMembersWidget::preloadMore() { //if (auto megagroup = peer()->asMegagroup()) { // auto &megagroupInfo = megagroup->mgInfo; // if (!megagroupInfo->lastParticipants.isEmpty() && megagroupInfo->lastParticipants.size() < megagroup->membersCount()) { - // peer()->session().api().requestLastParticipants(megagroup, false); + // peer()->session().api().requestLast(megagroup, false); // } //} } @@ -198,7 +199,8 @@ void GroupMembersWidget::refreshMembers() { fillChatMembers(chat); } else if (const auto megagroup = peer()->asMegagroup()) { if (megagroup->lastParticipantsRequestNeeded()) { - megagroup->session().api().requestLastParticipants(megagroup); + megagroup->session().api().chatParticipants().requestLast( + megagroup); } fillMegagroupMembers(megagroup); } diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 2abdd59cf..d70773c30 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "window/window_peer_menu.h" +#include "api/api_chat_participants.h" #include "lang/lang_keys.h" #include "ui/boxes/confirm_box.h" #include "boxes/delete_messages_box.h" @@ -1090,9 +1091,9 @@ void PeerMenuAddChannelMembers( return; } const auto api = &channel->session().api(); - api->requestChannelMembersForAdd(channel, crl::guard(navigation, [=]( + api->chatParticipants().requestForAdd(channel, crl::guard(navigation, [=]( const MTPchannels_ChannelParticipants &result) { - api->parseChannelParticipants(channel, result, [&]( + api->chatParticipants().parse(channel, result, [&]( int availableCount, const QVector &list) { auto already = (