From 02ad5f2772109b9535fd5e0b20d6214aea15849b Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 14 Jan 2021 13:05:14 +0400 Subject: [PATCH] Update API scheme and start invite links. --- Telegram/CMakeLists.txt | 2 + Telegram/Resources/langs/lang.strings | 2 + Telegram/Resources/tl/api.tl | 9 +- Telegram/SourceFiles/api/api_invite_links.cpp | 206 ++++++++++++++++++ Telegram/SourceFiles/api/api_invite_links.h | 85 ++++++++ Telegram/SourceFiles/apiwrap.cpp | 38 +--- Telegram/SourceFiles/apiwrap.h | 5 +- .../SourceFiles/boxes/add_contact_box.cpp | 3 +- Telegram/SourceFiles/boxes/confirm_box.cpp | 3 +- .../boxes/peers/edit_peer_info_box.cpp | 71 ++++++ .../boxes/peers/edit_peer_type_box.cpp | 34 +-- 11 files changed, 403 insertions(+), 55 deletions(-) create mode 100644 Telegram/SourceFiles/api/api_invite_links.cpp create mode 100644 Telegram/SourceFiles/api/api_invite_links.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 81df3d5aa..9de5f9162 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -145,6 +145,8 @@ PRIVATE api/api_global_privacy.h api/api_hash.cpp api/api_hash.h + api/api_invite_links.cpp + api/api_invite_links.h api/api_media.cpp api/api_media.h api/api_self_destruct.cpp diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index dcfb9aead..0afb64248 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -932,6 +932,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_manage_peer_exceptions" = "Exceptions"; "lng_manage_peer_removed_users" = "Removed users"; "lng_manage_peer_permissions" = "Permissions"; +"lng_manage_peer_invite_links" = "Invite links"; + "lng_manage_peer_group_type" = "Group type"; "lng_manage_peer_channel_type" = "Channel type"; diff --git a/Telegram/Resources/tl/api.tl b/Telegram/Resources/tl/api.tl index 11d67bbe6..1d2d02630 100644 --- a/Telegram/Resources/tl/api.tl +++ b/Telegram/Resources/tl/api.tl @@ -535,7 +535,7 @@ auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; -chatInviteExported#a9a847ea flags:# revoked:flags.0?true link:string admin_id:int date:int expire_date:flags.1?int usage_limit:flags.2?int usage:flags.3?int = ExportedChatInvite; +chatInviteExported#a9a847ea flags:# revoked:flags.0?true expired:flags.4?true permanent:flags.5?true link:string admin_id:int date:int expire_date:flags.1?int usage_limit:flags.2?int usage:flags.3?int = ExportedChatInvite; chatInviteAlready#5a686d7c chat:Chat = ChatInvite; chatInvite#dfc2f58e flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:Photo participants_count:int participants:flags.4?Vector = ChatInvite; @@ -1210,7 +1210,7 @@ chatInviteImporter#1e3e6680 user_id:int date:int = ChatInviteImporter; messages.exportedChatInvites#bdc62dcc count:int invites:Vector users:Vector = messages.ExportedChatInvites; -messages.exportedChatInvite#97c5e3a9 invite:ExportedChatInvite recent_importers:Vector users:Vector = messages.ExportedChatInvite; +messages.exportedChatInvite#1871be50 invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; messages.chatInviteImporters#81b6b00a count:int importers:Vector users:Vector = messages.ChatInviteImporters; @@ -1373,7 +1373,7 @@ messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages messages.getStickers#43d4f2c emoticon:string hash:int = messages.Stickers; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector = MessageMedia; -messages.exportChatInvite#14b9bcd7 flags:# peer:InputPeer expire_date:flags.0?int usage_limit:flags.1?int = ExportedChatInvite; +messages.exportChatInvite#14b9bcd7 flags:# legacy_revoke_permanent:flags.2?true peer:InputPeer expire_date:flags.0?int usage_limit:flags.1?int = ExportedChatInvite; messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; messages.importChatInvite#6c50051c hash:string = Updates; messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet; @@ -1463,9 +1463,8 @@ messages.getReplies#24b581ba peer:InputPeer msg_id:int offset_id:int offset_date messages.getDiscussionMessage#446972fd peer:InputPeer msg_id:int = messages.DiscussionMessage; messages.readDiscussion#f731a9f4 peer:InputPeer msg_id:int read_max_id:int = Bool; messages.unpinAllMessages#f025bc8b peer:InputPeer = messages.AffectedHistory; -messages.getExportedChatInvites#6d9cae03 flags:# expired:flags.1?true peer:InputPeer admin_id:flags.0?InputUser offset_link:flags.2?string limit:int = messages.ExportedChatInvites; +messages.getExportedChatInvites#6d9cae03 flags:# peer:InputPeer admin_id:flags.0?InputUser offset_link:flags.2?string limit:int = messages.ExportedChatInvites; messages.editExportedChatInvite#2e4ffbe flags:# revoked:flags.2?true peer:InputPeer link:string expire_date:flags.0?int usage_limit:flags.1?int = messages.ExportedChatInvite; -messages.getExportedChatInvite#73746f5c peer:InputPeer link:string = messages.ExportedChatInvite; messages.getChatInviteImporters#26fb7289 peer:InputPeer link:string offset_date:int offset_user:InputUser limit:int = messages.ChatInviteImporters; updates.getState#edd4882a = updates.State; diff --git a/Telegram/SourceFiles/api/api_invite_links.cpp b/Telegram/SourceFiles/api/api_invite_links.cpp new file mode 100644 index 000000000..b8ece44a1 --- /dev/null +++ b/Telegram/SourceFiles/api/api_invite_links.cpp @@ -0,0 +1,206 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "api/api_invite_links.h" + +#include "data/data_peer.h" +#include "data/data_chat.h" +#include "data/data_channel.h" +#include "data/data_session.h" +#include "data/data_changes.h" +#include "main/main_session.h" +#include "apiwrap.h" + +namespace Api { +namespace { + +constexpr auto kFirstPage = 10; +constexpr auto kPerPage = 50; + +} // namespace + +InviteLinks::InviteLinks(not_null api) : _api(api) { +} + +void InviteLinks::create( + not_null peer, + TimeId expireDate, + int usageLimit) { + if (_createRequests.contains(peer)) { + return; + } + + using Flag = MTPmessages_ExportChatInvite::Flag; + const auto requestId = _api->request(MTPmessages_ExportChatInvite( + MTP_flags((expireDate ? Flag::f_expire_date : Flag(0)) + | (usageLimit ? Flag::f_usage_limit : Flag(0))), + peer->input, + MTP_int(expireDate), + MTP_int(usageLimit) + )).done([=](const MTPExportedChatInvite &result) { + _createRequests.erase(peer); + const auto link = (result.type() == mtpc_chatInviteExported) + ? qs(result.c_chatInviteExported().vlink()) + : QString(); + if (!expireDate && !usageLimit) { + editPermanentLink(peer, QString(), link); + } + }).fail([=](const RPCError &error) { + _createRequests.erase(peer); + }).send(); + _createRequests.emplace(peer, requestId); +} + +void InviteLinks::edit( + not_null peer, + const QString &link, + TimeId expireDate, + int usageLimit) { + const auto key = EditKey{ peer, link }; + if (_editRequests.contains(key)) { + return; + } + + using Flag = MTPmessages_EditExportedChatInvite::Flag; + const auto requestId = _api->request(MTPmessages_EditExportedChatInvite( + MTP_flags((expireDate ? Flag::f_expire_date : Flag(0)) + | (usageLimit ? Flag::f_usage_limit : Flag(0))), + peer->input, + MTP_string(link), + MTP_int(expireDate), + MTP_int(usageLimit) + )).done([=](const MTPmessages_ExportedChatInvite &result) { + _editRequests.erase(key); + result.match([&](const MTPDmessages_exportedChatInvite &data) { + _api->session().data().processUsers(data.vusers()); + const auto &invite = data.vinvite(); + const auto link = (invite.type() == mtpc_chatInviteExported) + ? qs(invite.c_chatInviteExported().vlink()) + : QString(); + // #TODO links + }); + }).fail([=](const RPCError &error) { + _editRequests.erase(key); + }).send(); + _editRequests.emplace(key, requestId); +} + +void InviteLinks::revoke(not_null peer, const QString &link) { + const auto key = EditKey{ peer, link }; + if (_editRequests.contains(key)) { + return; + } + + const auto requestId = _api->request(MTPmessages_EditExportedChatInvite( + MTP_flags(MTPmessages_EditExportedChatInvite::Flag::f_revoked), + peer->input, + MTP_string(link), + MTPint(), // expire_date + MTPint() // usage_limit + )).done([=](const MTPmessages_ExportedChatInvite &result) { + _editRequests.erase(key); + result.match([&](const MTPDmessages_exportedChatInvite &data) { + _api->session().data().processUsers(data.vusers()); + const auto &invite = data.vinvite(); + const auto link = (invite.type() == mtpc_chatInviteExported) + ? qs(invite.c_chatInviteExported().vlink()) + : QString(); + editPermanentLink(peer, key.link, link); + }); + }).fail([=](const RPCError &error) { + _editRequests.erase(key); + }).send(); + _editRequests.emplace(key, requestId); +} + +void InviteLinks::requestLinks(not_null peer) { + if (_firstSliceRequests.contains(peer)) { + return; + } + const auto requestId = _api->request(MTPmessages_GetExportedChatInvites( + MTP_flags(0), + peer->input, + MTPInputUser(), // admin_id + MTPstring(), // offset_link + MTP_int(kFirstPage) + )).done([=](const MTPmessages_ExportedChatInvites &result) { + _firstSliceRequests.remove(peer); + _firstSlices.emplace_or_assign(peer, parseSlice(peer, result)); + peer->session().changes().peerUpdated( + peer, + Data::PeerUpdate::Flag::InviteLink); + }).fail([=](const RPCError &error) { + _firstSliceRequests.remove(peer); + }).send(); + _firstSliceRequests.emplace(peer, requestId); +} + +auto InviteLinks::links(not_null peer) const -> Links { + const auto i = _firstSlices.find(peer); + return (i != end(_firstSlices)) ? i->second : Links(); +} + +auto InviteLinks::parseSlice( + not_null peer, + const MTPmessages_ExportedChatInvites &slice) const -> Links { + auto result = Links(); + slice.match([&](const MTPDmessages_exportedChatInvites &data) { + auto &owner = peer->session().data(); + owner.processUsers(data.vusers()); + result.count = data.vcount().v; + for (const auto &invite : data.vinvites().v) { + invite.match([&](const MTPDchatInviteExported &data) { + result.links.push_back({ + .link = qs(data.vlink()), + .admin = owner.user(data.vadmin_id().v), + .date = data.vdate().v, + .expireDate = data.vexpire_date().value_or_empty(), + .usageLimit = data.vusage_limit().value_or_empty(), + .usage = data.vusage().value_or_empty(), + .revoked = data.is_revoked(), + }); + }); + } + }); + return result; +} + +void InviteLinks::requestMoreLinks( + not_null peer, + const QString &last, + Fn done) { + _api->request(MTPmessages_GetExportedChatInvites( + MTP_flags(MTPmessages_GetExportedChatInvites::Flag::f_offset_link), + peer->input, + MTPInputUser(), // admin_id, + MTP_string(last), + MTP_int(kPerPage) + )).done([=](const MTPmessages_ExportedChatInvites &result) { + done(parseSlice(peer, result)); + }).fail([=](const RPCError &error) { + done(Links()); + }).send(); +} + +void InviteLinks::editPermanentLink( + not_null peer, + const QString &from, + const QString &to) { + if (const auto chat = peer->asChat()) { + if (chat->inviteLink() == from) { + chat->setInviteLink(to); + } + } else if (const auto channel = peer->asChannel()) { + if (channel->inviteLink() == from) { + channel->setInviteLink(to); + } + } else { + Unexpected("Peer in InviteLinks::editMainLink."); + } +} + +} // namespace Api diff --git a/Telegram/SourceFiles/api/api_invite_links.h b/Telegram/SourceFiles/api/api_invite_links.h new file mode 100644 index 000000000..7de6341be --- /dev/null +++ b/Telegram/SourceFiles/api/api_invite_links.h @@ -0,0 +1,85 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +class ApiWrap; + +namespace Api { + +struct InviteLink { + QString link; + not_null admin; + TimeId date; + TimeId expireDate = 0; + int usageLimit = 0; + int usage = 0; + bool revoked = false; +}; + +struct PeerInviteLinks { + std::vector links; + int count = 0; +}; + +class InviteLinks final { +public: + explicit InviteLinks(not_null api); + + using Link = InviteLink; + using Links = PeerInviteLinks; + + void create( + not_null peer, + TimeId expireDate = 0, + int usageLimit = 0); + void edit( + not_null peer, + const QString &link, + TimeId expireDate, + int usageLimit); + void revoke(not_null peer, const QString &link); + + void requestLinks(not_null peer); + [[nodiscard]] Links links(not_null peer) const; + + void requestMoreLinks( + not_null peer, + const QString &last, + Fn done); + +private: + struct EditKey { + not_null peer; + QString link; + + friend inline bool operator<(const EditKey &a, const EditKey &b) { + return (a.peer == b.peer) + ? (a.link < b.link) + : (a.peer < b.peer); + } + }; + + void editPermanentLink( + not_null peer, + const QString &from, + const QString &to); + [[nodiscard]] Links parseSlice( + not_null peer, + const MTPmessages_ExportedChatInvites &slice) const; + + const not_null _api; + + base::flat_map, Links> _firstSlices; + base::flat_map, mtpRequestId> _firstSliceRequests; + + base::flat_map, mtpRequestId> _createRequests; + base::flat_map _editRequests; + +}; + +} // namespace Api diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index b2c3596be..3a311b7a6 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_authorizations.h" #include "api/api_attached_stickers.h" #include "api/api_hash.h" +#include "api/api_invite_links.h" #include "api/api_media.h" #include "api/api_sending.h" #include "api/api_text_entities.h" @@ -194,7 +195,8 @@ ApiWrap::ApiWrap(not_null session) , _attachedStickers(std::make_unique(this)) , _selfDestruct(std::make_unique(this)) , _sensitiveContent(std::make_unique(this)) -, _globalPrivacy(std::make_unique(this)) { +, _globalPrivacy(std::make_unique(this)) +, _inviteLinks(std::make_unique(this)) { crl::on_main(session, [=] { // You can't use _session->lifetime() in the constructor, // only queued, because it is not constructed yet. @@ -2120,36 +2122,6 @@ void ApiWrap::unblockPeer(not_null peer, Fn onDone) { _blockRequests.emplace(peer, requestId); } -void ApiWrap::exportInviteLink(not_null peer) { - if (_exportInviteRequests.find(peer) != end(_exportInviteRequests)) { - return; - } - - const auto requestId = [&] { - return request(MTPmessages_ExportChatInvite( - MTP_flags(0), - peer->input, - MTPint(), // expire_date - MTPint() // usage_limit - )).done([=](const MTPExportedChatInvite &result) { - _exportInviteRequests.erase(peer); - const auto link = (result.type() == mtpc_chatInviteExported) - ? qs(result.c_chatInviteExported().vlink()) - : QString(); - if (const auto chat = peer->asChat()) { - chat->setInviteLink(link); - } else if (const auto channel = peer->asChannel()) { - channel->setInviteLink(link); - } else { - Unexpected("Peer in ApiWrap::exportInviteLink."); - } - }).fail([=](const RPCError &error) { - _exportInviteRequests.erase(peer); - }).send(); - }(); - _exportInviteRequests.emplace(peer, requestId); -} - void ApiWrap::requestNotifySettings(const MTPInputNotifyPeer &peer) { const auto key = [&] { switch (peer.type()) { @@ -5243,6 +5215,10 @@ Api::GlobalPrivacy &ApiWrap::globalPrivacy() { return *_globalPrivacy; } +Api::InviteLinks &ApiWrap::inviteLinks() { + return *_inviteLinks; +} + void ApiWrap::createPoll( const PollData &data, const SendAction &action, diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index dbe80b6f0..47697939f 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -60,6 +60,7 @@ class AttachedStickers; class SelfDestruct; class SensitiveContent; class GlobalPrivacy; +class InviteLinks; namespace details { @@ -289,7 +290,6 @@ public: void blockPeer(not_null peer); void unblockPeer(not_null peer, Fn onDone = nullptr); - void exportInviteLink(not_null peer); void requestNotifySettings(const MTPInputNotifyPeer &peer); void updateNotifySettingsDelayed(not_null peer); void saveDraftToCloudDelayed(not_null history); @@ -464,6 +464,7 @@ public: [[nodiscard]] Api::SelfDestruct &selfDestruct(); [[nodiscard]] Api::SensitiveContent &sensitiveContent(); [[nodiscard]] Api::GlobalPrivacy &globalPrivacy(); + [[nodiscard]] Api::InviteLinks &inviteLinks(); void createPoll( const PollData &data, @@ -701,7 +702,6 @@ private: QMap _channelAmInRequests; base::flat_map, mtpRequestId> _blockRequests; - base::flat_map, mtpRequestId> _exportInviteRequests; base::flat_map _notifySettingRequests; base::flat_map, mtpRequestId> _draftsSaveRequestIds; base::Timer _draftsSaveTimer; @@ -828,6 +828,7 @@ private: const std::unique_ptr _selfDestruct; const std::unique_ptr _sensitiveContent; const std::unique_ptr _globalPrivacy; + const std::unique_ptr _inviteLinks; base::flat_map _pollVotesRequestIds; base::flat_map _pollCloseRequestIds; diff --git a/Telegram/SourceFiles/boxes/add_contact_box.cpp b/Telegram/SourceFiles/boxes/add_contact_box.cpp index da9c664cd..54e633fdc 100644 --- a/Telegram/SourceFiles/boxes/add_contact_box.cpp +++ b/Telegram/SourceFiles/boxes/add_contact_box.cpp @@ -40,6 +40,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mainwidget.h" #include "mainwindow.h" #include "apiwrap.h" +#include "api/api_invite_links.h" #include "main/main_session.h" #include "facades.h" #include "styles/style_layers.h" @@ -942,7 +943,7 @@ void SetupChannelBox::mouseMoveEvent(QMouseEvent *e) { void SetupChannelBox::mousePressEvent(QMouseEvent *e) { if (_linkOver) { if (_channel->inviteLink().isEmpty()) { - _channel->session().api().exportInviteLink(_channel); + _channel->session().api().inviteLinks().create(_channel); } else { QGuiApplication::clipboard()->setText(_channel->inviteLink()); Ui::Toast::Show(tr::lng_create_channel_link_copied(tr::now)); diff --git a/Telegram/SourceFiles/boxes/confirm_box.cpp b/Telegram/SourceFiles/boxes/confirm_box.cpp index 051a582fc..a9485ea86 100644 --- a/Telegram/SourceFiles/boxes/confirm_box.cpp +++ b/Telegram/SourceFiles/boxes/confirm_box.cpp @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mainwidget.h" #include "mainwindow.h" #include "apiwrap.h" +#include "api/api_invite_links.h" #include "history/history.h" #include "history/history_item.h" #include "ui/widgets/checkbox.h" @@ -407,7 +408,7 @@ void MaxInviteBox::mousePressEvent(QMouseEvent *e) { mouseMoveEvent(e); if (_linkOver) { if (_channel->inviteLink().isEmpty()) { - _channel->session().api().exportInviteLink(_channel); + _channel->session().api().inviteLinks().create(_channel); } else { QGuiApplication::clipboard()->setText(_channel->inviteLink()); Ui::Toast::Show(tr::lng_create_channel_link_copied(tr::now)); diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp index d78421756..edf4465bb 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp @@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_chat.h" #include "data/data_peer.h" #include "data/data_session.h" +#include "data/data_changes.h" #include "history/admin_log/history_admin_log_section.h" #include "info/profile/info_profile_values.h" #include "lang/lang_keys.h" @@ -45,6 +46,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/window_session_controller.h" #include "info/profile/info_profile_icon.h" #include "app.h" +#include "apiwrap.h" +#include "api/api_invite_links.h" #include "facades.h" #include "styles/style_layers.h" #include "styles/style_boxes.h" @@ -236,6 +239,49 @@ void ShowEditPermissions( }, box->lifetime()); } +void ShowEditInviteLinks( + not_null navigation, + not_null peer) { + const auto box = Ui::show( + Box(navigation, peer), + Ui::LayerOption::KeepOther); + const auto saving = box->lifetime().make_state(0); + const auto save = [=]( + not_null peer, + EditPeerPermissionsBox::Result result) { + Expects(result.slowmodeSeconds == 0 || peer->isChannel()); + + const auto close = crl::guard(box, [=] { box->closeBox(); }); + SaveDefaultRestrictions( + peer, + MTP_chatBannedRights(MTP_flags(result.rights), MTP_int(0)), + close); + if (const auto channel = peer->asChannel()) { + SaveSlowmodeSeconds(channel, result.slowmodeSeconds, close); + } + }; + box->saveEvents( + ) | rpl::start_with_next([=](EditPeerPermissionsBox::Result result) { + if (*saving) { + return; + } + *saving = true; + + const auto saveFor = peer->migrateToOrMe(); + const auto chat = saveFor->asChat(); + if (!result.slowmodeSeconds || !chat) { + save(saveFor, result); + return; + } + const auto api = &peer->session().api(); + api->migrateChat(chat, [=](not_null channel) { + save(channel, result); + }, [=](const RPCError &error) { + *saving = false; + }); + }, box->lifetime()); +} + } // namespace namespace { @@ -868,6 +914,11 @@ void Controller::fillManageSection() { ? channel->canEditPermissions() : chat->canEditPermissions(); }(); + const auto canEditInviteLinks = [&] { + return isChannel + ? channel->canHaveInviteLink() + : chat->canHaveInviteLink(); + }(); const auto canViewAdmins = [&] { return isChannel ? channel->canViewAdmins() @@ -949,6 +1000,26 @@ void Controller::fillManageSection() { [=] { ShowEditPermissions(_navigation, _peer); }, st::infoIconPermissions); } + if (canEditInviteLinks) { + AddButtonWithCount( + _controls.buttonsLayout, + tr::lng_manage_peer_invite_links(), + Info::Profile::MigratedOrMeValue( + _peer + ) | rpl::map([=](not_null peer) { + peer->session().api().inviteLinks().requestLinks(peer); + return peer->session().changes().peerUpdates( + peer, + Data::PeerUpdate::Flag::InviteLink + ) | rpl::map([=] { + return peer->session().api().inviteLinks().links( + peer).count; + }); + }) | rpl::flatten_latest( + ) | ToPositiveNumberString(), + [=] { ShowEditInviteLinks(_navigation, _peer); }, + st::infoIconPermissions); + } if (canViewAdmins) { AddButtonWithCount( _controls.buttonsLayout, diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_type_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_type_box.cpp index 386d1c36e..5b20229e2 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_type_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_type_box.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/peers/edit_peer_type_box.h" #include "apiwrap.h" +#include "api/api_invite_links.h" #include "main/main_session.h" #include "boxes/add_contact_box.h" #include "boxes/confirm_box.h" @@ -126,8 +127,7 @@ private: void refreshEditInviteLink(); void refreshCreateInviteLink(); void createInviteLink(); - void revokeInviteLink(); - void exportInviteLink(const QString &confirmation); + void revokeInviteLink(const QString &link); void fillPrivaciesButtons( not_null parent, @@ -536,22 +536,26 @@ void Controller::showUsernameResult( } void Controller::createInviteLink() { - exportInviteLink((_isGroup - ? tr::lng_group_invite_about - : tr::lng_group_invite_about_channel)(tr::now)); -} - -void Controller::revokeInviteLink() { - exportInviteLink(tr::lng_group_invite_about_new(tr::now)); -} - -void Controller::exportInviteLink(const QString &confirmation) { const auto callback = crl::guard(this, [=](Fn &&close) { close(); - _peer->session().api().exportInviteLink(_peer->migrateToOrMe()); + _peer->session().api().inviteLinks().create(_peer->migrateToOrMe()); }); auto box = Box( - confirmation, + (_isGroup + ? tr::lng_group_invite_about + : tr::lng_group_invite_about_channel)(tr::now), + std::move(callback)); + Ui::show(std::move(box), Ui::LayerOption::KeepOther); +} + +void Controller::revokeInviteLink(const QString &link) { + const auto callback = crl::guard(this, [=](Fn &&close) { + close(); + const auto peer = _peer->migrateToOrMe(); + peer->session().api().inviteLinks().revoke(peer, link); + }); + auto box = Box( + tr::lng_group_invite_about_new(tr::now), std::move(callback)); Ui::show(std::move(box), Ui::LayerOption::KeepOther); } @@ -623,7 +627,7 @@ object_ptr Controller::createInviteLinkEdit() { container, tr::lng_group_invite_create_new(tr::now), st::editPeerInviteLinkButton) - )->addClickHandler([=] { revokeInviteLink(); }); + )->addClickHandler([=] { revokeInviteLink(inviteLinkText()); }); observeInviteLink();