Check if bot is in group or if can be added.

This commit is contained in:
John Preston 2023-01-31 17:40:44 +04:00
parent 17ce93fd5e
commit 4234f0b797
4 changed files with 208 additions and 67 deletions

View file

@ -4089,6 +4089,50 @@ void ApiWrap::saveContactSignupSilent(bool silent) {
_contactSignupSilentRequestId = requestId;
}
auto ApiWrap::botCommonGroups(not_null<UserData*> bot) const
-> std::optional<std::vector<not_null<PeerData*>>> {
const auto i = _botCommonGroups.find(bot);
return (i != end(_botCommonGroups))
? i->second
: std::optional<std::vector<not_null<PeerData*>>>();
}
void ApiWrap::requestBotCommonGroups(
not_null<UserData*> bot,
Fn<void()> done) {
if (_botCommonGroupsRequests.contains(bot)) {
return;
}
_botCommonGroupsRequests.emplace(bot, done);
const auto finish = [=](std::vector<not_null<PeerData*>> list) {
_botCommonGroups.emplace(bot, std::move(list));
if (const auto callback = _botCommonGroupsRequests.take(bot)) {
(*callback)();
}
};
const auto limit = 100;
request(MTPmessages_GetCommonChats(
bot->inputUser,
MTP_long(0), // max_id
MTP_int(limit)
)).done([=](const MTPmessages_Chats &result) {
const auto chats = result.match([](const auto &data) {
return &data.vchats().v;
});
auto &owner = session().data();
auto list = std::vector<not_null<PeerData*>>();
list.reserve(chats->size());
for (const auto &chat : *chats) {
if (const auto peer = owner.processChat(chat)) {
list.push_back(peer);
}
}
finish(std::move(list));
}).fail([=] {
finish({});
}).send();
}
void ApiWrap::saveSelfBio(const QString &text) {
if (_bio.requestId) {
if (text != _bio.requestedText) {

View file

@ -352,6 +352,10 @@ public:
std::optional<bool> contactSignupSilentCurrent() const;
void saveContactSignupSilent(bool silent);
[[nodiscard]] auto botCommonGroups(not_null<UserData*> bot) const
-> std::optional<std::vector<not_null<PeerData*>>>;
void requestBotCommonGroups(not_null<UserData*> bot, Fn<void()> done);
void saveSelfBio(const QString &text);
[[nodiscard]] Api::Authorizations &authorizations();
@ -692,6 +696,11 @@ private:
std::optional<bool> _contactSignupSilent;
rpl::event_stream<bool> _contactSignupSilentChanges;
base::flat_map<
not_null<UserData*>,
std::vector<not_null<PeerData*>>> _botCommonGroups;
base::flat_map<not_null<UserData*>, Fn<void()>> _botCommonGroupsRequests;
base::flat_map<FullMsgId, QString> _unlikelyMessageLinks;
};

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/peers/choose_peer_box.h"
#include "apiwrap.h" // ApiWrap::botCommonGroups / requestBotCommonGroups.
#include "boxes/add_contact_box.h"
#include "boxes/peer_list_controllers.h"
#include "boxes/premium_limits_box.h"
@ -18,8 +19,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item_reply_markup.h"
#include "info/profile/info_profile_icon.h"
#include "lang/lang_keys.h"
#include "main/main_session.h" // Session::api().
#include "settings/settings_common.h"
#include "ui/boxes/confirm_box.h"
#include "ui/text/text_utilities.h"
#include "ui/widgets/buttons.h"
#include "ui/wrap/vertical_layout.h"
#include "window/window_session_controller.h"
@ -55,10 +58,87 @@ private:
const not_null<Window::SessionNavigation*> _navigation;
not_null<UserData*> _bot;
RequestPeerQuery _query;
base::flat_set<not_null<PeerData*>> _commonGroups;
Fn<void(not_null<PeerData*>)> _callback;
};
using RightsMap = std::vector<std::pair<ChatAdminRight, tr::phrase<>>>;
[[nodiscard]] RightsMap GroupRights() {
using Flag = ChatAdminRight;
return {
{ Flag::ChangeInfo, tr::lng_request_group_change_info },
{
Flag::DeleteMessages,
tr::lng_request_group_delete_messages },
{ Flag::BanUsers, tr::lng_request_group_ban_users },
{ Flag::InviteByLinkOrAdd, tr::lng_request_group_invite },
{ Flag::PinMessages, tr::lng_request_group_pin_messages },
{ Flag::ManageTopics, tr::lng_request_group_manage_topics },
{
Flag::ManageCall,
tr::lng_request_group_manage_video_chats },
{ Flag::Anonymous, tr::lng_request_group_anonymous },
{ Flag::AddAdmins, tr::lng_request_group_add_admins },
};
}
[[nodiscard]] RightsMap BroadcastRights() {
using Flag = ChatAdminRight;
return {
{ Flag::ChangeInfo, tr::lng_request_channel_change_info },
{
Flag::PostMessages,
tr::lng_request_channel_post_messages },
{
Flag::EditMessages,
tr::lng_request_channel_edit_messages },
{
Flag::DeleteMessages,
tr::lng_request_channel_delete_messages },
{
Flag::InviteByLinkOrAdd,
tr::lng_request_channel_add_subscribers },
{
Flag::ManageCall,
tr::lng_request_channel_manage_livestreams },
{ Flag::AddAdmins, tr::lng_request_channel_add_admins },
};
}
[[nodiscard]] QString RightsText(
ChatAdminRights rights,
const RightsMap &phrases) {
auto list = QStringList();
for (const auto &[flag, phrase] : phrases) {
if (rights & flag) {
list.push_back(phrase(tr::now));
}
}
const auto count = list.size();
if (!count) {
return QString();
}
const auto last = list.back();
return (count > 1)
? tr::lng_request_peer_rights_and(
tr::now,
lt_rights,
list.mid(0, count - 1).join(", "),
lt_last,
last)
: last;
}
[[nodiscard]] QString GroupRightsText(ChatAdminRights rights) {
return RightsText(rights, GroupRights());
}
[[nodiscard]] QString BroadcastRightsText(ChatAdminRights rights) {
return RightsText(rights, BroadcastRights());
}
[[nodiscard]] QStringList RestrictionsList(RequestPeerQuery query) {
using Flag = ChatAdminRight;
using Type = RequestPeerQuery::Type;
@ -74,30 +154,11 @@ private:
result.push_back(no(tr::now));
}
};
const auto addRights = [&](
ChatAdminRights rights,
std::vector<std::pair<Flag, tr::phrase<>>> phrases) {
auto list = QStringList();
for (const auto &[flag, phrase] : phrases) {
if (rights & flag) {
list.push_back(phrase(tr::now));
}
const auto addRights = [&](const QString &rights) {
if (!rights.isEmpty()) {
result.push_back(
tr::lng_request_peer_rights(tr::now, lt_rights, rights));
}
const auto count = list.size();
if (!count) {
return;
}
const auto last = list.back();
const auto full = (count > 1)
? tr::lng_request_peer_rights_and(
tr::now,
lt_rights,
list.mid(0, count - 1).join(", "),
lt_last,
last)
: last;
result.push_back(
tr::lng_request_peer_rights(tr::now, lt_rights, full));
};
switch (query.type) {
case Type::User:
@ -120,21 +181,7 @@ private:
if (query.amCreator) {
result.push_back(tr::lng_request_group_am_owner(tr::now));
} else {
addRights(query.myRights, {
{ Flag::ChangeInfo, tr::lng_request_group_change_info },
{
Flag::DeleteMessages,
tr::lng_request_group_delete_messages },
{ Flag::BanUsers, tr::lng_request_group_ban_users },
{ Flag::InviteByLinkOrAdd, tr::lng_request_group_invite },
{ Flag::PinMessages, tr::lng_request_group_pin_messages },
{ Flag::ManageTopics, tr::lng_request_group_manage_topics },
{
Flag::ManageCall,
tr::lng_request_group_manage_video_chats },
{ Flag::Anonymous, tr::lng_request_group_anonymous },
{ Flag::AddAdmins, tr::lng_request_group_add_admins },
});
addRights(GroupRightsText(query.myRights));
}
break;
case Type::Broadcast:
@ -145,25 +192,7 @@ private:
if (query.amCreator) {
result.push_back(tr::lng_request_channel_am_owner(tr::now));
} else {
addRights(query.myRights, {
{ Flag::ChangeInfo, tr::lng_request_channel_change_info },
{
Flag::PostMessages,
tr::lng_request_channel_post_messages },
{
Flag::EditMessages,
tr::lng_request_channel_edit_messages },
{
Flag::DeleteMessages,
tr::lng_request_channel_delete_messages },
{
Flag::InviteByLinkOrAdd,
tr::lng_request_channel_add_subscribers },
{
Flag::ManageCall,
tr::lng_request_channel_manage_livestreams },
{ Flag::AddAdmins, tr::lng_request_channel_add_admins },
});
addRights(BroadcastRightsText(query.myRights));
}
break;
}
@ -175,10 +204,48 @@ object_ptr<Ui::BoxContent> MakeConfirmBox(
not_null<PeerData*> peer,
RequestPeerQuery query,
Fn<void()> confirmed) {
auto text = TextWithEntities{ "Sure?.." };
const auto user = peer->asUser();
const auto name = user ? user->firstName : peer->name();
const auto botName = bot->name();
auto text = tr::lng_request_peer_confirm(
tr::now,
lt_chat,
Ui::Text::Bold(name),
lt_bot,
Ui::Text::Bold(botName),
Ui::Text::WithEntities);
if (!user) {
const auto rights = peer->isBroadcast()
? BroadcastRightsText(query.botRights)
: GroupRightsText(query.botRights);
if (!rights.isEmpty()) {
text.append('\n').append('\n').append(
tr::lng_request_peer_confirm_rights(
tr::now,
lt_bot,
Ui::Text::Bold(botName),
lt_chat,
Ui::Text::Bold(name),
lt_rights,
TextWithEntities{ rights },
Ui::Text::WithEntities));
} else if (!peer->isBroadcast() && query.isBotParticipant) {
const auto common = bot->session().api().botCommonGroups(bot);
if (!common || !ranges::contains(*common, peer)) {
text.append('\n').append('\n').append(
tr::lng_request_peer_confirm_add(
tr::now,
lt_bot,
Ui::Text::Bold(botName),
lt_chat,
Ui::Text::Bold(name),
Ui::Text::WithEntities));
}
}
}
return Ui::MakeConfirmBox({
.text = std::move(text),
.confirmed = std::move(confirmed),
.confirmed = [=](Fn<void()> close) { confirmed(); close(); },
.confirmText = tr::lng_request_peer_confirm_send(tr::now),
});
}
@ -206,7 +273,8 @@ object_ptr<Ui::BoxContent> CreatePeerByQueryBox(
[[nodiscard]] bool FilterPeerByQuery(
not_null<PeerData*> peer,
RequestPeerQuery query) {
RequestPeerQuery query,
const base::flat_set<not_null<PeerData*>> &commonGroups) {
using Type = RequestPeerQuery::Type;
using Restriction = RequestPeerQuery::Restriction;
const auto checkRestriction = [](Restriction restriction, bool value) {
@ -239,7 +307,13 @@ object_ptr<Ui::BoxContent> CreatePeerByQueryBox(
&& checkRights(
query.myRights,
chat ? chat->amCreator() : megagroup->amCreator(),
chat ? chat->adminRights() : megagroup->adminRights());
chat ? chat->adminRights() : megagroup->adminRights())
&& (!query.isBotParticipant
|| query.myRights
|| commonGroups.contains(peer)
|| (chat
? chat->canAddMembers()
: megagroup->canAddMembers()));
}
case Type::Broadcast: {
const auto broadcast = peer->asBroadcast();
@ -265,6 +339,9 @@ ChoosePeerBoxController::ChoosePeerBoxController(
, _bot(bot)
, _query(query)
, _callback(std::move(callback)) {
if (const auto list = _bot->session().api().botCommonGroups(_bot)) {
_commonGroups = { begin(*list), end(*list) };
}
}
Main::Session &ChoosePeerBoxController::session() const {
@ -358,7 +435,7 @@ void ChoosePeerBoxController::rowClicked(not_null<PeerListRow*> row) {
auto ChoosePeerBoxController::createRow(not_null<History*> history)
-> std::unique_ptr<Row> {
return FilterPeerByQuery(history->peer, _query)
return FilterPeerByQuery(history->peer, _query, _commonGroups)
? std::make_unique<Row>(history)
: nullptr;
}
@ -388,11 +465,23 @@ QString ChoosePeerBoxController::emptyBoxText() const {
} // namespace
QPointer<Ui::BoxContent> ShowChoosePeerBox(
void ShowChoosePeerBox(
not_null<Window::SessionNavigation*> navigation,
not_null<UserData*> bot,
RequestPeerQuery query,
Fn<void(not_null<PeerData*>)> &&chosen) {
Fn<void(not_null<PeerData*>)> chosen) {
const auto needCommonGroups = query.isBotParticipant
&& (query.type == RequestPeerQuery::Type::Group)
&& !query.myRights;
if (needCommonGroups && !bot->session().api().botCommonGroups(bot)) {
const auto weak = base::make_weak(navigation);
bot->session().api().requestBotCommonGroups(bot, [=] {
if (const auto strong = weak.get()) {
ShowChoosePeerBox(strong, bot, query, chosen);
}
});
return;
}
const auto weak = std::make_shared<QPointer<Ui::BoxContent>>();
auto initBox = [=](not_null<PeerListBox*> box) {
box->addButton(tr::lng_cancel(), [box] {
@ -412,5 +501,4 @@ QPointer<Ui::BoxContent> ShowChoosePeerBox(
query,
std::move(callback)),
std::move(initBox)), Ui::LayerOption::KeepOther);
return weak->data();
}

View file

@ -17,8 +17,8 @@ namespace Window {
class SessionNavigation;
} // namespace Window
QPointer<Ui::BoxContent> ShowChoosePeerBox(
void ShowChoosePeerBox(
not_null<Window::SessionNavigation*> navigation,
not_null<UserData*> bot,
RequestPeerQuery query,
Fn<void(not_null<PeerData*>)> &&chosen);
Fn<void(not_null<PeerData*>)> chosen);