Correctly handle complex pin_messages/manage_topics.

This commit is contained in:
John Preston 2022-10-24 13:13:21 +04:00
parent 53beb6f562
commit 70e5f752ba
16 changed files with 135 additions and 53 deletions

View file

@ -2891,6 +2891,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_rights_group_invite" = "Add users";
"lng_rights_group_pin" = "Pin messages";
"lng_rights_group_pin_with_topics" = "Pin messages and topics";
"lng_rights_group_pin_topics" = "Pin topics";
"lng_rights_group_topics" = "Manage topics";
"lng_rights_group_add_topics" = "Create topics";
"lng_rights_group_manage_calls" = "Manage voice chats";
@ -3109,6 +3110,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_admin_log_admin_invite_users" = "Add members";
"lng_admin_log_admin_invite_link" = "Invite users via link";
"lng_admin_log_admin_pin_messages" = "Pin messages";
"lng_admin_log_admin_pin_messages_topics" = "Pin messages and topics";
"lng_admin_log_admin_pin_topics" = "Pin topics";
"lng_admin_log_admin_manage_topics" = "Manage topics";
"lng_admin_log_admin_create_topics" = "Create topics";
"lng_admin_log_admin_manage_calls" = "Manage voice chats";
"lng_admin_log_admin_manage_calls_channel" = "Manage live streams";
"lng_admin_log_admin_add_admins" = "Add new admins";

View file

