menu_antispam_validator.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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 "menu/menu_antispam_validator.h"
  8. #include "apiwrap.h"
  9. #include "boxes/peers/edit_participants_box.h"
  10. #include "boxes/peers/edit_peer_info_box.h"
  11. #include "data/data_changes.h"
  12. #include "data/data_channel.h"
  13. #include "data/data_session.h"
  14. #include "history/history_item.h"
  15. #include "lang/lang_keys.h"
  16. #include "main/main_app_config.h"
  17. #include "main/main_session.h"
  18. #include "settings/settings_common.h" // IconDescriptor.
  19. #include "ui/text/text_utilities.h"
  20. #include "ui/toast/toast.h"
  21. #include "ui/vertical_list.h"
  22. #include "ui/widgets/buttons.h"
  23. #include "ui/widgets/popup_menu.h"
  24. #include "ui/wrap/slide_wrap.h"
  25. #include "ui/wrap/vertical_layout.h"
  26. #include "window/window_session_controller.h"
  27. #include "styles/style_info.h"
  28. #include "styles/style_menu_icons.h"
  29. #include "styles/style_settings.h"
  30. namespace AntiSpamMenu {
  31. namespace {
  32. [[nodiscard]] int EnableAntiSpamMinMembers(not_null<ChannelData*> channel) {
  33. return channel->session().appConfig().get<int>(
  34. u"telegram_antispam_group_size_min"_q,
  35. 100);
  36. }
  37. [[nodiscard]] UserId AntiSpamUserId(not_null<ChannelData*> channel) {
  38. const auto id = channel->session().appConfig().get<QString>(
  39. u"telegram_antispam_user_id"_q,
  40. QString());
  41. return UserId(id.toULongLong());
  42. }
  43. } // namespace
  44. AntiSpamValidator::AntiSpamValidator(
  45. not_null<Window::SessionController*> controller,
  46. not_null<ChannelData*> channel)
  47. : _channel(channel)
  48. , _controller(controller) {
  49. }
  50. object_ptr<Ui::RpWidget> AntiSpamValidator::createButton() const {
  51. const auto channel = _channel;
  52. auto container = object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
  53. (QWidget*)nullptr,
  54. object_ptr<Ui::VerticalLayout>((QWidget*)nullptr));
  55. struct State {
  56. rpl::variable<bool> locked;
  57. rpl::event_stream<bool> toggled;
  58. };
  59. Ui::AddSkip(container->entity());
  60. const auto state = container->lifetime().make_state<State>();
  61. const auto button = container->entity()->add(
  62. EditPeerInfoBox::CreateButton(
  63. container->entity(),
  64. tr::lng_manage_peer_antispam(),
  65. rpl::single(QString()),
  66. [] {},
  67. st::manageGroupTopicsButton,
  68. { &st::menuIconAntispam }
  69. ))->toggleOn(rpl::single(
  70. _channel->antiSpamMode()
  71. ) | rpl::then(state->toggled.events()));
  72. container->show(anim::type::instant);
  73. Ui::AddSkip(container->entity());
  74. Ui::AddDividerText(
  75. container->entity(),
  76. tr::lng_manage_peer_antispam_about());
  77. const auto updateLocked = [=] {
  78. const auto min = EnableAntiSpamMinMembers(channel);
  79. const auto locked = (channel->membersCount() < min);
  80. state->locked = locked;
  81. button->setToggleLocked(locked);
  82. };
  83. using UpdateFlag = Data::PeerUpdate::Flag;
  84. _channel->session().changes().peerUpdates(
  85. _channel,
  86. UpdateFlag::Members | UpdateFlag::Admins
  87. ) | rpl::start_with_next(updateLocked, button->lifetime());
  88. updateLocked();
  89. button->toggledValue(
  90. ) | rpl::start_with_next([=, controller = _controller](bool toggled) {
  91. if (state->locked.current() && toggled) {
  92. state->toggled.fire(false);
  93. controller->showToast(tr::lng_manage_peer_antispam_not_enough(
  94. tr::now,
  95. lt_count,
  96. EnableAntiSpamMinMembers(channel),
  97. Ui::Text::RichLangValue));
  98. } else {
  99. channel->session().api().request(MTPchannels_ToggleAntiSpam(
  100. channel->inputChannel,
  101. MTP_bool(toggled)
  102. )).done([=](const MTPUpdates &result) {
  103. channel->session().api().applyUpdates(result);
  104. }).send();
  105. }
  106. }, button->lifetime());
  107. return container;
  108. }
  109. void AntiSpamValidator::resolveUser(Fn<void()> finish) const {
  110. if (_channel->antiSpamMode()) {
  111. const auto mtpUserId = peerToBareMTPInt(AntiSpamUserId(_channel));
  112. _channel->session().api().request(MTPusers_GetUsers(
  113. MTP_vector<MTPInputUser>(1, MTP_inputUser(mtpUserId, MTPlong()))
  114. )).done([=, channel = _channel](const MTPVector<MTPUser> &result) {
  115. channel->owner().processUsers(result);
  116. finish();
  117. }).fail([=] {
  118. finish();
  119. }).send();
  120. } else {
  121. finish();
  122. }
  123. }
  124. UserData *AntiSpamValidator::maybeAppendUser() const {
  125. if (_channel->antiSpamMode()) {
  126. const auto userId = AntiSpamUserId(_channel);
  127. if (const auto user = _channel->owner().user(userId)) {
  128. return user;
  129. }
  130. }
  131. return nullptr;
  132. }
  133. UserId AntiSpamValidator::userId() const {
  134. return AntiSpamUserId(_channel);
  135. }
  136. void AntiSpamValidator::addAction(
  137. not_null<Ui::PopupMenu*> menu,
  138. FullMsgId fakeId) const {
  139. if (!fakeId) {
  140. return;
  141. }
  142. const auto suggestReport = [&](MsgId eventId) {
  143. const auto text = tr::lng_admin_log_antispam_menu_report_toast(
  144. tr::now,
  145. lt_link,
  146. Ui::Text::Link(
  147. tr::lng_admin_log_antispam_menu_report_toast_link(
  148. tr::now),
  149. "internal:show"),
  150. Ui::Text::RichLangValue);
  151. const auto showToast = [=,
  152. window = _controller,
  153. channel = _channel] {
  154. window->showToast({
  155. .text = text,
  156. .filter = [=](
  157. const ClickHandlerPtr&,
  158. Qt::MouseButton) {
  159. ParticipantsBoxController::Start(
  160. window,
  161. channel,
  162. ParticipantsRole::Admins);
  163. return true;
  164. },
  165. .duration = ApiWrap::kJoinErrorDuration,
  166. });
  167. };
  168. menu->addAction(
  169. tr::lng_admin_log_antispam_menu_report(tr::now),
  170. [=, channel = _channel] {
  171. _channel->session().api().request(
  172. MTPchannels_ReportAntiSpamFalsePositive(
  173. channel->inputChannel,
  174. MTP_int(eventId)
  175. )).done(showToast).send();
  176. },
  177. &st::menuIconReportAntiSpam);
  178. };
  179. {
  180. const auto it = _itemEventMsgIds.find(fakeId);
  181. if (it != end(_itemEventMsgIds)) {
  182. suggestReport(it->second);
  183. menu->addSeparator();
  184. }
  185. }
  186. }
  187. void AntiSpamValidator::addEventMsgId(FullMsgId fakeId, MsgId realId) {
  188. _itemEventMsgIds.emplace(fakeId, realId);
  189. }
  190. } // namespace AntiSpamMenu