Add bot to group / channel by link with rights.

This commit is contained in:
John Preston 2022-03-24 13:46:44 +04:00
parent 649f2908e8
commit 468917a91a
11 changed files with 302 additions and 102 deletions

View file

@ -3526,9 +3526,11 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
finishForwarding(action);
}
void ApiWrap::sendBotStart(not_null<UserData*> bot, PeerData *chat) {
void ApiWrap::sendBotStart(
not_null<UserData*> bot,
PeerData *chat,
const QString &startTokenForChat) {
Expects(bot->isBot());
Expects(chat == nullptr || !bot->botInfo->startGroupToken.isEmpty());
if (chat && chat->isChannel() && !chat->isMegagroup()) {
ShowAddParticipantsError("USER_BOT", chat, { 1, bot });
@ -3536,20 +3538,28 @@ void ApiWrap::sendBotStart(not_null<UserData*> bot, PeerData *chat) {
}
auto &info = bot->botInfo;
auto &token = chat ? info->startGroupToken : info->startToken;
auto &token = chat ? startTokenForChat : info->startToken;
if (token.isEmpty()) {
auto message = MessageToSend(
Api::SendAction(_session->data().history(bot)));
message.textWithTags = { qsl("/start"), TextWithTags::Tags() };
Api::SendAction(_session->data().history(chat
? chat
: bot.get())));
message.textWithTags = { u"/start"_q, TextWithTags::Tags() };
if (chat) {
message.textWithTags.text += '@' + bot->username;
}
sendMessage(std::move(message));
return;
}
const auto randomId = base::RandomValue<uint64>();
if (!chat) {
info->startToken = QString();
}
request(MTPmessages_StartBot(
bot->inputUser,
chat ? chat->input : MTP_inputPeerEmpty(),
MTP_long(randomId),
MTP_string(base::take(token))
MTP_string(token)
)).done([=](const MTPUpdates &result) {
applyUpdates(result);
}).fail([=](const MTP::Error &error) {

View file

@ -320,7 +320,10 @@ public:
void cancelLocalItem(not_null<HistoryItem*> item);
void sendMessage(MessageToSend &&message);
void sendBotStart(not_null<UserData*> bot, PeerData *chat = nullptr);
void sendBotStart(
not_null<UserData*> bot,
PeerData *chat = nullptr,
const QString &startTokenForChat = QString());
void sendInlineResult(
not_null<UserData*> bot,
not_null<InlineBots::Result*> data,

View file

@ -19,6 +19,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/peers/edit_participants_box.h"
#include "boxes/filters/edit_filter_chats_list.h"
#include "ui/boxes/confirm_box.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/wrap/slide_wrap.h"
#include "base/random.h"
#include "base/weak_ptr.h"
#include "api/api_chat_participants.h"
@ -54,7 +56,10 @@ private:
};
void ShareBotGame(not_null<UserData*> bot, not_null<PeerData*> chat) {
void ShareBotGame(
not_null<UserData*> bot,
not_null<PeerData*> chat,
const QString &shortName) {
const auto history = chat->owner().history(chat);
auto &histories = history->owner().histories();
const auto requestType = Data::Histories::RequestType::Send;
@ -68,7 +73,7 @@ void ShareBotGame(not_null<UserData*> bot, not_null<PeerData*> chat) {
MTP_inputMediaGame(
MTP_inputGameShortName(
bot->inputUser,
MTP_string(bot->botInfo->shareGameShortName))),
MTP_string(shortName))),
MTP_string(),
MTP_long(randomId),
MTPReplyMarkup(),
@ -138,23 +143,40 @@ void Controller::addRow(not_null<PeerData*> peer) {
} // namespace
void AddBotToGroupBoxController::Start(not_null<UserData*> bot) {
void AddBotToGroupBoxController::Start(
not_null<UserData*> bot,
Scope scope,
const QString &token,
ChatAdminRights requestedRights) {
auto initBox = [=](not_null<PeerListBox*> box) {
box->addButton(tr::lng_cancel(), [box] { box->closeBox(); });
};
Ui::show(Box<PeerListBox>(
std::make_unique<AddBotToGroupBoxController>(bot),
std::make_unique<AddBotToGroupBoxController>(
bot,
scope,
token,
requestedRights),
std::move(initBox)));
}
AddBotToGroupBoxController::AddBotToGroupBoxController(
not_null<UserData*> bot)
: ChatsListBoxController(SharingBotGame(bot)
not_null<UserData*> bot,
Scope scope,
const QString &token,
ChatAdminRights requestedRights)
: ChatsListBoxController((scope == Scope::ShareGame)
? std::make_unique<PeerListGlobalSearchController>(&bot->session())
: nullptr)
, _bot(bot)
, _adminToGroup(_bot->botInfo->groupAdminRights != 0)
, _adminToChannel(_bot->botInfo->channelAdminRights != 0) {
, _scope(scope)
, _token(token)
, _requestedRights(requestedRights)
, _adminToGroup((scope == Scope::GroupAdmin)
|| (scope == Scope::All && _bot->botInfo->groupAdminRights != 0))
, _adminToChannel((scope == Scope::ChannelAdmin)
|| (scope == Scope::All && _bot->botInfo->channelAdminRights != 0))
, _memberToGroup(scope == Scope::All) {
}
Main::Session &AddBotToGroupBoxController::session() const {
@ -170,8 +192,8 @@ void AddBotToGroupBoxController::rowClicked(not_null<PeerListRow*> row) {
}
void AddBotToGroupBoxController::shareBotGame(not_null<PeerData*> chat) {
auto send = crl::guard(this, [bot = _bot, chat] {
ShareBotGame(bot, chat);
auto send = crl::guard(this, [bot = _bot, chat, token = _token] {
ShareBotGame(bot, chat, token);
});
auto confirmText = [chat] {
if (chat->isUser()) {
@ -187,6 +209,34 @@ void AddBotToGroupBoxController::shareBotGame(not_null<PeerData*> chat) {
Ui::LayerOption::KeepOther);
}
void AddBotToGroupBoxController::requestExistingRights(
not_null<ChannelData*> channel) {
if (_existingRightsChannel == channel) {
return;
}
_existingRightsChannel = channel;
_bot->session().api().request(_existingRightsRequestId).cancel();
_existingRightsRequestId = _bot->session().api().request(
MTPchannels_GetParticipant(
_existingRightsChannel->inputChannel,
_bot->input)
).done([=](const MTPchannels_ChannelParticipant &result) {
result.match([&](const MTPDchannels_channelParticipant &data) {
channel->owner().processUsers(data.vusers());
const auto participant = Api::ChatParticipant(
data.vparticipant(),
channel);
_existingRights = participant.rights().flags;
_existingRank = participant.rank();
addBotToGroup(_existingRightsChannel);
});
}).fail([=] {
_existingRights = ChatAdminRights();
_existingRank = QString();
addBotToGroup(_existingRightsChannel);
}).send();
}
void AddBotToGroupBoxController::addBotToGroup(not_null<PeerData*> chat) {
if (const auto megagroup = chat->asMegagroup()) {
if (!megagroup->canAddMembers()) {
@ -196,38 +246,66 @@ void AddBotToGroupBoxController::addBotToGroup(not_null<PeerData*> chat) {
return;
}
}
if (_existingRightsChannel != chat) {
_existingRights = {};
_existingRank = QString();
_existingRightsChannel = nullptr;
_bot->session().api().request(_existingRightsRequestId).cancel();
}
const auto requestedAddAdmin = (_scope == Scope::GroupAdmin)
|| (_scope == Scope::ChannelAdmin);
if (chat->isChannel()
&& requestedAddAdmin
&& !_existingRights.has_value()) {
requestExistingRights(chat->asChannel());
return;
}
const auto bot = _bot;
const auto close = [=](auto&&...) {
Ui::hideLayer();
Ui::showPeerHistory(chat, ShowAtUnreadMsgId);
};
const auto rights = (chat->isBroadcast()
&& chat->asBroadcast()->canAddAdmins())
const auto rights = requestedAddAdmin
? _requestedRights
: (chat->isBroadcast()
&& chat->asBroadcast()->canAddAdmins())
? bot->botInfo->channelAdminRights
: ((chat->isMegagroup() && chat->asMegagroup()->canAddAdmins())
|| (chat->isChat() && chat->asChat()->canAddAdmins()))
? bot->botInfo->groupAdminRights
: ChatAdminRights();
if (rights) {
const auto addingAdmin = requestedAddAdmin || (rights != 0);
if (addingAdmin) {
const auto scope = _scope;
const auto token = _token;
const auto done = [=](
ChatAdminRightsInfo newRights,
const QString &rank) {
if (scope == Scope::GroupAdmin) {
chat->session().api().sendBotStart(bot, chat, token);
}
close();
};
const auto saveCallback = SaveAdminCallback(
chat,
bot,
close,
done,
close);
auto box = object_ptr<EditAdminBox>(nullptr);
box = Box<EditAdminBox>(
auto box = Box<EditAdminBox>(
chat,
bot,
ChatAdminRightsInfo(rights),
QString(),
true);
_existingRank,
EditAdminBotFields{
_token,
_existingRights.value_or(ChatAdminRights()) });
box->setSaveCallback(saveCallback);
Ui::show(std::move(box), Ui::LayerOption::KeepOther);
} else {
Ui::show(
Ui::MakeConfirmBox({
tr::lng_bot_sure_invite(tr::now, lt_group, chat->name),
crl::guard(this, [=] { AddBotToGroup(bot, chat); }),
crl::guard(this, [=] { AddBotToGroup(bot, chat, _token); }),
}),
Ui::LayerOption::KeepOther);
}
@ -251,32 +329,33 @@ bool AddBotToGroupBoxController::needToCreateRow(
return true;
}
if (const auto chat = peer->asChat()) {
if (_adminToGroup && chat->canAddAdmins()) {
if (onlyAdminToGroup()) {
return chat->canAddAdmins();
} else if (_adminToGroup && chat->canAddAdmins()) {
_groups.fire_copy(peer);
} else {
} else if (!onlyAdminToChannel()) {
return chat->canAddMembers();
}
} else if (const auto group = peer->asMegagroup()) {
if (_adminToGroup && group->canAddAdmins()) {
if (onlyAdminToGroup()) {
return group->canAddAdmins();
} else if (_adminToGroup && group->canAddAdmins()) {
_groups.fire_copy(peer);
} else {
} else if (!onlyAdminToChannel()) {
return group->canAddMembers();
}
} else if (const auto channel = peer->asBroadcast()) {
if (_adminToChannel && channel->canAddAdmins()) {
if (onlyAdminToChannel()) {
return channel->canAddAdmins();
} else if (_adminToChannel && channel->canAddAdmins()) {
_channels.fire_copy(peer);
}
}
return false;
}
bool AddBotToGroupBoxController::SharingBotGame(not_null<UserData*> bot) {
const auto &info = bot->botInfo;
return (info && !info->shareGameShortName.isEmpty());
}
bool AddBotToGroupBoxController::sharingBotGame() const {
return SharingBotGame(_bot);
return (_scope == Scope::ShareGame);
}
QString AddBotToGroupBoxController::emptyBoxText() const {
@ -310,29 +389,31 @@ object_ptr<Ui::RpWidget> AddBotToGroupBoxController::prepareAdminnedChats() {
const auto addList = [&](
tr::phrase<> subtitle,
rpl::event_stream<not_null<PeerData*>> &items) {
container->add(CreatePeerListSectionSubtitle(
container,
subtitle()));
container->add(object_ptr<Ui::FixedHeightWidget>(
container,
st::membersMarginTop));
const auto wrap = container->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
container,
object_ptr<Ui::VerticalLayout>(container)));
wrap->hide(anim::type::instant);
const auto delegate = container->lifetime().make_state<
const auto inner = wrap->entity();
inner->add(CreatePeerListSectionSubtitle(inner, subtitle()));
const auto delegate = inner->lifetime().make_state<
PeerListContentDelegateSimple
>();
const auto controller = container->lifetime().make_state<Controller>(
const auto controller = inner->lifetime().make_state<Controller>(
&session(),
items.events(),
callback);
const auto content = result->add(object_ptr<PeerListContent>(
const auto content = inner->add(object_ptr<PeerListContent>(
container,
controller));
delegate->setContent(content);
controller->setDelegate(delegate);
container->add(object_ptr<Ui::FixedHeightWidget>(
container,
st::membersMarginBottom));
items.events() | rpl::take(1) | rpl::start_with_next([=] {
wrap->show(anim::type::instant);
}, inner->lifetime());
};
if (_adminToChannel) {
addList(tr::lng_bot_channels_manage, _channels);
@ -353,11 +434,20 @@ object_ptr<Ui::RpWidget> AddBotToGroupBoxController::prepareAdminnedChats() {
return result;
}
bool AddBotToGroupBoxController::onlyAdminToGroup() const {
return _adminToGroup && !_memberToGroup && !_adminToChannel;
}
bool AddBotToGroupBoxController::onlyAdminToChannel() const {
return _adminToChannel && !_memberToGroup && !_adminToGroup;
}
void AddBotToGroupBoxController::prepareViewHook() {
delegate()->peerListSetTitle((sharingBotGame() || _adminToChannel)
? tr::lng_bot_choose_chat()
: tr::lng_bot_choose_group());
if (_adminToGroup || _adminToChannel) {
if ((_adminToGroup && !onlyAdminToGroup())
|| (_adminToChannel && !onlyAdminToChannel())) {
delegate()->peerListSetAboveWidget(prepareAdminnedChats());
}
@ -370,9 +460,12 @@ void AddBotToGroupBoxController::prepareViewHook() {
}, lifetime());
}
void AddBotToGroup(not_null<UserData*> bot, not_null<PeerData*> chat) {
if (bot->isBot() && !bot->botInfo->startGroupToken.isEmpty()) {
chat->session().api().sendBotStart(bot, chat);
void AddBotToGroup(
not_null<UserData*> bot,
not_null<PeerData*> chat,
const QString &startToken) {
if (!startToken.isEmpty()) {
chat->session().api().sendBotStart(bot, chat, startToken);
} else {
chat->session().api().chatParticipants().add(chat, { 1, bot });
}

View file

@ -8,14 +8,30 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "boxes/peer_list_controllers.h"
#include "data/data_chat_participant_status.h"
class AddBotToGroupBoxController
: public ChatsListBoxController
, public base::has_weak_ptr {
public:
static void Start(not_null<UserData*> bot);
enum class Scope {
None,
GroupAdmin,
ChannelAdmin,
ShareGame,
All,
};
static void Start(
not_null<UserData*> bot,
Scope scope = Scope::All,
const QString &token = QString(),
ChatAdminRights requestedRights = {});
explicit AddBotToGroupBoxController(not_null<UserData*> bot);
AddBotToGroupBoxController(
not_null<UserData*> bot,
Scope scope,
const QString &token,
ChatAdminRights requestedRights);
Main::Session &session() const override;
void rowClicked(not_null<PeerListRow*> row) override;
@ -26,9 +42,10 @@ protected:
QString emptyBoxText() const override;
private:
static bool SharingBotGame(not_null<UserData*> bot);
[[nodiscard]] object_ptr<Ui::RpWidget> prepareAdminnedChats();
object_ptr<Ui::RpWidget> prepareAdminnedChats();
[[nodiscard]] bool onlyAdminToGroup() const;
[[nodiscard]] bool onlyAdminToChannel() const;
bool needToCreateRow(not_null<PeerData*> peer) const;
bool sharingBotGame() const;
@ -37,13 +54,28 @@ private:
void shareBotGame(not_null<PeerData*> chat);
void addBotToGroup(not_null<PeerData*> chat);
void requestExistingRights(not_null<ChannelData*> channel);
const not_null<UserData*> _bot;
const Scope _scope = Scope::None;
const QString _token;
const ChatAdminRights _requestedRights;
ChannelData *_existingRightsChannel = nullptr;
mtpRequestId _existingRightsRequestId = 0;
std::optional<ChatAdminRights> _existingRights;
QString _existingRank;
rpl::event_stream<not_null<PeerData*>> _groups;
rpl::event_stream<not_null<PeerData*>> _channels;
bool _adminToGroup = false;
bool _adminToChannel = false;
bool _memberToGroup = false;
};
void AddBotToGroup(not_null<UserData*> bot, not_null<PeerData*> chat);
void AddBotToGroup(
not_null<UserData*> bot,
not_null<PeerData*> chat,
const QString &startToken);

View file

@ -200,7 +200,7 @@ EditAdminBox::EditAdminBox(
not_null<UserData*> user,
ChatAdminRightsInfo rights,
const QString &rank,
bool addingBot)
std::optional<EditAdminBotFields> addingBot)
: EditParticipantBox(
nullptr,
peer,
@ -209,7 +209,7 @@ EditAdminBox::EditAdminBox(
, _show(this)
, _oldRights(rights)
, _oldRank(rank)
, _addingBot(addingBot) {
, _addingBot(std::move(addingBot)) {
}
ChatAdminRightsInfo EditAdminBox::defaultRights() const {
@ -240,12 +240,17 @@ void EditAdminBox::prepare() {
EditParticipantBox::prepare();
setTitle(_addingBot
? tr::lng_bot_add_title()
? (_addingBot->existing
? tr::lng_rights_edit_admin()
: tr::lng_bot_add_title())
: _oldRights.flags
? tr::lng_rights_edit_admin()
: tr::lng_channel_add_admin());
if (_addingBot && !peer()->isBroadcast() && _saveCallback) {
if (_addingBot
&& !_addingBot->existing
&& !peer()->isBroadcast()
&& _saveCallback) {
addControl(
object_ptr<Ui::BoxContentDivider>(this),
st::rightsDividerMargin / 2);
@ -277,7 +282,9 @@ void EditAdminBox::prepare() {
const auto chat = peer()->asChat();
const auto channel = peer()->asChannel();
const auto prepareRights = _oldRights.flags
const auto prepareRights = _addingBot
? ChatAdminRightsInfo(_oldRights.flags | _addingBot->existing)
: _oldRights.flags
? _oldRights
: defaultRights();
const auto disabledByDefaults = (channel && !channel->isMegagroup())
@ -368,7 +375,7 @@ void EditAdminBox::prepare() {
? ~Flags(0)
: channel->adminRights());
_saveCallback(
_addingBot ? ChatAdminRightsInfo() : _oldRights,
_oldRights,
ChatAdminRightsInfo(newFlags),
_rank ? _rank->getLastText().trimmed() : QString());
};
@ -376,9 +383,9 @@ void EditAdminBox::prepare() {
if (!_saveCallback) {
return;
} else if (_addAsAdmin && !_addAsAdmin->checked()) {
AddBotToGroup(user(), peer());
AddBotToGroup(user(), peer(), _addingBot->token);
return;
} else if (_addingBot) {
} else if (_addingBot && !_addingBot->existing) {
const auto phrase = peer()->isBroadcast()
? tr::lng_bot_sure_add_text_channel
: tr::lng_bot_sure_add_text_group;
@ -409,7 +416,7 @@ void EditAdminBox::finishAddAdmin() {
void EditAdminBox::refreshButtons() {
clearButtons();
if (canSave()) {
addButton(!_addingBot
addButton((!_addingBot || _addingBot->existing)
? tr::lng_settings_save()
: _adminControlsWrap->toggled()
? tr::lng_bot_add_as_admin()

View file

@ -65,6 +65,11 @@ private:
};
struct EditAdminBotFields {
QString token;
ChatAdminRights existing;
};
class EditAdminBox : public EditParticipantBox {
public:
EditAdminBox(
@ -73,7 +78,7 @@ public:
not_null<UserData*> user,
ChatAdminRightsInfo rights,
const QString &rank,
bool addingBot = false);
std::optional<EditAdminBotFields> addingBot = {});
void setSaveCallback(
Fn<void(
@ -127,7 +132,7 @@ private:
mtpRequestId _transferRequestId = 0;
Fn<void()> _save, _finishSave;
bool _addingBot = false;
std::optional<EditAdminBotFields> _addingBot;
};

View file

@ -251,6 +251,39 @@ bool ShowWallPaper(
params);
}
[[nodiscard]] ChatAdminRights ParseRequestedAdminRights(
const QString &value) {
auto result = ChatAdminRights();
for (const auto &element : value.split(QRegularExpression("[+ ]"))) {
if (element == u"change_info"_q) {
result |= ChatAdminRight::ChangeInfo;
} else if (element == u"post_messages"_q) {
result |= ChatAdminRight::PostMessages;
} else if (element == u"edit_messages"_q) {
result |= ChatAdminRight::EditMessages;
} else if (element == u"delete_messages"_q) {
result |= ChatAdminRight::DeleteMessages;
} else if (element == u"restrict_members"_q) {
result |= ChatAdminRight::BanUsers;
} else if (element == u"invite_users"_q) {
result |= ChatAdminRight::InviteUsers;
} else if (element == u"pin_messages"_q) {
result |= ChatAdminRight::PinMessages;
} else if (element == u"promote_members"_q) {
result |= ChatAdminRight::AddAdmins;
} else if (element == u"manage_video_chats"_q) {
result |= ChatAdminRight::ManageCall;
} else if (element == u"anonymous"_q) {
result |= ChatAdminRight::Anonymous;
} else if (element == u"manage_chat"_q) {
result |= ChatAdminRight::Other;
} else {
return {};
}
}
return result;
}
bool ResolveUsernameOrPhone(
Window::SessionController *controller,
const Match &match,
@ -278,18 +311,24 @@ bool ResolveUsernameOrPhone(
} else if (!validDomain(domain) && !validPhone(phone)) {
return false;
}
auto start = qsl("start");
auto startToken = params.value(start);
if (startToken.isEmpty()) {
start = qsl("startgroup");
startToken = params.value(start);
if (startToken.isEmpty()) {
start = QString();
}
using BotStartType = Window::BotStartType;
auto startType = BotStartType::None;
auto startToken = params.value(u"start"_q);
if (!startToken.isEmpty()) {
startType = BotStartType::Personal;
} else if (params.contains(u"startgroup"_q)) {
startType = BotStartType::Group;
startToken = params.value(u"startgroup"_q);
} else if (params.contains(u"startchannel"_q)) {
startType = BotStartType::Channel;
}
auto post = ShowAtUnreadMsgId;
auto adminRights = ChatAdminRights();
if (startType == BotStartType::Group
|| startType == BotStartType::Channel) {
post = ShowAtProfileMsgId;
adminRights = ParseRequestedAdminRights(params.value(u"admin"_q));
}
auto post = (start == qsl("startgroup"))
? ShowAtProfileMsgId
: ShowAtUnreadMsgId;
const auto postParam = params.value(qsl("post"));
if (const auto postId = postParam.toInt()) {
post = postId;
@ -301,7 +340,8 @@ bool ResolveUsernameOrPhone(
const auto gameParam = params.value(qsl("game"));
if (!gameParam.isEmpty() && validDomain(gameParam)) {
startToken = gameParam;
post = ShowAtGameShareMsgId;
post = ShowAtProfileMsgId;
startType = BotStartType::ShareGame;
}
const auto fromMessageId = context.value<ClickHandlerContext>().itemId;
using Navigation = Window::SessionNavigation;
@ -318,7 +358,9 @@ bool ResolveUsernameOrPhone(
Navigation::ThreadId{ threadId }
}
: Navigation::RepliesByLinkInfo{ v::null },
.startType = startType,
.startToken = startToken,
.startAdminRights = adminRights,
.voicechatHash = (params.contains(u"livestream"_q)
? std::make_optional(params.value(u"livestream"_q))
: params.contains(u"videochat"_q)

View file

@ -84,7 +84,6 @@ constexpr auto ShowAtTheEndMsgId = MsgId(SpecialMsgIdShift + 1);
constexpr auto SwitchAtTopMsgId = MsgId(SpecialMsgIdShift + 2);
constexpr auto ShowAtProfileMsgId = MsgId(SpecialMsgIdShift + 3);
constexpr auto ShowAndStartBotMsgId = MsgId(SpecialMsgIdShift + 4);
constexpr auto ShowAtGameShareMsgId = MsgId(SpecialMsgIdShift + 5);
constexpr auto ShowForChooseMessagesMsgId = MsgId(SpecialMsgIdShift + 6);
static_assert(SpecialMsgIdShift + 0xFF < 0);

View file

@ -20,7 +20,7 @@ struct BotInfo {
std::vector<BotCommand> commands;
Ui::Text::String text = { int(st::msgMinWidth) }; // description
QString startToken, startGroupToken, shareGameShortName;
QString startToken;
Dialogs::EntryState inlineReturnTo;
ChatAdminRights groupAdminRights;

View file

@ -338,6 +338,7 @@ void SessionNavigation::showPeerByLinkResolved(
}).send();
return;
}
using Scope = AddBotToGroupBoxController::Scope;
const auto &replies = info.repliesInfo;
if (const auto threadId = std::get_if<ThreadId>(&replies)) {
showRepliesForMessage(
@ -351,31 +352,28 @@ void SessionNavigation::showPeerByLinkResolved(
info.messageId,
commentId->id,
params);
} else if (info.messageId == ShowAtGameShareMsgId) {
const auto user = peer->asUser();
if (user && user->isBot() && !info.startToken.isEmpty()) {
user->botInfo->shareGameShortName = info.startToken;
AddBotToGroupBoxController::Start(user);
} else {
crl::on_main(this, [=] {
showPeerHistory(peer->id, params);
});
}
} else if (info.messageId == ShowAtProfileMsgId && !peer->isChannel()) {
const auto user = peer->asUser();
if (user
&& user->isBot()
&& !user->botInfo->cantJoinGroups
&& !info.startToken.isEmpty()) {
user->botInfo->startGroupToken = info.startToken;
AddBotToGroupBoxController::Start(user);
} else if (user && user->isBot()) {
const auto scope = (info.startType == BotStartType::ShareGame)
? Scope::ShareGame
: (info.startType == BotStartType::Group)
? (info.startAdminRights ? Scope::GroupAdmin : Scope::All)
: (info.startType == BotStartType::Channel)
? Scope::ChannelAdmin
: Scope::None;
if (!user || !user->isBot()) {
showPeerInfo(peer, params);
} else if (scope != Scope::None) {
AddBotToGroupBoxController::Start(
user,
scope,
info.startToken,
info.startAdminRights);
} else {
// Always open bot chats, even from mention links.
crl::on_main(this, [=] {
showPeerHistory(peer->id, params);
});
} else {
showPeerInfo(peer, params);
}
} else {
const auto user = peer->asUser();

View file

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/observer.h"
#include "base/weak_ptr.h"
#include "base/timer.h"
#include "data/data_chat_participant_status.h"
#include "dialogs/dialogs_key.h"
#include "ui/layers/layer_widget.h"
#include "ui/layers/show.h"
@ -86,6 +87,14 @@ enum class GifPauseReason {
using GifPauseReasons = base::flags<GifPauseReason>;
inline constexpr bool is_flag_type(GifPauseReason) { return true; };
enum class BotStartType {
None,
Personal,
Group,
Channel,
ShareGame,
};
struct PeerThemeOverride {
PeerData *peer = nullptr;
std::shared_ptr<Ui::ChatTheme> theme;
@ -178,7 +187,9 @@ public:
QString phone;
MsgId messageId = ShowAtUnreadMsgId;
RepliesByLinkInfo repliesInfo;
BotStartType startType = BotStartType::None;
QString startToken;
ChatAdminRights startAdminRights;
std::optional<QString> voicechatHash;
FullMsgId clickFromMessageId;
};