data_chat_participant_status.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  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 "data/data_chat_participant_status.h"
  8. #include "base/unixtime.h"
  9. #include "boxes/peers/edit_peer_permissions_box.h"
  10. #include "chat_helpers/compose/compose_show.h"
  11. #include "data/data_chat.h"
  12. #include "data/data_channel.h"
  13. #include "data/data_forum_topic.h"
  14. #include "data/data_peer_values.h"
  15. #include "data/data_user.h"
  16. #include "lang/lang_keys.h"
  17. #include "main/main_session.h"
  18. #include "ui/boxes/confirm_box.h"
  19. #include "ui/chat/attach/attach_prepare.h"
  20. #include "ui/layers/generic_box.h"
  21. #include "ui/text/text_utilities.h"
  22. #include "ui/toast/toast.h"
  23. #include "window/window_session_controller.h"
  24. #include "styles/style_widgets.h"
  25. namespace {
  26. [[nodiscard]] ChatAdminRights ChatAdminRightsFlags(
  27. const MTPChatAdminRights &rights) {
  28. return rights.match([](const MTPDchatAdminRights &data) {
  29. return ChatAdminRights::from_raw(int32(data.vflags().v));
  30. });
  31. }
  32. [[nodiscard]] ChatRestrictions ChatBannedRightsFlags(
  33. const MTPChatBannedRights &rights) {
  34. return rights.match([](const MTPDchatBannedRights &data) {
  35. return ChatRestrictions::from_raw(int32(data.vflags().v));
  36. });
  37. }
  38. [[nodiscard]] TimeId ChatBannedRightsUntilDate(
  39. const MTPChatBannedRights &rights) {
  40. return rights.match([](const MTPDchatBannedRights &data) {
  41. return data.vuntil_date().v;
  42. });
  43. }
  44. } // namespace
  45. ChatAdminRightsInfo::ChatAdminRightsInfo(const MTPChatAdminRights &rights)
  46. : flags(ChatAdminRightsFlags(rights)) {
  47. }
  48. ChatRestrictionsInfo::ChatRestrictionsInfo(const MTPChatBannedRights &rights)
  49. : flags(ChatBannedRightsFlags(rights))
  50. , until(ChatBannedRightsUntilDate(rights)) {
  51. }
  52. namespace Data {
  53. std::vector<ChatRestrictions> ListOfRestrictions(
  54. RestrictionsSetOptions options) {
  55. auto labels = RestrictionLabels(options);
  56. return ranges::views::all(labels)
  57. | ranges::views::transform(&RestrictionLabel::flags)
  58. | ranges::to_vector;
  59. }
  60. ChatRestrictions AllSendRestrictions() {
  61. constexpr auto result = [] {
  62. auto result = ChatRestrictions();
  63. for (const auto right : AllSendRestrictionsList()) {
  64. result |= right;
  65. }
  66. return result;
  67. }();
  68. return result;
  69. }
  70. ChatRestrictions FilesSendRestrictions() {
  71. constexpr auto result = [] {
  72. auto result = ChatRestrictions();
  73. for (const auto right : FilesSendRestrictionsList()) {
  74. result |= right;
  75. }
  76. return result;
  77. }();
  78. return result;
  79. }
  80. ChatRestrictions TabbedPanelSendRestrictions() {
  81. constexpr auto result = [] {
  82. auto result = ChatRestrictions();
  83. for (const auto right : TabbedPanelSendRestrictionsList()) {
  84. result |= right;
  85. }
  86. return result;
  87. }();
  88. return result;
  89. }
  90. // Duplicated in CanSendAnyOfValue().
  91. bool CanSendAnyOf(
  92. not_null<const Thread*> thread,
  93. ChatRestrictions rights,
  94. bool forbidInForums) {
  95. const auto peer = thread->peer();
  96. const auto topic = thread->asTopic();
  97. return CanSendAnyOf(peer, rights, forbidInForums && !topic)
  98. && (!topic || !topic->closed() || topic->canToggleClosed());
  99. }
  100. // Duplicated in CanSendAnyOfValue().
  101. bool CanSendAnyOf(
  102. not_null<const PeerData*> peer,
  103. ChatRestrictions rights,
  104. bool forbidInForums) {
  105. if (const auto user = peer->asUser()) {
  106. if (user->isInaccessible()
  107. || user->isRepliesChat()
  108. || user->isVerifyCodes()) {
  109. return false;
  110. } else if (user->requiresPremiumToWrite()
  111. && !user->session().premium()) {
  112. return false;
  113. } else if (rights
  114. & ~(ChatRestriction::SendVoiceMessages
  115. | ChatRestriction::SendVideoMessages
  116. | ChatRestriction::SendPolls)) {
  117. return true;
  118. }
  119. for (const auto right : {
  120. ChatRestriction::SendVoiceMessages,
  121. ChatRestriction::SendVideoMessages,
  122. ChatRestriction::SendPolls,
  123. }) {
  124. if ((rights & right) && !user->amRestricted(right)) {
  125. return true;
  126. }
  127. }
  128. return false;
  129. } else if (const auto chat = peer->asChat()) {
  130. if (!chat->amIn()) {
  131. return false;
  132. }
  133. for (const auto right : AllSendRestrictionsList()) {
  134. if ((rights & right) && !chat->amRestricted(right)) {
  135. return true;
  136. }
  137. }
  138. return false;
  139. } else if (const auto channel = peer->asChannel()) {
  140. using Flag = ChannelDataFlag;
  141. const auto allowed = channel->amIn()
  142. || ((channel->flags() & Flag::HasLink)
  143. && !(channel->flags() & Flag::JoinToWrite));
  144. if (!allowed || (forbidInForums && channel->isForum())) {
  145. return false;
  146. } else if (channel->canPostMessages()) {
  147. return true;
  148. } else if (channel->isBroadcast()) {
  149. return false;
  150. }
  151. for (const auto right : AllSendRestrictionsList()) {
  152. if ((rights & right) && !channel->amRestricted(right)) {
  153. return true;
  154. }
  155. }
  156. return false;
  157. }
  158. Unexpected("Peer type in CanSendAnyOf.");
  159. }
  160. SendError RestrictionError(
  161. not_null<PeerData*> peer,
  162. ChatRestriction restriction) {
  163. using Flag = ChatRestriction;
  164. if (const auto restricted = peer->amRestricted(restriction)) {
  165. if (const auto user = peer->asUser()) {
  166. if (user->requiresPremiumToWrite()
  167. && !user->session().premium()) {
  168. return SendError({
  169. .text = tr::lng_restricted_send_non_premium(
  170. tr::now,
  171. lt_user,
  172. user->shortName()),
  173. .premiumToLift = true,
  174. });
  175. }
  176. const auto result = (restriction == Flag::SendVoiceMessages)
  177. ? tr::lng_restricted_send_voice_messages(
  178. tr::now,
  179. lt_user,
  180. user->name())
  181. : (restriction == Flag::SendVideoMessages)
  182. ? tr::lng_restricted_send_video_messages(
  183. tr::now,
  184. lt_user,
  185. user->name())
  186. : (restriction == Flag::SendPolls)
  187. ? u"can't send polls :("_q
  188. : (restriction == Flag::PinMessages)
  189. ? u"can't pin :("_q
  190. : SendError();
  191. Ensures(result.has_value());
  192. return result;
  193. }
  194. const auto all = restricted.isWithEveryone();
  195. const auto channel = peer->asChannel();
  196. if (!all && channel) {
  197. auto restrictedUntil = channel->restrictedUntil();
  198. if (restrictedUntil > 0
  199. && !ChannelData::IsRestrictedForever(restrictedUntil)) {
  200. auto restrictedUntilDateTime = base::unixtime::parse(
  201. channel->restrictedUntil());
  202. auto date = QLocale().toString(
  203. restrictedUntilDateTime.date(),
  204. QLocale::ShortFormat);
  205. auto time = QLocale().toString(
  206. restrictedUntilDateTime.time(),
  207. QLocale::ShortFormat);
  208. switch (restriction) {
  209. case Flag::SendPolls:
  210. return tr::lng_restricted_send_polls_until(
  211. tr::now, lt_date, date, lt_time, time);
  212. case Flag::SendOther:
  213. return tr::lng_restricted_send_message_until(
  214. tr::now, lt_date, date, lt_time, time);
  215. case Flag::SendPhotos:
  216. return tr::lng_restricted_send_photos_until(
  217. tr::now, lt_date, date, lt_time, time);
  218. case Flag::SendVideos:
  219. return tr::lng_restricted_send_videos_until(
  220. tr::now, lt_date, date, lt_time, time);
  221. case Flag::SendMusic:
  222. return tr::lng_restricted_send_music_until(
  223. tr::now, lt_date, date, lt_time, time);
  224. case Flag::SendFiles:
  225. return tr::lng_restricted_send_files_until(
  226. tr::now, lt_date, date, lt_time, time);
  227. case Flag::SendVideoMessages:
  228. return tr::lng_restricted_send_video_messages_until(
  229. tr::now, lt_date, date, lt_time, time);
  230. case Flag::SendVoiceMessages:
  231. return tr::lng_restricted_send_voice_messages_until(
  232. tr::now, lt_date, date, lt_time, time);
  233. case Flag::SendStickers:
  234. return tr::lng_restricted_send_stickers_until(
  235. tr::now, lt_date, date, lt_time, time);
  236. case Flag::SendGifs:
  237. return tr::lng_restricted_send_gifs_until(
  238. tr::now, lt_date, date, lt_time, time);
  239. case Flag::SendInline:
  240. case Flag::SendGames:
  241. return tr::lng_restricted_send_inline_until(
  242. tr::now, lt_date, date, lt_time, time);
  243. }
  244. Unexpected("Restriction in Data::RestrictionErrorKey.");
  245. }
  246. }
  247. if (all
  248. && channel
  249. && channel->boostsUnrestrict()
  250. && !channel->unrestrictedByBoosts()) {
  251. return SendError({
  252. .text = tr::lng_restricted_boost_group(tr::now),
  253. .boostsToLift = (channel->boostsUnrestrict()
  254. - channel->boostsApplied()),
  255. });
  256. }
  257. switch (restriction) {
  258. case Flag::SendPolls:
  259. return all
  260. ? tr::lng_restricted_send_polls_all(tr::now)
  261. : tr::lng_restricted_send_polls(tr::now);
  262. case Flag::SendOther:
  263. return all
  264. ? tr::lng_restricted_send_message_all(tr::now)
  265. : tr::lng_restricted_send_message(tr::now);
  266. case Flag::SendPhotos:
  267. return all
  268. ? tr::lng_restricted_send_photos_all(tr::now)
  269. : tr::lng_restricted_send_photos(tr::now);
  270. case Flag::SendVideos:
  271. return all
  272. ? tr::lng_restricted_send_videos_all(tr::now)
  273. : tr::lng_restricted_send_videos(tr::now);
  274. case Flag::SendMusic:
  275. return all
  276. ? tr::lng_restricted_send_music_all(tr::now)
  277. : tr::lng_restricted_send_music(tr::now);
  278. case Flag::SendFiles:
  279. return all
  280. ? tr::lng_restricted_send_files_all(tr::now)
  281. : tr::lng_restricted_send_files(tr::now);
  282. case Flag::SendVideoMessages:
  283. return all
  284. ? tr::lng_restricted_send_video_messages_all(tr::now)
  285. : tr::lng_restricted_send_video_messages_group(tr::now);
  286. case Flag::SendVoiceMessages:
  287. return all
  288. ? tr::lng_restricted_send_voice_messages_all(tr::now)
  289. : tr::lng_restricted_send_voice_messages_group(tr::now);
  290. case Flag::SendStickers:
  291. return all
  292. ? tr::lng_restricted_send_stickers_all(tr::now)
  293. : tr::lng_restricted_send_stickers(tr::now);
  294. case Flag::SendGifs:
  295. return all
  296. ? tr::lng_restricted_send_gifs_all(tr::now)
  297. : tr::lng_restricted_send_gifs(tr::now);
  298. case Flag::SendInline:
  299. case Flag::SendGames:
  300. return all
  301. ? tr::lng_restricted_send_inline_all(tr::now)
  302. : tr::lng_restricted_send_inline(tr::now);
  303. }
  304. Unexpected("Restriction in Data::RestrictionErrorKey.");
  305. }
  306. return SendError();
  307. }
  308. SendError AnyFileRestrictionError(not_null<PeerData*> peer) {
  309. using Restriction = ChatRestriction;
  310. for (const auto right : FilesSendRestrictionsList()) {
  311. if (!RestrictionError(peer, right)) {
  312. return {};
  313. }
  314. }
  315. return RestrictionError(peer, Restriction::SendFiles);
  316. }
  317. SendError FileRestrictionError(
  318. not_null<PeerData*> peer,
  319. const Ui::PreparedList &list,
  320. std::optional<bool> compress) {
  321. const auto slowmode = peer->slowmodeApplied();
  322. if (slowmode) {
  323. if (!list.canBeSentInSlowmode()) {
  324. return tr::lng_slowmode_no_many(tr::now);
  325. } else if (list.files.size() > 1 && list.hasSticker()) {
  326. if (compress == false) {
  327. return tr::lng_slowmode_no_many(tr::now);
  328. } else {
  329. compress = true;
  330. }
  331. }
  332. }
  333. for (const auto &file : list.files) {
  334. if (const auto error = FileRestrictionError(peer, file, compress)) {
  335. return error;
  336. }
  337. }
  338. return {};
  339. }
  340. SendError FileRestrictionError(
  341. not_null<PeerData*> peer,
  342. const Ui::PreparedFile &file,
  343. std::optional<bool> compress) {
  344. using Type = Ui::PreparedFile::Type;
  345. using Restriction = ChatRestriction;
  346. const auto stickers = RestrictionError(peer, Restriction::SendStickers);
  347. const auto gifs = RestrictionError(peer, Restriction::SendGifs);
  348. const auto photos = RestrictionError(peer, Restriction::SendPhotos);
  349. const auto videos = RestrictionError(peer, Restriction::SendVideos);
  350. const auto music = RestrictionError(peer, Restriction::SendMusic);
  351. const auto files = RestrictionError(peer, Restriction::SendFiles);
  352. if (!stickers && !gifs && !photos && !videos && !music && !files) {
  353. return {};
  354. }
  355. switch (file.type) {
  356. case Type::Photo:
  357. if (compress == true && photos) {
  358. return photos;
  359. } else if (const auto other = file.isSticker() ? stickers : files) {
  360. if ((compress == false || photos) && other) {
  361. return (file.isSticker() || !photos) ? other : photos;
  362. }
  363. }
  364. break;
  365. case Type::Video:
  366. if (const auto error = file.isGifv() ? gifs : videos) {
  367. return error;
  368. }
  369. break;
  370. case Type::Music:
  371. if (music) {
  372. return music;
  373. }
  374. break;
  375. case Type::File:
  376. if (files) {
  377. return files;
  378. }
  379. break;
  380. }
  381. return {};
  382. }
  383. void ShowSendErrorToast(
  384. not_null<Window::SessionNavigation*> navigation,
  385. not_null<PeerData*> peer,
  386. Data::SendError error) {
  387. return ShowSendErrorToast(navigation->uiShow(), peer, error);
  388. }
  389. void ShowSendErrorToast(
  390. std::shared_ptr<ChatHelpers::Show> show,
  391. not_null<PeerData*> peer,
  392. Data::SendError error) {
  393. if (!error.boostsToLift) {
  394. show->showToast(*error);
  395. return;
  396. }
  397. const auto boost = [=] {
  398. const auto window = show->resolveWindow();
  399. window->resolveBoostState(peer->asChannel(), error.boostsToLift);
  400. };
  401. show->showToast({
  402. .text = Ui::Text::Link(*error),
  403. .filter = [=](const auto &...) { boost(); return false; },
  404. });
  405. }
  406. } // namespace Data