api_user_names.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  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_user_names.h"
  8. #include "apiwrap.h"
  9. #include "data/data_channel.h"
  10. #include "data/data_peer.h"
  11. #include "data/data_user.h"
  12. #include "main/main_session.h"
  13. namespace Api {
  14. namespace {
  15. [[nodiscard]] Data::Username UsernameFromTL(const MTPUsername &username) {
  16. return {
  17. .username = qs(username.data().vusername()),
  18. .active = username.data().is_active(),
  19. .editable = username.data().is_editable(),
  20. };
  21. }
  22. [[nodiscard]] std::optional<MTPInputUser> BotUserInput(
  23. not_null<PeerData*> peer) {
  24. const auto user = peer->asUser();
  25. return (user && user->botInfo && user->botInfo->canEditInformation)
  26. ? std::make_optional<MTPInputUser>(user->inputUser)
  27. : std::nullopt;
  28. }
  29. } // namespace
  30. Usernames::Usernames(not_null<ApiWrap*> api)
  31. : _session(&api->session())
  32. , _api(&api->instance()) {
  33. }
  34. rpl::producer<Data::Usernames> Usernames::loadUsernames(
  35. not_null<PeerData*> peer) const {
  36. return [=](auto consumer) {
  37. auto lifetime = rpl::lifetime();
  38. const auto push = [consumer](
  39. const auto &usernames,
  40. const auto &username) {
  41. if (usernames) {
  42. if (usernames->v.empty()) {
  43. // Probably will never happen.
  44. consumer.put_next({});
  45. } else {
  46. auto parsed = FromTL(*usernames);
  47. if ((parsed.size() == 1)
  48. && username
  49. && (parsed.front().username == qs(*username))) {
  50. // Probably will never happen.
  51. consumer.put_next({});
  52. } else {
  53. consumer.put_next(std::move(parsed));
  54. }
  55. }
  56. } else {
  57. consumer.put_next({});
  58. }
  59. };
  60. const auto requestUser = [&](const MTPInputUser &data) {
  61. _session->api().request(MTPusers_GetUsers(
  62. MTP_vector<MTPInputUser>(1, data)
  63. )).done([=](const MTPVector<MTPUser> &result) {
  64. result.v.front().match([&](const MTPDuser &data) {
  65. push(data.vusernames(), data.vusername());
  66. consumer.put_done();
  67. }, [&](const MTPDuserEmpty&) {
  68. consumer.put_next({});
  69. consumer.put_done();
  70. });
  71. }).send();
  72. };
  73. const auto requestChannel = [&](const MTPInputChannel &data) {
  74. _session->api().request(MTPchannels_GetChannels(
  75. MTP_vector<MTPInputChannel>(1, data)
  76. )).done([=](const MTPmessages_Chats &result) {
  77. result.match([&](const auto &data) {
  78. data.vchats().v.front().match([&](const MTPDchannel &c) {
  79. push(c.vusernames(), c.vusername());
  80. consumer.put_done();
  81. }, [&](auto &&) {
  82. consumer.put_next({});
  83. consumer.put_done();
  84. });
  85. });
  86. }).send();
  87. };
  88. if (peer->isSelf()) {
  89. requestUser(MTP_inputUserSelf());
  90. } else if (const auto user = peer->asUser()) {
  91. requestUser(user->inputUser);
  92. } else if (const auto channel = peer->asChannel()) {
  93. requestChannel(channel->inputChannel);
  94. }
  95. return lifetime;
  96. };
  97. }
  98. rpl::producer<rpl::no_value, Usernames::Error> Usernames::toggle(
  99. not_null<PeerData*> peer,
  100. const QString &username,
  101. bool active) {
  102. const auto peerId = peer->id;
  103. const auto it = _toggleRequests.find(peerId);
  104. const auto found = (it != end(_toggleRequests));
  105. auto &entry = (!found
  106. ? _toggleRequests.emplace(
  107. peerId,
  108. Entry{ .usernames = { username } }).first
  109. : it)->second;
  110. if (ranges::contains(entry.usernames, username)) {
  111. if (found) {
  112. return entry.done.events();
  113. }
  114. } else {
  115. entry.usernames.push_back(username);
  116. }
  117. const auto pop = [=](Error error) {
  118. const auto it = _toggleRequests.find(peerId);
  119. if (it != end(_toggleRequests)) {
  120. auto &list = it->second.usernames;
  121. list.erase(ranges::remove(list, username), end(list));
  122. if (list.empty()) {
  123. if (error == Error::Unknown) {
  124. it->second.done.fire_done();
  125. } else if (error == Error::TooMuch) {
  126. it->second.done.fire_error_copy(error);
  127. }
  128. _toggleRequests.remove(peerId);
  129. }
  130. }
  131. };
  132. const auto done = [=] {
  133. pop(Error::Unknown);
  134. };
  135. const auto fail = [=](const MTP::Error &error) {
  136. const auto type = error.type();
  137. if (type == u"USERNAMES_ACTIVE_TOO_MUCH"_q) {
  138. pop(Error::TooMuch);
  139. } else {
  140. pop(Error::Unknown);
  141. }
  142. };
  143. if (peer->isSelf()) {
  144. _api.request(MTPaccount_ToggleUsername(
  145. MTP_string(username),
  146. MTP_bool(active)
  147. )).done(done).fail(fail).send();
  148. } else if (const auto channel = peer->asChannel()) {
  149. _api.request(MTPchannels_ToggleUsername(
  150. channel->inputChannel,
  151. MTP_string(username),
  152. MTP_bool(active)
  153. )).done(done).fail(fail).send();
  154. } else if (const auto botUserInput = BotUserInput(peer)) {
  155. _api.request(MTPbots_ToggleUsername(
  156. *botUserInput,
  157. MTP_string(username),
  158. MTP_bool(active)
  159. )).done(done).fail(fail).send();
  160. } else {
  161. return rpl::never<rpl::no_value, Error>();
  162. }
  163. return entry.done.events();
  164. }
  165. rpl::producer<> Usernames::reorder(
  166. not_null<PeerData*> peer,
  167. const std::vector<QString> &usernames) {
  168. const auto peerId = peer->id;
  169. const auto it = _reorderRequests.find(peerId);
  170. if (it != end(_reorderRequests)) {
  171. _api.request(it->second).cancel();
  172. _reorderRequests.erase(peerId);
  173. }
  174. return [=](auto consumer) {
  175. auto lifetime = rpl::lifetime();
  176. auto tlUsernames = ranges::views::all(
  177. usernames
  178. ) | ranges::views::transform([](const QString &username) {
  179. return MTP_string(username);
  180. }) | ranges::to<QVector<MTPstring>>;
  181. const auto finish = [=] {
  182. if (_reorderRequests.contains(peerId)) {
  183. _reorderRequests.erase(peerId);
  184. }
  185. consumer.put_done();
  186. };
  187. if (usernames.empty()) {
  188. crl::on_main([=] { consumer.put_done(); });
  189. return lifetime;
  190. }
  191. if (peer->isSelf()) {
  192. const auto requestId = _api.request(MTPaccount_ReorderUsernames(
  193. MTP_vector<MTPstring>(std::move(tlUsernames))
  194. )).done(finish).fail(finish).send();
  195. _reorderRequests.emplace(peerId, requestId);
  196. } else if (const auto channel = peer->asChannel()) {
  197. const auto requestId = _api.request(MTPchannels_ReorderUsernames(
  198. channel->inputChannel,
  199. MTP_vector<MTPstring>(std::move(tlUsernames))
  200. )).done(finish).fail(finish).send();
  201. _reorderRequests.emplace(peerId, requestId);
  202. } else if (const auto botUserInput = BotUserInput(peer)) {
  203. const auto requestId = _api.request(MTPbots_ReorderUsernames(
  204. *botUserInput,
  205. MTP_vector<MTPstring>(std::move(tlUsernames))
  206. )).done(finish).fail(finish).send();
  207. _reorderRequests.emplace(peerId, requestId);
  208. }
  209. return lifetime;
  210. };
  211. }
  212. Data::Usernames Usernames::FromTL(const MTPVector<MTPUsername> &usernames) {
  213. return ranges::views::all(
  214. usernames.v
  215. ) | ranges::views::transform(UsernameFromTL) | ranges::to_vector;
  216. }
  217. void Usernames::requestToCache(not_null<PeerData*> peer) {
  218. _tinyCache = {};
  219. if (const auto user = peer->asUser()) {
  220. if (user->usernames().empty()) {
  221. return;
  222. }
  223. } else if (const auto channel = peer->asChannel()) {
  224. if (channel->usernames().empty()) {
  225. return;
  226. }
  227. }
  228. const auto lifetime = std::make_shared<rpl::lifetime>();
  229. *lifetime = loadUsernames(
  230. peer
  231. ) | rpl::start_with_next([=, id = peer->id](Data::Usernames usernames) {
  232. _tinyCache = std::make_pair(id, std::move(usernames));
  233. lifetime->destroy();
  234. });
  235. }
  236. Data::Usernames Usernames::cacheFor(PeerId id) {
  237. return (_tinyCache.first == id) ? _tinyCache.second : Data::Usernames();
  238. }
  239. } // namespace Api