@ -647,7 +647,7 @@ rightsHeaderLabel: FlatLabel(boxLabel) {
textFg: windowActiveTextFg;
}
rightsUntilMargin: margins(0px, 8px, 0px, 20px);
rightsRankMargin: margins(0px, 16px, 0px, 20px);
rightsRankMargin: margins(0px, 7px, 0px, 20px);
mutePhotoButton: UserpicButton(defaultUserpicButton) {
size: size(40px, 40px);

View file

@ -222,15 +222,15 @@ ChatAdminRightsInfo EditAdminBox::defaultRights() const {
? ChatAdminRightsInfo{ (Flag::ChangeInfo
| Flag::DeleteMessages
| Flag::BanUsers
| Flag::InviteUsers
| Flag::PinMessages
| Flag::InviteByLinkOrAdd
| Flag::ManageTopics
| Flag::PinMessagesOrTopics
| Flag::ManageCall) }
: ChatAdminRightsInfo{ (Flag::ChangeInfo
| Flag::PostMessages
| Flag::EditMessages
| Flag::DeleteMessages
| Flag::InviteUsers
| Flag::InviteByLinkOrAdd
| Flag::ManageCall) };
}
@ -329,10 +329,14 @@ void EditAdminBox::prepare() {
const auto anyoneCanAddMembers = chat
? chat->anyoneCanAddMembers()
: channel->anyoneCanAddMembers();
const auto anyoneCanPinMessages = chat
? chat->anyoneCanPinMessages()
: channel->anyoneCanPinMessages();
const auto options = Data::AdminRightsSetOptions{
.isGroup = isGroup,
.isForum = peer()->isForum(),
.anyoneCanAddMembers = anyoneCanAddMembers,
.anyoneCanPinMessages = anyoneCanPinMessages,
};
auto [checkboxes, getChecked, changes] = CreateEditAdminRights(
inner,

View file

@ -148,7 +148,8 @@ ChatRestrictions NegateRestrictions(ChatRestrictions value) {
//| Flag::ViewMessages
| Flag::ChangeInfo
| Flag::EmbedLinks
| Flag::InviteUsers
| Flag::AddParticipants
| Flag::CreateTopics
| Flag::PinMessages
| Flag::SendGames
| Flag::SendGifs
@ -185,12 +186,15 @@ ChatRestrictions DisabledByAdminRights(not_null<PeerData*> peer) {
Unexpected("User in DisabledByAdminRights.");
}();
return Flag(0)
| ((adminRights & Admin::PinMessages)
| ((adminRights & Admin::ManageTopics)
? Flag(0)
: Flag::CreateTopics)
| ((adminRights & Admin::PinMessagesOrTopics)
? Flag(0)
: Flag::PinMessages)
| ((adminRights & Admin::InviteUsers)
| ((adminRights & Admin::InviteByLinkOrAdd)
? Flag(0)
: Flag::InviteUsers)
: Flag::AddParticipants)
| ((adminRights & Admin::ChangeInfo)
? Flag(0)
: Flag::ChangeInfo);
@ -307,18 +311,23 @@ ChatAdminRights DisabledByDefaultRestrictions(not_null<PeerData*> peer) {
}
Unexpected("User in DisabledByDefaultRestrictions.");
}());
const auto forum = peer->isForum();
return Flag(0)
| ((restrictions & Restriction::PinMessages)
//
// We allow to edit 'pin_messages' admin right in forums
// even if it is allowed in default permissions, because
// if everyone can 'pin_messages' admin can also pin topics.
| ((forum || (restrictions & Restriction::PinMessages))
? Flag(0)
: Flag::PinMessages)
: Flag::PinMessagesOrTopics)
//
// We allow to edit 'invite_users' admin right no matter what
// is chosen in default permissions for 'invite_users', because
// if everyone can 'invite_users' it handles invite link for admins.
//
//| ((restrictions & Restriction::InviteUsers)
//| ((restrictions & Restriction::AddParticipants)
// ? Flag(0)
// : Flag::InviteUsers)
// : Flag::InviteByLinkOrAdd)
//
| ((restrictions & Restriction::ChangeInfo)
? Flag(0)
@ -727,8 +736,8 @@ std::vector<RestrictionLabel> RestrictionLabels(
| Flag::SendInline, tr::lng_rights_chat_send_stickers(tr::now) },
{ Flag::EmbedLinks, tr::lng_rights_chat_send_links(tr::now) },
{ Flag::SendPolls, tr::lng_rights_chat_send_polls(tr::now) },
{ Flag::InviteUsers, tr::lng_rights_chat_add_members(tr::now) },
{ Flag::ManageTopics, tr::lng_rights_group_add_topics(tr::now) },
{ Flag::AddParticipants, tr::lng_rights_chat_add_members(tr::now) },
{ Flag::CreateTopics, tr::lng_rights_group_add_topics(tr::now) },
{ Flag::PinMessages, tr::lng_rights_group_pin(tr::now) },
{ Flag::ChangeInfo, tr::lng_rights_group_info(tr::now) },
};
@ -736,7 +745,7 @@ std::vector<RestrictionLabel> RestrictionLabels(
result.erase(
ranges::remove(
result,
Flag::ManageTopics,
Flag::CreateTopics,
&RestrictionLabel::flags),
end(result));
}
@ -752,13 +761,15 @@ std::vector<AdminRightLabel> AdminRightLabels(
{ Flag::ChangeInfo, tr::lng_rights_group_info(tr::now) },
{ Flag::DeleteMessages, tr::lng_rights_group_delete(tr::now) },
{ Flag::BanUsers, tr::lng_rights_group_ban(tr::now) },
{ Flag::InviteUsers, options.anyoneCanAddMembers
{ Flag::InviteByLinkOrAdd, options.anyoneCanAddMembers
? tr::lng_rights_group_invite_link(tr::now)
: tr::lng_rights_group_invite(tr::now) },
{ Flag::ManageTopics, tr::lng_rights_group_topics(tr::now) },
{ Flag::PinMessages, options.isForum
? tr::lng_rights_group_pin_with_topics(tr::now)
: tr::lng_rights_group_pin(tr::now) },
{ Flag::PinMessagesOrTopics, !options.isForum
? tr::lng_rights_group_pin(tr::now)
: options.anyoneCanPinMessages
? tr::lng_rights_group_pin_topics(tr::now)
: tr::lng_rights_group_pin_with_topics(tr::now) },
{ Flag::ManageCall, tr::lng_rights_group_manage_calls(tr::now) },
{ Flag::Anonymous, tr::lng_rights_group_anonymous(tr::now) },
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) },
@ -778,7 +789,7 @@ std::vector<AdminRightLabel> AdminRightLabels(
{ Flag::PostMessages, tr::lng_rights_channel_post(tr::now) },
{ Flag::EditMessages, tr::lng_rights_channel_edit(tr::now) },
{ Flag::DeleteMessages, tr::lng_rights_channel_delete(tr::now) },
{ Flag::InviteUsers, tr::lng_rights_group_invite(tr::now) },
{ Flag::InviteByLinkOrAdd, tr::lng_rights_group_invite(tr::now) },
{ Flag::ManageCall, tr::lng_rights_channel_manage_calls(tr::now) },
{ Flag::AddAdmins, tr::lng_rights_add_admins(tr::now) }
};

View file

@ -295,9 +295,11 @@ bool ShowWallPaper(
} else if (element == u"restrict_members"_q) {
result |= ChatAdminRight::BanUsers;
} else if (element == u"invite_users"_q) {
result |= ChatAdminRight::InviteUsers;
result |= ChatAdminRight::InviteByLinkOrAdd;
} else if (element == u"manage_topics"_q) {
result |= ChatAdminRight::ManageTopics;
} else if (element == u"pin_messages"_q) {
result |= ChatAdminRight::PinMessages;
result |= ChatAdminRight::PinMessagesOrTopics;
} else if (element == u"promote_members"_q) {
result |= ChatAdminRight::AddAdmins;
} else if (element == u"manage_video_chats"_q) {

View file

@ -201,7 +201,7 @@ void ChannelData::setInviteLink(const QString &newInviteLink) {
bool ChannelData::canHaveInviteLink() const {
return amCreator()
|| (adminRights() & AdminRight::InviteUsers);
|| (adminRights() & AdminRight::InviteByLinkOrAdd);
}
void ChannelData::setLocation(const MTPChannelLocation &data) {
@ -525,7 +525,11 @@ bool ChannelData::canDeleteMessages() const {
}
bool ChannelData::anyoneCanAddMembers() const {
return !(defaultRestrictions() & Restriction::InviteUsers);
return !(defaultRestrictions() & Restriction::AddParticipants);
}
bool ChannelData::anyoneCanPinMessages() const {
return !(defaultRestrictions() & Restriction::PinMessages);
}
bool ChannelData::hiddenPreHistory() const {
@ -534,8 +538,8 @@ bool ChannelData::hiddenPreHistory() const {
bool ChannelData::canAddMembers() const {
return isMegagroup()
? !amRestricted(ChatRestriction::InviteUsers)
: ((adminRights() & AdminRight::InviteUsers) || amCreator());
? !amRestricted(ChatRestriction::AddParticipants)
: ((adminRights() & AdminRight::InviteByLinkOrAdd) || amCreator());
}
bool ChannelData::canSendPolls() const {

View file

@ -324,6 +324,7 @@ public:
[[nodiscard]] bool canBanMembers() const;
[[nodiscard]] bool canSendPolls() const;
[[nodiscard]] bool anyoneCanAddMembers() const;
[[nodiscard]] bool anyoneCanPinMessages() const;
[[nodiscard]] bool canEditMessages() const;
[[nodiscard]] bool canDeleteMessages() const;

View file

@ -57,8 +57,8 @@ ChatAdminRightsInfo ChatData::defaultAdminRights(not_null<UserData*> user) {
| Flag::ChangeInfo
| Flag::DeleteMessages
| Flag::BanUsers
| Flag::InviteUsers
| Flag::PinMessages
| Flag::InviteByLinkOrAdd
| Flag::PinMessagesOrTopics
| Flag::ManageCall
| (isCreator ? Flag::AddAdmins : Flag(0)));
}
@ -96,7 +96,7 @@ bool ChatData::canDeleteMessages() const {
}
bool ChatData::canAddMembers() const {
return amIn() && !amRestricted(ChatRestriction::InviteUsers);
return amIn() && !amRestricted(ChatRestriction::AddParticipants);
}
bool ChatData::canSendPolls() const {
@ -113,7 +113,11 @@ bool ChatData::canBanMembers() const {
}
bool ChatData::anyoneCanAddMembers() const {
return !(defaultRestrictions() & ChatRestriction::InviteUsers);
return !(defaultRestrictions() & ChatRestriction::AddParticipants);
}
bool ChatData::anyoneCanPinMessages() const {
return !(defaultRestrictions() & ChatRestriction::PinMessages);
}
void ChatData::setName(const QString &newName) {
@ -147,7 +151,7 @@ void ChatData::setInviteLink(const QString &newInviteLink) {
bool ChatData::canHaveInviteLink() const {
return amCreator()
|| (adminRights() & ChatAdminRight::InviteUsers);
|| (adminRights() & ChatAdminRight::InviteByLinkOrAdd);
}
void ChatData::setAdminRights(ChatAdminRights rights) {

View file

@ -112,6 +112,7 @@ public:
[[nodiscard]] bool canBanMembers() const;
[[nodiscard]] bool canSendPolls() const;
[[nodiscard]] bool anyoneCanAddMembers() const;
[[nodiscard]] bool anyoneCanPinMessages() const;
void applyEditAdmin(not_null<UserData*> user, bool isAdmin);

View file

@ -18,8 +18,8 @@ enum class ChatAdminRight {
EditMessages = (1 << 2),
DeleteMessages = (1 << 3),
BanUsers = (1 << 4),
InviteUsers = (1 << 5),
PinMessages = (1 << 7),
InviteByLinkOrAdd = (1 << 5),
PinMessagesOrTopics = (1 << 7),
AddAdmins = (1 << 9),
Anonymous = (1 << 10),
ManageCall = (1 << 11),
@ -40,9 +40,9 @@ enum class ChatRestriction {
EmbedLinks = (1 << 7),
SendPolls = (1 << 8),
ChangeInfo = (1 << 10),
InviteUsers = (1 << 15),
AddParticipants = (1 << 15),
PinMessages = (1 << 17),
ManageTopics = (1 << 18),
CreateTopics = (1 << 18),
};
inline constexpr bool is_flag_type(ChatRestriction) { return true; }
using ChatRestrictions = base::flags<ChatRestriction>;
@ -74,6 +74,7 @@ struct AdminRightsSetOptions {
bool isGroup : 1 = false;
bool isForum : 1 = false;
bool anyoneCanAddMembers : 1 = false;
bool anyoneCanPinMessages : 1 = false;
};
struct RestrictionsSetOptions {

View file

@ -210,10 +210,12 @@ bool ForumTopic::canEdit() const {
}
bool ForumTopic::canDelete() const {
return !creating()
&& (channel()->canEditTopics()
// We don't know if we can delete or not.
/*|| (my() && onlyOneMyMessage)*/);
if (creating()) {
return false;
} else if (channel()->canDeleteMessages()) {
return true;
}
return my() && replies()->canDeleteMyTopic();
}
bool ForumTopic::canToggleClosed() const {
@ -221,7 +223,12 @@ bool ForumTopic::canToggleClosed() const {
}
bool ForumTopic::canTogglePinned() const {
return !creating() && channel()->canEditTopics();
if (creating()) {
return false;
}
const auto channel = this->channel();
return channel->amCreator()
|| (channel->adminRights() & ChatAdminRight::PinMessagesOrTopics);
}
bool ForumTopic::creating() const {

View file

@ -524,21 +524,25 @@ bool PeerData::canPinMessages() const {
} else if (const auto channel = asChannel()) {
return channel->isMegagroup()
? !channel->amRestricted(ChatRestriction::PinMessages)
: ((channel->adminRights() & ChatAdminRight::EditMessages)
|| channel->amCreator());
: ((channel->amCreator()
|| channel->adminRights() & ChatAdminRight::EditMessages));
}
Unexpected("Peer type in PeerData::canPinMessages.");
}
bool PeerData::canCreateTopics() const {
return isForum() && canPinMessages();
if (const auto channel = asChannel()) {
return channel->isForum()
&& !channel->amRestricted(ChatRestriction::CreateTopics);
}
return false;
}
bool PeerData::canEditTopics() const {
if (const auto channel = asChannel()) {
return channel->isForum()
&& (channel->amCreator()
|| (channel->adminRights() & ChatAdminRight::PinMessages));
|| (channel->adminRights() & ChatAdminRight::ManageTopics));
}
return false;
}
@ -959,12 +963,14 @@ Data::RestrictionCheckResult PeerData::amRestricted(
ChatRestriction right) const {
using Result = Data::RestrictionCheckResult;
const auto allowByAdminRights = [](auto right, auto chat) -> bool {
if (right == ChatRestriction::InviteUsers) {
return chat->adminRights() & ChatAdminRight::InviteUsers;
if (right == ChatRestriction::AddParticipants) {
return chat->adminRights() & ChatAdminRight::InviteByLinkOrAdd;
} else if (right == ChatRestriction::ChangeInfo) {
return chat->adminRights() & ChatAdminRight::ChangeInfo;
} else if (right == ChatRestriction::CreateTopics) {
return chat->adminRights() & ChatAdminRight::ManageTopics;
} else if (right == ChatRestriction::PinMessages) {
return chat->adminRights() & ChatAdminRight::PinMessages;
return chat->adminRights() & ChatAdminRight::PinMessagesOrTopics;
} else {
return chat->hasAdminRights();
}

View file

@ -264,7 +264,7 @@ rpl::producer<bool> CanPinMessagesValue(not_null<PeerData*> peer) {
| ChatDataFlag::Creator;
return rpl::combine(
PeerFlagsValue(chat, mask),
AdminRightValue(chat, ChatAdminRight::PinMessages),
AdminRightValue(chat, ChatAdminRight::PinMessagesOrTopics),
DefaultRestrictionValue(chat, ChatRestriction::PinMessages),
[](
ChatDataFlags flags,
@ -284,7 +284,7 @@ rpl::producer<bool> CanPinMessagesValue(not_null<PeerData*> peer) {
return rpl::single(true);
}
return rpl::combine(
AdminRightValue(megagroup, ChatAdminRight::PinMessages),
AdminRightValue(megagroup, ChatAdminRight::PinMessagesOrTopics),
DefaultRestrictionValue(megagroup, ChatRestriction::PinMessages),
PeerFlagsValue(
megagroup,

View file

@ -28,6 +28,7 @@ namespace {
constexpr auto kMessagesPerPage = 50;
constexpr auto kReadRequestTimeout = 3 * crl::time(1000);
constexpr auto kMaxMessagesToDeleteMyTopic = 10;
[[nodiscard]] HistoryService *GenerateDivider(
not_null<History*> history,
@ -947,4 +948,25 @@ void RepliesList::reloadUnreadCountIfNeeded() {
}
}
bool RepliesList::canDeleteMyTopic() const {
if (_skippedBefore != 0 || _skippedAfter != 0) {
return false;
}
auto counter = 0;
const auto owner = &_history->owner();
const auto peerId = _history->peer->id;
for (const auto &id : _list) {
if (id == _rootId) {
continue;
} else if (const auto item = owner->message(peerId, id)) {
if (!item->out() || ++counter > kMaxMessagesToDeleteMyTopic) {
return false;
}
} else {
return false;
}
}
return true;
}
} // namespace Data

View file

@ -54,6 +54,8 @@ public:
void readTill(not_null<HistoryItem*> item);
void readTill(MsgId tillId);
[[nodiscard]] bool canDeleteMyTopic() const;
[[nodiscard]] rpl::lifetime &lifetime() {
return _lifetime;
}

View file

@ -199,9 +199,18 @@ TextWithEntities GenerateAdminChangeText(
const auto useInviteLinkPhrase = channel->isMegagroup()
&& channel->anyoneCanAddMembers();
const auto pinMessagesAndTopics = channel->isForum()
&& !channel->anyoneCanPinMessages();
const auto pinOnlyTopics = channel->isForum()
&& channel->anyoneCanPinMessages();
const auto invitePhrase = useInviteLinkPhrase
? tr::lng_admin_log_admin_invite_link
: tr::lng_admin_log_admin_invite_users;
const auto pinPhrase = pinOnlyTopics
? tr::lng_admin_log_admin_pin_topics
: pinMessagesAndTopics
? tr::lng_admin_log_admin_pin_messages_topics
: tr::lng_admin_log_admin_pin_messages;
const auto callPhrase = channel->isBroadcast()
? tr::lng_admin_log_admin_manage_calls_channel
: tr::lng_admin_log_admin_manage_calls;
@ -211,12 +220,14 @@ TextWithEntities GenerateAdminChangeText(
{ Flag::EditMessages, tr::lng_admin_log_admin_edit_messages },
{ Flag::DeleteMessages, tr::lng_admin_log_admin_delete_messages },
{ Flag::BanUsers, tr::lng_admin_log_admin_ban_users },
{ Flag::InviteUsers, invitePhrase },
{ Flag::PinMessages, tr::lng_admin_log_admin_pin_messages },
{ Flag::InviteByLinkOrAdd, invitePhrase },
{ Flag::ManageTopics, tr::lng_admin_log_admin_manage_topics },
{ Flag::PinMessagesOrTopics, pinPhrase },
{ Flag::ManageCall, tr::lng_admin_log_admin_manage_calls },
{ Flag::AddAdmins, tr::lng_admin_log_admin_add_admins },
};
phraseMap[Flag::InviteUsers] = invitePhrase;
phraseMap[Flag::InviteByLinkOrAdd] = invitePhrase;
phraseMap[Flag::PinMessagesOrTopics] = pinPhrase;
phraseMap[Flag::ManageCall] = callPhrase;
if (!channel->isMegagroup()) {
@ -253,7 +264,8 @@ QString GeneratePermissionsChangeText(
{ Flag::EmbedLinks, tr::lng_admin_log_banned_embed_links },
{ Flag::SendPolls, tr::lng_admin_log_banned_send_polls },
{ Flag::ChangeInfo, tr::lng_admin_log_admin_change_info },
{ Flag::InviteUsers, tr::lng_admin_log_admin_invite_users },
{ Flag::AddParticipants, tr::lng_admin_log_admin_invite_users },
{ Flag::CreateTopics, tr::lng_admin_log_admin_create_topics },
{ Flag::PinMessages, tr::lng_admin_log_admin_pin_messages },
};
return CollectChanges(phraseMap, prevRights.flags, newRights.flags);