url_auth_box.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  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 "boxes/url_auth_box.h"
  8. #include "boxes/abstract_box.h"
  9. #include "history/history.h"
  10. #include "history/history_item.h"
  11. #include "history/history_item_components.h"
  12. #include "data/data_session.h"
  13. #include "data/data_user.h"
  14. #include "core/click_handler_types.h"
  15. #include "ui/text/text_utilities.h"
  16. #include "ui/wrap/vertical_layout.h"
  17. #include "ui/widgets/checkbox.h"
  18. #include "ui/widgets/labels.h"
  19. #include "lang/lang_keys.h"
  20. #include "main/main_session.h"
  21. #include "apiwrap.h"
  22. #include "styles/style_layers.h"
  23. #include "styles/style_boxes.h"
  24. void UrlAuthBox::Activate(
  25. not_null<const HistoryItem*> message,
  26. int row,
  27. int column) {
  28. const auto itemId = message->fullId();
  29. const auto button = HistoryMessageMarkupButton::Get(
  30. &message->history()->owner(),
  31. itemId,
  32. row,
  33. column);
  34. if (button->requestId || !message->isRegular()) {
  35. return;
  36. }
  37. const auto session = &message->history()->session();
  38. const auto inputPeer = message->history()->peer->input;
  39. const auto buttonId = button->buttonId;
  40. const auto url = QString::fromUtf8(button->data);
  41. using Flag = MTPmessages_RequestUrlAuth::Flag;
  42. button->requestId = session->api().request(MTPmessages_RequestUrlAuth(
  43. MTP_flags(Flag::f_peer | Flag::f_msg_id | Flag::f_button_id),
  44. inputPeer,
  45. MTP_int(itemId.msg),
  46. MTP_int(buttonId),
  47. MTPstring() // #TODO auth url
  48. )).done([=](const MTPUrlAuthResult &result) {
  49. const auto button = HistoryMessageMarkupButton::Get(
  50. &session->data(),
  51. itemId,
  52. row,
  53. column);
  54. if (!button) {
  55. return;
  56. }
  57. button->requestId = 0;
  58. result.match([&](const MTPDurlAuthResultAccepted &data) {
  59. UrlClickHandler::Open(qs(data.vurl()));
  60. }, [&](const MTPDurlAuthResultDefault &data) {
  61. HiddenUrlClickHandler::Open(url);
  62. }, [&](const MTPDurlAuthResultRequest &data) {
  63. if (const auto item = session->data().message(itemId)) {
  64. Request(data, item, row, column);
  65. }
  66. });
  67. }).fail([=] {
  68. const auto button = HistoryMessageMarkupButton::Get(
  69. &session->data(),
  70. itemId,
  71. row,
  72. column);
  73. if (!button) return;
  74. button->requestId = 0;
  75. HiddenUrlClickHandler::Open(url);
  76. }).send();
  77. }
  78. void UrlAuthBox::Activate(
  79. not_null<Main::Session*> session,
  80. const QString &url,
  81. QVariant context) {
  82. context = QVariant::fromValue([&] {
  83. auto result = context.value<ClickHandlerContext>();
  84. result.skipBotAutoLogin = true;
  85. return result;
  86. }());
  87. using Flag = MTPmessages_RequestUrlAuth::Flag;
  88. session->api().request(MTPmessages_RequestUrlAuth(
  89. MTP_flags(Flag::f_url),
  90. MTPInputPeer(),
  91. MTPint(), // msg_id
  92. MTPint(), // button_id
  93. MTP_string(url)
  94. )).done([=](const MTPUrlAuthResult &result) {
  95. result.match([&](const MTPDurlAuthResultAccepted &data) {
  96. UrlClickHandler::Open(qs(data.vurl()), context);
  97. }, [&](const MTPDurlAuthResultDefault &data) {
  98. HiddenUrlClickHandler::Open(url, context);
  99. }, [&](const MTPDurlAuthResultRequest &data) {
  100. Request(data, session, url, context);
  101. });
  102. }).fail([=] {
  103. HiddenUrlClickHandler::Open(url, context);
  104. }).send();
  105. }
  106. void UrlAuthBox::Request(
  107. const MTPDurlAuthResultRequest &request,
  108. not_null<const HistoryItem*> message,
  109. int row,
  110. int column) {
  111. const auto itemId = message->fullId();
  112. const auto button = HistoryMessageMarkupButton::Get(
  113. &message->history()->owner(),
  114. itemId,
  115. row,
  116. column);
  117. if (button->requestId || !message->isRegular()) {
  118. return;
  119. }
  120. const auto session = &message->history()->session();
  121. const auto inputPeer = message->history()->peer->input;
  122. const auto buttonId = button->buttonId;
  123. const auto url = QString::fromUtf8(button->data);
  124. const auto bot = request.is_request_write_access()
  125. ? session->data().processUser(request.vbot()).get()
  126. : nullptr;
  127. const auto box = std::make_shared<QPointer<Ui::BoxContent>>();
  128. const auto finishWithUrl = [=](const QString &url) {
  129. if (*box) {
  130. (*box)->closeBox();
  131. }
  132. UrlClickHandler::Open(url);
  133. };
  134. const auto callback = [=](Result result) {
  135. if (result == Result::None) {
  136. finishWithUrl(url);
  137. } else if (const auto msg = session->data().message(itemId)) {
  138. const auto allowWrite = (result == Result::AuthAndAllowWrite);
  139. using Flag = MTPmessages_AcceptUrlAuth::Flag;
  140. const auto flags = (allowWrite ? Flag::f_write_allowed : Flag(0))
  141. | (Flag::f_peer | Flag::f_msg_id | Flag::f_button_id);
  142. session->api().request(MTPmessages_AcceptUrlAuth(
  143. MTP_flags(flags),
  144. inputPeer,
  145. MTP_int(itemId.msg),
  146. MTP_int(buttonId),
  147. MTPstring() // #TODO auth url
  148. )).done([=](const MTPUrlAuthResult &result) {
  149. const auto to = result.match(
  150. [&](const MTPDurlAuthResultAccepted &data) {
  151. return qs(data.vurl());
  152. }, [&](const MTPDurlAuthResultDefault &data) {
  153. return url;
  154. }, [&](const MTPDurlAuthResultRequest &data) {
  155. LOG(("API Error: "
  156. "got urlAuthResultRequest after acceptUrlAuth."));
  157. return url;
  158. });
  159. finishWithUrl(to);
  160. }).fail([=] {
  161. finishWithUrl(url);
  162. }).send();
  163. }
  164. };
  165. *box = Ui::show(
  166. Box<UrlAuthBox>(session, url, qs(request.vdomain()), bot, callback),
  167. Ui::LayerOption::KeepOther);
  168. }
  169. void UrlAuthBox::Request(
  170. const MTPDurlAuthResultRequest &request,
  171. not_null<Main::Session*> session,
  172. const QString &url,
  173. QVariant context) {
  174. const auto bot = request.is_request_write_access()
  175. ? session->data().processUser(request.vbot()).get()
  176. : nullptr;
  177. const auto box = std::make_shared<QPointer<Ui::BoxContent>>();
  178. const auto finishWithUrl = [=](const QString &url) {
  179. if (*box) {
  180. (*box)->closeBox();
  181. }
  182. UrlClickHandler::Open(url, context);
  183. };
  184. const auto callback = [=](Result result) {
  185. if (result == Result::None) {
  186. finishWithUrl(url);
  187. } else {
  188. const auto allowWrite = (result == Result::AuthAndAllowWrite);
  189. using Flag = MTPmessages_AcceptUrlAuth::Flag;
  190. const auto flags = (allowWrite ? Flag::f_write_allowed : Flag(0))
  191. | Flag::f_url;
  192. session->api().request(MTPmessages_AcceptUrlAuth(
  193. MTP_flags(flags),
  194. MTPInputPeer(),
  195. MTPint(), // msg_id
  196. MTPint(), // button_id
  197. MTP_string(url)
  198. )).done([=](const MTPUrlAuthResult &result) {
  199. const auto to = result.match(
  200. [&](const MTPDurlAuthResultAccepted &data) {
  201. return qs(data.vurl());
  202. }, [&](const MTPDurlAuthResultDefault &data) {
  203. return url;
  204. }, [&](const MTPDurlAuthResultRequest &data) {
  205. LOG(("API Error: "
  206. "got urlAuthResultRequest after acceptUrlAuth."));
  207. return url;
  208. });
  209. finishWithUrl(to);
  210. }).fail([=] {
  211. finishWithUrl(url);
  212. }).send();
  213. }
  214. };
  215. *box = Ui::show(
  216. Box<UrlAuthBox>(session, url, qs(request.vdomain()), bot, callback),
  217. Ui::LayerOption::KeepOther);
  218. }
  219. UrlAuthBox::UrlAuthBox(
  220. QWidget*,
  221. not_null<Main::Session*> session,
  222. const QString &url,
  223. const QString &domain,
  224. UserData *bot,
  225. Fn<void(Result)> callback)
  226. : _content(setupContent(session, url, domain, bot, std::move(callback))) {
  227. }
  228. void UrlAuthBox::prepare() {
  229. setDimensionsToContent(st::boxWidth, _content);
  230. addButton(tr::lng_open_link(), [=] { _callback(); });
  231. addButton(tr::lng_cancel(), [=] { closeBox(); });
  232. }
  233. not_null<Ui::RpWidget*> UrlAuthBox::setupContent(
  234. not_null<Main::Session*> session,
  235. const QString &url,
  236. const QString &domain,
  237. UserData *bot,
  238. Fn<void(Result)> callback) {
  239. const auto result = Ui::CreateChild<Ui::VerticalLayout>(this);
  240. result->add(
  241. object_ptr<Ui::FlatLabel>(
  242. result,
  243. tr::lng_url_auth_open_confirm(tr::now, lt_link, url),
  244. st::boxLabel),
  245. st::boxPadding);
  246. const auto addCheckbox = [&](const TextWithEntities &text) {
  247. const auto checkbox = result->add(
  248. object_ptr<Ui::Checkbox>(
  249. result,
  250. text,
  251. true,
  252. st::urlAuthCheckbox),
  253. style::margins(
  254. st::boxPadding.left(),
  255. st::boxPadding.bottom(),
  256. st::boxPadding.right(),
  257. st::boxPadding.bottom()));
  258. checkbox->setAllowTextLines();
  259. return checkbox;
  260. };
  261. const auto auth = addCheckbox(
  262. tr::lng_url_auth_login_option(
  263. tr::now,
  264. lt_domain,
  265. Ui::Text::Bold(domain),
  266. lt_user,
  267. Ui::Text::Bold(session->user()->name()),
  268. Ui::Text::WithEntities));
  269. const auto allow = bot
  270. ? addCheckbox(tr::lng_url_auth_allow_messages(
  271. tr::now,
  272. lt_bot,
  273. Ui::Text::Bold(bot->firstName),
  274. Ui::Text::WithEntities))
  275. : nullptr;
  276. if (allow) {
  277. rpl::single(
  278. auth->checked()
  279. ) | rpl::then(
  280. auth->checkedChanges()
  281. ) | rpl::start_with_next([=](bool checked) {
  282. if (!checked) {
  283. allow->setChecked(false);
  284. }
  285. allow->setDisabled(!checked);
  286. }, auth->lifetime());
  287. }
  288. _callback = [=, callback = std::move(callback)]() {
  289. const auto authed = auth->checked();
  290. const auto allowed = (authed && allow && allow->checked());
  291. const auto onstack = callback;
  292. onstack(allowed
  293. ? Result::AuthAndAllowWrite
  294. : authed
  295. ? Result::Auth
  296. : Result::None);
  297. };
  298. return result;
  299. }