api_chat_participants.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "api/api_chat_participants.h"
  8. #include "apiwrap.h"
  9. #include "boxes/add_contact_box.h" // ShowAddParticipantsError
  10. #include "boxes/peers/add_participants_box.h" // ChatInviteForbidden
  11. #include "data/data_changes.h"
  12. #include "data/data_channel.h"
  13. #include "data/data_channel_admins.h"
  14. #include "data/data_chat.h"
  15. #include "data/data_histories.h"
  16. #include "data/data_session.h"
  17. #include "data/data_user.h"
  18. #include "history/history.h"
  19. #include "main/main_session.h"
  20. #include "mtproto/mtproto_config.h"
  21. namespace Api {
  22. namespace {
  23. using Members = ChatParticipants::Members;
  24. constexpr auto kSmallDelayMs = crl::time(5);
  25. // 1 second wait before reload members in channel after adding.
  26. constexpr auto kReloadChannelMembersTimeout = 1000;
  27. // Max users in one super group invite request.
  28. constexpr auto kMaxUsersPerInvite = 100;
  29. // How many messages from chat history server should forward to user,
  30. // that was added to this chat.
  31. constexpr auto kForwardMessagesOnAdd = 100;
  32. std::vector<ChatParticipant> ParseList(
  33. const ChatParticipants::TLMembers &data,
  34. not_null<PeerData*> peer) {
  35. return ranges::views::all(
  36. data.vparticipants().v
  37. ) | ranges::views::transform([&](const MTPChannelParticipant &p) {
  38. return ChatParticipant(p, peer);
  39. }) | ranges::to_vector;
  40. }
  41. void ApplyMegagroupAdmins(not_null<ChannelData*> channel, Members list) {
  42. Expects(channel->isMegagroup());
  43. const auto i = ranges::find_if(list, &Api::ChatParticipant::isCreator);
  44. if (i != list.end()) {
  45. i->tryApplyCreatorTo(channel);
  46. } else {
  47. channel->mgInfo->creator = nullptr;
  48. channel->mgInfo->creatorRank = QString();
  49. }
  50. auto adding = base::flat_map<UserId, QString>();
  51. for (const auto &p : list) {
  52. if (p.isUser()) {
  53. adding.emplace(p.userId(), p.rank());
  54. }
  55. }
  56. if (channel->mgInfo->creator) {
  57. adding.emplace(
  58. peerToUser(channel->mgInfo->creator->id),
  59. channel->mgInfo->creatorRank);
  60. }
  61. auto removing = channel->mgInfo->admins;
  62. if (removing.empty() && adding.empty()) {
  63. // Add some admin-placeholder so we don't DDOS
  64. // server with admins list requests.
  65. LOG(("API Error: Got empty admins list from server."));
  66. adding.emplace(0, QString());
  67. }
  68. Data::ChannelAdminChanges changes(channel);
  69. for (const auto &[addingId, rank] : adding) {
  70. if (!removing.remove(addingId)) {
  71. changes.add(addingId, rank);
  72. }
  73. }
  74. for (const auto &[removingId, rank] : removing) {
  75. changes.remove(removingId);
  76. }
  77. }
  78. void RefreshChannelAdmins(
  79. not_null<ChannelData*> channel,
  80. Members participants) {
  81. Data::ChannelAdminChanges changes(channel);
  82. for (const auto &p : participants) {
  83. if (p.isUser()) {
  84. if (p.isCreatorOrAdmin()) {
  85. p.tryApplyCreatorTo(channel);
  86. changes.add(p.userId(), p.rank());
  87. } else {
  88. changes.remove(p.userId());
  89. }
  90. }
  91. }
  92. }
  93. void ApplyLastList(
  94. not_null<ChannelData*> channel,
  95. int availableCount,
  96. Members list) {
  97. channel->mgInfo->lastAdmins.clear();
  98. channel->mgInfo->lastRestricted.clear();
  99. channel->mgInfo->lastParticipants.clear();
  100. channel->mgInfo->lastParticipantsStatus
  101. = MegagroupInfo::LastParticipantsUpToDate
  102. | MegagroupInfo::LastParticipantsOnceReceived;
  103. auto botStatus = channel->mgInfo->botStatus;
  104. for (const auto &p : list) {
  105. const auto participant = channel->owner().peer(p.id());
  106. const auto user = participant->asUser();
  107. const auto adminRights = p.rights();
  108. const auto restrictedRights = p.restrictions();
  109. if (p.isCreator()) {
  110. Assert(user != nullptr);
  111. p.tryApplyCreatorTo(channel);
  112. if (!channel->mgInfo->admins.empty()) {
  113. Data::ChannelAdminChanges(channel).add(p.userId(), p.rank());
  114. }
  115. }
  116. if (user
  117. && !base::contains(channel->mgInfo->lastParticipants, user)) {
  118. channel->mgInfo->lastParticipants.push_back(user);
  119. if (adminRights.flags) {
  120. channel->mgInfo->lastAdmins.emplace(
  121. user,
  122. MegagroupInfo::Admin{ adminRights, p.canBeEdited() });
  123. } else if (restrictedRights.flags) {
  124. channel->mgInfo->lastRestricted.emplace(
  125. user,
  126. MegagroupInfo::Restricted{ restrictedRights });
  127. }
  128. if (user->isBot()) {
  129. channel->mgInfo->bots.insert(user);
  130. if ((channel->mgInfo->botStatus != 0)
  131. && (channel->mgInfo->botStatus < 2)) {
  132. channel->mgInfo->botStatus = 2;
  133. }
  134. }
  135. }
  136. }
  137. //
  138. // getParticipants(Recent) sometimes can't return all members,
  139. // only some last subset, size of this subset is availableCount.
  140. //
  141. // So both list size and availableCount have nothing to do with
  142. // the full supergroup members count.
  143. //
  144. //if (list.isEmpty()) {
  145. // channel->setMembersCount(channel->mgInfo->lastParticipants.size());
  146. //} else {
  147. // channel->setMembersCount(availableCount);
  148. //}
  149. channel->session().changes().peerUpdated(
  150. channel,
  151. (Data::PeerUpdate::Flag::Members | Data::PeerUpdate::Flag::Admins));
  152. channel->mgInfo->botStatus = botStatus;
  153. channel->session().changes().peerUpdated(
  154. channel,
  155. Data::PeerUpdate::Flag::FullInfo);
  156. }
  157. void ApplyBotsList(
  158. not_null<ChannelData*> channel,
  159. int availableCount,
  160. Members list) {
  161. const auto history = channel->owner().historyLoaded(channel);
  162. channel->mgInfo->bots.clear();
  163. channel->mgInfo->botStatus = -1;
  164. auto needBotsInfos = false;
  165. auto botStatus = channel->mgInfo->botStatus;
  166. auto keyboardBotFound = !history || !history->lastKeyboardFrom;
  167. for (const auto &p : list) {
  168. const auto participant = channel->owner().peer(p.id());
  169. const auto user = participant->asUser();
  170. if (user && user->isBot()) {
  171. channel->mgInfo->bots.insert(user);
  172. botStatus = 2;// (botStatus > 0/* || !i.key()->botInfo->readsAllHistory*/) ? 2 : 1;
  173. if (!user->botInfo->inited) {
  174. needBotsInfos = true;
  175. }
  176. }
  177. if (!keyboardBotFound
  178. && participant->id == history->lastKeyboardFrom) {
  179. keyboardBotFound = true;
  180. }
  181. }
  182. if (needBotsInfos) {
  183. channel->session().api().requestFullPeer(channel);
  184. }
  185. if (!keyboardBotFound) {
  186. history->clearLastKeyboard();
  187. }
  188. channel->mgInfo->botStatus = botStatus;
  189. channel->session().changes().peerUpdated(
  190. channel,
  191. Data::PeerUpdate::Flag::FullInfo);
  192. }
  193. [[nodiscard]] ChatParticipants::Peers ParseSimilarChannels(
  194. not_null<Main::Session*> session,
  195. const MTPmessages_Chats &chats) {
  196. auto result = ChatParticipants::Peers();
  197. chats.match([&](const auto &data) {
  198. const auto &list = data.vchats().v;
  199. result.list.reserve(list.size());
  200. for (const auto &chat : list) {
  201. const auto peer = session->data().processChat(chat);
  202. if (const auto channel = peer->asChannel()) {
  203. result.list.push_back(channel);
  204. }
  205. }
  206. if constexpr (MTPDmessages_chatsSlice::Is<decltype(data)>()) {
  207. if (session->premiumPossible()) {
  208. result.more = data.vcount().v - data.vchats().v.size();
  209. }
  210. }
  211. });
  212. return result;
  213. }
  214. [[nodiscard]] ChatParticipants::Peers ParseSimilarChannels(
  215. not_null<ChannelData*> channel,
  216. const MTPmessages_Chats &chats) {
  217. return ParseSimilarChannels(&channel->session(), chats);
  218. }
  219. [[nodiscard]] ChatParticipants::Peers ParseSimilarBots(
  220. not_null<Main::Session*> session,
  221. const MTPusers_Users &users) {
  222. auto result = ChatParticipants::Peers();
  223. users.match([&](const auto &data) {
  224. const auto &list = data.vusers().v;
  225. result.list.reserve(list.size());
  226. for (const auto &user : list) {
  227. result.list.push_back(session->data().processUser(user));
  228. }
  229. if constexpr (MTPDusers_usersSlice::Is<decltype(data)>()) {
  230. if (session->premiumPossible()) {
  231. result.more = data.vcount().v - data.vusers().v.size();
  232. }
  233. }
  234. });
  235. return result;
  236. }
  237. } // namespace
  238. ChatParticipant::ChatParticipant(
  239. const MTPChannelParticipant &p,
  240. not_null<PeerData*> peer) {
  241. _peer = p.match([](const MTPDchannelParticipantBanned &data) {
  242. return peerFromMTP(data.vpeer());
  243. }, [](const MTPDchannelParticipantLeft &data) {
  244. return peerFromMTP(data.vpeer());
  245. }, [](const auto &data) {
  246. return peerFromUser(data.vuser_id());
  247. });
  248. p.match([&](const MTPDchannelParticipantCreator &data) {
  249. _canBeEdited = (peer->session().userPeerId() == _peer);
  250. _type = Type::Creator;
  251. _rights = ChatAdminRightsInfo(data.vadmin_rights());
  252. _rank = qs(data.vrank().value_or_empty());
  253. }, [&](const MTPDchannelParticipantAdmin &data) {
  254. _canBeEdited = data.is_can_edit();
  255. _type = Type::Admin;
  256. _rank = qs(data.vrank().value_or_empty());
  257. _rights = ChatAdminRightsInfo(data.vadmin_rights());
  258. _by = peerToUser(peerFromUser(data.vpromoted_by()));
  259. _date = data.vdate().v;
  260. }, [&](const MTPDchannelParticipantSelf &data) {
  261. _type = Type::Member;
  262. _date = data.vdate().v;
  263. _by = peerToUser(peerFromUser(data.vinviter_id()));
  264. if (data.vsubscription_until_date()) {
  265. _subscriptionDate = data.vsubscription_until_date()->v;
  266. }
  267. }, [&](const MTPDchannelParticipant &data) {
  268. _type = Type::Member;
  269. _date = data.vdate().v;
  270. if (data.vsubscription_until_date()) {
  271. _subscriptionDate = data.vsubscription_until_date()->v;
  272. }
  273. }, [&](const MTPDchannelParticipantBanned &data) {
  274. _restrictions = ChatRestrictionsInfo(data.vbanned_rights());
  275. _by = peerToUser(peerFromUser(data.vkicked_by()));
  276. _date = data.vdate().v;
  277. _type = (_restrictions.flags & ChatRestriction::ViewMessages)
  278. ? Type::Banned
  279. : Type::Restricted;
  280. }, [&](const MTPDchannelParticipantLeft &data) {
  281. _type = Type::Left;
  282. });
  283. }
  284. ChatParticipant::ChatParticipant(
  285. Type type,
  286. PeerId peerId,
  287. UserId by,
  288. ChatRestrictionsInfo restrictions,
  289. ChatAdminRightsInfo rights,
  290. bool canBeEdited,
  291. QString rank)
  292. : _type(type)
  293. , _peer(peerId)
  294. , _by(by)
  295. , _canBeEdited(canBeEdited)
  296. , _rank(rank)
  297. , _restrictions(std::move(restrictions))
  298. , _rights(std::move(rights)) {
  299. }
  300. void ChatParticipant::tryApplyCreatorTo(
  301. not_null<ChannelData*> channel) const {
  302. if (isCreator() && isUser()) {
  303. if (const auto info = channel->mgInfo.get()) {
  304. info->creator = channel->owner().userLoaded(userId());
  305. info->creatorRank = rank();
  306. }
  307. }
  308. }
  309. bool ChatParticipant::isUser() const {
  310. return peerIsUser(_peer);
  311. }
  312. bool ChatParticipant::isCreator() const {
  313. return _type == Type::Creator;
  314. }
  315. bool ChatParticipant::isCreatorOrAdmin() const {
  316. return _type == Type::Creator || _type == Type::Admin;
  317. }
  318. bool ChatParticipant::isKicked() const {
  319. return _type == Type::Banned;
  320. }
  321. bool ChatParticipant::canBeEdited() const {
  322. return _canBeEdited;
  323. }
  324. UserId ChatParticipant::by() const {
  325. return _by;
  326. }
  327. PeerId ChatParticipant::id() const {
  328. return _peer;
  329. }
  330. UserId ChatParticipant::userId() const {
  331. return peerToUser(_peer);
  332. }
  333. ChatRestrictionsInfo ChatParticipant::restrictions() const {
  334. return _restrictions;
  335. }
  336. ChatAdminRightsInfo ChatParticipant::rights() const {
  337. return _rights;
  338. }
  339. TimeId ChatParticipant::subscriptionDate() const {
  340. return _subscriptionDate;
  341. }
  342. TimeId ChatParticipant::promotedSince() const {
  343. return (_type == Type::Admin) ? _date : TimeId(0);
  344. }
  345. TimeId ChatParticipant::restrictedSince() const {
  346. return (_type == Type::Restricted || _type == Type::Banned)
  347. ? _date
  348. : TimeId(0);
  349. }
  350. TimeId ChatParticipant::memberSince() const {
  351. return (_type == Type::Member) ? _date : TimeId(0);
  352. }
  353. ChatParticipant::Type ChatParticipant::type() const {
  354. return _type;
  355. }
  356. QString ChatParticipant::rank() const {
  357. return _rank;
  358. }
  359. ChatParticipants::ChatParticipants(not_null<ApiWrap*> api)
  360. : _session(&api->session())
  361. , _api(&api->instance()) {
  362. }
  363. void ChatParticipants::requestForAdd(
  364. not_null<ChannelData*> channel,
  365. Fn<void(const TLMembers&)> callback) {
  366. Expects(callback != nullptr);
  367. _forAdd.callback = std::move(callback);
  368. if (_forAdd.channel == channel) {
  369. return;
  370. }
  371. _api.request(base::take(_forAdd.requestId)).cancel();
  372. const auto offset = 0;
  373. const auto participantsHash = uint64(0);
  374. _forAdd.channel = channel;
  375. _forAdd.requestId = _api.request(MTPchannels_GetParticipants(
  376. channel->inputChannel,
  377. MTP_channelParticipantsRecent(),
  378. MTP_int(offset),
  379. MTP_int(channel->session().serverConfig().chatSizeMax),
  380. MTP_long(participantsHash)
  381. )).done([=](const MTPchannels_ChannelParticipants &result) {
  382. result.match([&](const MTPDchannels_channelParticipants &data) {
  383. base::take(_forAdd).callback(data);
  384. }, [&](const MTPDchannels_channelParticipantsNotModified &) {
  385. base::take(_forAdd);
  386. LOG(("API Error: "
  387. "channels.channelParticipantsNotModified received!"));
  388. });
  389. }).fail([=] {
  390. base::take(_forAdd);
  391. }).send();
  392. }
  393. void ChatParticipants::requestLast(not_null<ChannelData*> channel) {
  394. if (!channel->isMegagroup()
  395. || !channel->canViewMembers()
  396. || _participantsRequests.contains(channel)) {
  397. return;
  398. }
  399. const auto offset = 0;
  400. const auto participantsHash = uint64(0);
  401. const auto requestId = _api.request(MTPchannels_GetParticipants(
  402. channel->inputChannel,
  403. MTP_channelParticipantsRecent(),
  404. MTP_int(offset),
  405. MTP_int(channel->session().serverConfig().chatSizeMax),
  406. MTP_long(participantsHash)
  407. )).done([=](const MTPchannels_ChannelParticipants &result) {
  408. _participantsRequests.remove(channel);
  409. result.match([&](const MTPDchannels_channelParticipants &data) {
  410. const auto &[availableCount, list] = Parse(channel, data);
  411. ApplyLastList(channel, availableCount, list);
  412. }, [](const MTPDchannels_channelParticipantsNotModified &) {
  413. LOG(("API Error: "
  414. "channels.channelParticipantsNotModified received!"));
  415. });
  416. }).fail([this, channel] {
  417. _participantsRequests.remove(channel);
  418. }).send();
  419. _participantsRequests[channel] = requestId;
  420. }
  421. void ChatParticipants::requestBots(not_null<ChannelData*> channel) {
  422. if (!channel->isMegagroup() || _botsRequests.contains(channel)) {
  423. return;
  424. }
  425. const auto offset = 0;
  426. const auto participantsHash = uint64(0);
  427. const auto requestId = _api.request(MTPchannels_GetParticipants(
  428. channel->inputChannel,
  429. MTP_channelParticipantsBots(),
  430. MTP_int(offset),
  431. MTP_int(channel->session().serverConfig().chatSizeMax),
  432. MTP_long(participantsHash)
  433. )).done([=](const MTPchannels_ChannelParticipants &result) {
  434. _botsRequests.remove(channel);
  435. result.match([&](const MTPDchannels_channelParticipants &data) {
  436. const auto &[availableCount, list] = Parse(channel, data);
  437. ApplyBotsList(channel, availableCount, list);
  438. }, [](const MTPDchannels_channelParticipantsNotModified &) {
  439. LOG(("API Error: "
  440. "channels.channelParticipantsNotModified received!"));
  441. });
  442. }).fail([=] {
  443. _botsRequests.remove(channel);
  444. }).send();
  445. _botsRequests[channel] = requestId;
  446. }
  447. void ChatParticipants::requestAdmins(not_null<ChannelData*> channel) {
  448. if (!channel->isMegagroup() || _adminsRequests.contains(channel)) {
  449. return;
  450. }
  451. const auto offset = 0;
  452. const auto participantsHash = uint64(0);
  453. const auto requestId = _api.request(MTPchannels_GetParticipants(
  454. channel->inputChannel,
  455. MTP_channelParticipantsAdmins(),
  456. MTP_int(offset),
  457. MTP_int(channel->session().serverConfig().chatSizeMax),
  458. MTP_long(participantsHash)
  459. )).done([=](const MTPchannels_ChannelParticipants &result) {
  460. channel->mgInfo->adminsLoaded = true;
  461. _adminsRequests.remove(channel);
  462. result.match([&](const MTPDchannels_channelParticipants &data) {
  463. channel->owner().processUsers(data.vusers());
  464. ApplyMegagroupAdmins(channel, ParseList(data, channel));
  465. }, [](const MTPDchannels_channelParticipantsNotModified &) {
  466. LOG(("API Error: "
  467. "channels.channelParticipantsNotModified received!"));
  468. });
  469. }).fail([=] {
  470. channel->mgInfo->adminsLoaded = true;
  471. _adminsRequests.remove(channel);
  472. }).send();
  473. _adminsRequests[channel] = requestId;
  474. }
  475. void ChatParticipants::requestCountDelayed(
  476. not_null<ChannelData*> channel) {
  477. _participantsCountRequestTimer.call(
  478. kReloadChannelMembersTimeout,
  479. [=] { channel->updateFullForced(); });
  480. }
  481. void ChatParticipants::add(
  482. std::shared_ptr<Ui::Show> show,
  483. not_null<PeerData*> peer,
  484. const std::vector<not_null<UserData*>> &users,
  485. bool passGroupHistory,
  486. Fn<void(bool)> done) {
  487. if (const auto chat = peer->asChat()) {
  488. for (const auto &user : users) {
  489. _api.request(MTPmessages_AddChatUser(
  490. chat->inputChat,
  491. user->inputUser,
  492. MTP_int(passGroupHistory ? kForwardMessagesOnAdd : 0)
  493. )).done([=](const MTPmessages_InvitedUsers &result) {
  494. const auto &data = result.data();
  495. chat->session().api().applyUpdates(data.vupdates());
  496. if (done) done(true);
  497. ChatInviteForbidden(
  498. show,
  499. chat,
  500. CollectForbiddenUsers(&chat->session(), result));
  501. }).fail([=](const MTP::Error &error) {
  502. const auto type = error.type();
  503. ShowAddParticipantsError(show, type, peer, user);
  504. if (done) done(false);
  505. }).afterDelay(kSmallDelayMs).send();
  506. }
  507. } else if (const auto channel = peer->asChannel()) {
  508. const auto hasBot = ranges::any_of(users, &UserData::isBot);
  509. if (!peer->isMegagroup() && hasBot) {
  510. ShowAddParticipantsError(
  511. show,
  512. u"USER_BOT"_q,
  513. peer,
  514. { .users = users });
  515. return;
  516. }
  517. auto list = QVector<MTPInputUser>();
  518. list.reserve(std::min(int(users.size()), int(kMaxUsersPerInvite)));
  519. const auto send = [&] {
  520. const auto callback = base::take(done);
  521. _api.request(MTPchannels_InviteToChannel(
  522. channel->inputChannel,
  523. MTP_vector<MTPInputUser>(list)
  524. )).done([=](const MTPmessages_InvitedUsers &result) {
  525. const auto &data = result.data();
  526. channel->session().api().applyUpdates(data.vupdates());
  527. requestCountDelayed(channel);
  528. if (callback) callback(true);
  529. ChatInviteForbidden(
  530. show,
  531. channel,
  532. CollectForbiddenUsers(&channel->session(), result));
  533. }).fail([=](const MTP::Error &error) {
  534. ShowAddParticipantsError(show, error.type(), peer, {
  535. .users = users,
  536. });
  537. if (callback) callback(false);
  538. }).afterDelay(kSmallDelayMs).send();
  539. };
  540. for (const auto &user : users) {
  541. list.push_back(user->inputUser);
  542. if (list.size() == kMaxUsersPerInvite) {
  543. send();
  544. list.clear();
  545. }
  546. }
  547. if (!list.empty()) {
  548. send();
  549. }
  550. } else {
  551. Unexpected("User in ChatParticipants::add.");
  552. }
  553. }
  554. ChatParticipants::Parsed ChatParticipants::Parse(
  555. not_null<ChannelData*> channel,
  556. const TLMembers &data) {
  557. channel->owner().processUsers(data.vusers());
  558. channel->owner().processChats(data.vchats());
  559. auto list = ParseList(data, channel);
  560. if (channel->mgInfo) {
  561. RefreshChannelAdmins(channel, list);
  562. }
  563. return { data.vcount().v, std::move(list) };
  564. }
  565. ChatParticipants::Parsed ChatParticipants::ParseRecent(
  566. not_null<ChannelData*> channel,
  567. const TLMembers &data) {
  568. const auto result = Parse(channel, data);
  569. const auto applyLast = channel->isMegagroup()
  570. && channel->canViewMembers()
  571. && (channel->mgInfo->lastParticipants.size() <= result.list.size());
  572. if (applyLast) {
  573. ApplyLastList(channel, result.availableCount, result.list);
  574. }
  575. return result;
  576. }
  577. void ChatParticipants::Restrict(
  578. not_null<ChannelData*> channel,
  579. not_null<PeerData*> participant,
  580. ChatRestrictionsInfo oldRights,
  581. ChatRestrictionsInfo newRights,
  582. Fn<void()> onDone,
  583. Fn<void()> onFail) {
  584. channel->session().api().request(MTPchannels_EditBanned(
  585. channel->inputChannel,
  586. participant->input,
  587. MTP_chatBannedRights(
  588. MTP_flags(MTPDchatBannedRights::Flags::from_raw(
  589. uint32(newRights.flags))),
  590. MTP_int(newRights.until))
  591. )).done([=](const MTPUpdates &result) {
  592. channel->session().api().applyUpdates(result);
  593. channel->applyEditBanned(participant, oldRights, newRights);
  594. if (onDone) {
  595. onDone();
  596. }
  597. }).fail([=] {
  598. if (onFail) {
  599. onFail();
  600. }
  601. }).send();
  602. }
  603. void ChatParticipants::requestSelf(not_null<ChannelData*> channel) {
  604. if (_selfParticipantRequests.contains(channel)) {
  605. return;
  606. }
  607. const auto finalize = [=](
  608. UserId inviter = -1,
  609. TimeId inviteDate = 0,
  610. bool inviteViaRequest = false) {
  611. channel->inviter = inviter;
  612. channel->inviteDate = inviteDate;
  613. channel->inviteViaRequest = inviteViaRequest;
  614. if (const auto history = channel->owner().historyLoaded(channel)) {
  615. if (history->lastMessageKnown()) {
  616. history->checkLocalMessages();
  617. history->owner().sendHistoryChangeNotifications();
  618. } else {
  619. history->owner().histories().requestDialogEntry(history);
  620. }
  621. }
  622. };
  623. _selfParticipantRequests.emplace(channel);
  624. _api.request(MTPchannels_GetParticipant(
  625. channel->inputChannel,
  626. MTP_inputPeerSelf()
  627. )).done([=](const MTPchannels_ChannelParticipant &result) {
  628. _selfParticipantRequests.erase(channel);
  629. result.match([&](const MTPDchannels_channelParticipant &data) {
  630. channel->owner().processUsers(data.vusers());
  631. const auto &participant = data.vparticipant();
  632. participant.match([&](const MTPDchannelParticipantSelf &data) {
  633. finalize(
  634. data.vinviter_id().v,
  635. data.vdate().v,
  636. data.is_via_request());
  637. }, [&](const MTPDchannelParticipantCreator &) {
  638. if (channel->mgInfo) {
  639. channel->mgInfo->creator = channel->session().user();
  640. }
  641. finalize(channel->session().userId(), channel->date);
  642. }, [&](const MTPDchannelParticipantAdmin &data) {
  643. const auto inviter = data.is_self()
  644. ? data.vinviter_id().value_or(-1)
  645. : -1;
  646. finalize(inviter, data.vdate().v);
  647. }, [&](const MTPDchannelParticipantBanned &data) {
  648. LOG(("API Error: Got self banned participant."));
  649. finalize();
  650. }, [&](const MTPDchannelParticipant &data) {
  651. LOG(("API Error: Got self regular participant."));
  652. finalize();
  653. }, [&](const MTPDchannelParticipantLeft &data) {
  654. LOG(("API Error: Got self left participant."));
  655. finalize();
  656. });
  657. });
  658. }).fail([=](const MTP::Error &error) {
  659. _selfParticipantRequests.erase(channel);
  660. if (error.type() == u"CHANNEL_PRIVATE"_q) {
  661. channel->privateErrorReceived();
  662. }
  663. finalize();
  664. }).afterDelay(kSmallDelayMs).send();
  665. }
  666. void ChatParticipants::kick(
  667. not_null<ChatData*> chat,
  668. not_null<PeerData*> participant) {
  669. Expects(participant->isUser());
  670. _api.request(MTPmessages_DeleteChatUser(
  671. MTP_flags(0),
  672. chat->inputChat,
  673. participant->asUser()->inputUser
  674. )).done([=](const MTPUpdates &result) {
  675. chat->session().api().applyUpdates(result);
  676. }).send();
  677. }
  678. void ChatParticipants::kick(
  679. not_null<ChannelData*> channel,
  680. not_null<PeerData*> participant,
  681. ChatRestrictionsInfo currentRights) {
  682. const auto kick = KickRequest(channel, participant);
  683. if (_kickRequests.contains(kick)) return;
  684. const auto rights = ChannelData::KickedRestrictedRights(participant);
  685. const auto requestId = _api.request(MTPchannels_EditBanned(
  686. channel->inputChannel,
  687. participant->input,
  688. MTP_chatBannedRights(
  689. MTP_flags(
  690. MTPDchatBannedRights::Flags::from_raw(uint32(rights.flags))),
  691. MTP_int(rights.until))
  692. )).done([=](const MTPUpdates &result) {
  693. channel->session().api().applyUpdates(result);
  694. _kickRequests.remove(KickRequest(channel, participant));
  695. channel->applyEditBanned(participant, currentRights, rights);
  696. }).fail([this, kick] {
  697. _kickRequests.remove(kick);
  698. }).send();
  699. _kickRequests.emplace(kick, requestId);
  700. }
  701. void ChatParticipants::unblock(
  702. not_null<ChannelData*> channel,
  703. not_null<PeerData*> participant) {
  704. const auto kick = KickRequest(channel, participant);
  705. if (_kickRequests.contains(kick)) {
  706. return;
  707. }
  708. const auto requestId = _api.request(MTPchannels_EditBanned(
  709. channel->inputChannel,
  710. participant->input,
  711. MTP_chatBannedRights(MTP_flags(0), MTP_int(0))
  712. )).done([=](const MTPUpdates &result) {
  713. channel->session().api().applyUpdates(result);
  714. _kickRequests.remove(KickRequest(channel, participant));
  715. if (channel->kickedCount() > 0) {
  716. channel->setKickedCount(channel->kickedCount() - 1);
  717. } else {
  718. channel->updateFullForced();
  719. }
  720. }).fail([=] {
  721. _kickRequests.remove(kick);
  722. }).send();
  723. _kickRequests.emplace(kick, requestId);
  724. }
  725. void ChatParticipants::loadSimilarPeers(not_null<PeerData*> peer) {
  726. if (const auto i = _similar.find(peer); i != end(_similar)) {
  727. if (i->second.requestId
  728. || !i->second.peers.more
  729. || !peer->session().premium()) {
  730. return;
  731. }
  732. }
  733. if (const auto channel = peer->asBroadcast()) {
  734. using Flag = MTPchannels_GetChannelRecommendations::Flag;
  735. _similar[peer].requestId = _api.request(
  736. MTPchannels_GetChannelRecommendations(
  737. MTP_flags(Flag::f_channel),
  738. channel->inputChannel)
  739. ).done([=](const MTPmessages_Chats &result) {
  740. auto &similar = _similar[channel];
  741. similar.requestId = 0;
  742. auto parsed = ParseSimilarChannels(channel, result);
  743. if (similar.peers == parsed) {
  744. return;
  745. }
  746. similar.peers = std::move(parsed);
  747. if (const auto history = channel->owner().historyLoaded(channel)) {
  748. if (const auto item = history->joinedMessageInstance()) {
  749. history->owner().requestItemResize(item);
  750. }
  751. }
  752. _similarLoaded.fire_copy(channel);
  753. }).send();
  754. } else if (const auto bot = peer->asBot()) {
  755. _similar[peer].requestId = _api.request(
  756. MTPbots_GetBotRecommendations(bot->inputUser)
  757. ).done([=](const MTPusers_Users &result) {
  758. auto &similar = _similar[peer];
  759. similar.requestId = 0;
  760. auto parsed = ParseSimilarBots(&peer->session(), result);
  761. if (similar.peers == parsed) {
  762. return;
  763. }
  764. similar.peers = std::move(parsed);
  765. _similarLoaded.fire_copy(peer);
  766. }).send();
  767. }
  768. }
  769. auto ChatParticipants::similar(not_null<PeerData*> peer)
  770. -> const Peers & {
  771. const auto i = (peer->isBroadcast() || peer->isBot())
  772. ? _similar.find(peer)
  773. : end(_similar);
  774. if (i != end(_similar)) {
  775. return i->second.peers;
  776. }
  777. static const auto empty = Peers();
  778. return empty;
  779. }
  780. auto ChatParticipants::similarLoaded() const
  781. -> rpl::producer<not_null<PeerData*>> {
  782. return _similarLoaded.events();
  783. }
  784. void ChatParticipants::loadRecommendations() {
  785. if (_recommendationsLoaded.current() || _recommendations.requestId) {
  786. return;
  787. }
  788. _recommendations.requestId = _api.request(
  789. MTPchannels_GetChannelRecommendations(
  790. MTP_flags(0),
  791. MTP_inputChannelEmpty())
  792. ).done([=](const MTPmessages_Chats &result) {
  793. _recommendations.requestId = 0;
  794. auto parsed = ParseSimilarChannels(_session, result);
  795. _recommendations.peers = std::move(parsed);
  796. _recommendations.peers.more = 0;
  797. _recommendationsLoaded = true;
  798. }).send();
  799. }
  800. const ChatParticipants::Peers &ChatParticipants::recommendations() const {
  801. return _recommendations.peers;
  802. }
  803. rpl::producer<> ChatParticipants::recommendationsLoaded() const {
  804. return _recommendationsLoaded.changes() | rpl::to_empty;
  805. }
  806. } // namespace Api