Support anonymous group admins.

This commit is contained in:
John Preston 2020-09-10 14:19:48 +03:00
parent b8424b1d89
commit 01ab6e6d4d
11 changed files with 102 additions and 67 deletions

View file

@ -1320,6 +1320,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_message_ph" = "Write a message...";
"lng_broadcast_ph" = "Broadcast a message...";
"lng_broadcast_silent_ph" = "Silent broadcast...";
"lng_send_anonymous_ph" = "Send anonymously...";
"lng_record_cancel" = "Release outside this field to cancel";
"lng_will_be_notified" = "Members will be notified when you post";
"lng_wont_be_notified" = "Members will not be notified when you post";
@ -1834,6 +1835,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_rights_group_invite" = "Add users";
"lng_rights_group_pin" = "Pin messages";
"lng_rights_group_delete" = "Delete messages";
"lng_rights_group_anonymous" = "Remain Anonymous";
"lng_rights_add_admins" = "Add new admins";
"lng_rights_chat_read" = "Read messages";
"lng_rights_chat_send_text" = "Send messages";

View file

@ -39,10 +39,12 @@ void InnerFillMessagePostFlags(
const Api::SendOptions &options,
not_null<PeerData*> peer,
MTPDmessage::Flags &flags) {
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
if (!channelPost) {
const auto anonymousPost = peer->amAnonymous();
if (!anonymousPost) {
flags |= MTPDmessage::Flag::f_from_id;
return;
} else if (peer->asMegagroup()) {
return;
}
flags |= MTPDmessage::Flag::f_post;
// Don't display views and author of a new post when it's scheduled.
@ -82,15 +84,15 @@ void SendExistingMedia(
flags |= MTPDmessage::Flag::f_reply_to;
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
}
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = message.action.options.silent
|| (channelPost && session->data().notifySilentPosts(peer));
|| (peer->isBroadcast() && session->data().notifySilentPosts(peer));
InnerFillMessagePostFlags(message.action.options, peer, flags);
if (silentPost) {
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
}
auto messageFromId = channelPost ? 0 : session->userPeerId();
auto messagePostAuthor = channelPost ? session->user()->name : QString();
auto messageFromId = anonymousPost ? 0 : session->userPeerId();
auto messagePostAuthor = peer->isBroadcast() ? session->user()->name : QString();
auto caption = TextWithEntities{
message.textWithTags.text,
@ -253,15 +255,15 @@ bool SendDice(Api::MessageToSend &message) {
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
}
const auto replyHeader = NewMessageReplyHeader(message.action);
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = message.action.options.silent
|| (channelPost && session->data().notifySilentPosts(peer));
|| (peer->isBroadcast() && session->data().notifySilentPosts(peer));
InnerFillMessagePostFlags(message.action.options, peer, flags);
if (silentPost) {
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
}
auto messageFromId = channelPost ? 0 : session->userPeerId();
auto messagePostAuthor = channelPost ? session->user()->name : QString();
auto messageFromId = anonymousPost ? 0 : session->userPeerId();
auto messagePostAuthor = peer->isBroadcast() ? session->user()->name : QString();
const auto replyTo = message.action.replyTo;
if (message.action.options.scheduled) {
@ -395,7 +397,7 @@ void SendConfirmedFile(
flags |= MTPDmessage::Flag::f_reply_to;
}
const auto replyHeader = NewMessageReplyHeader(action);
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = file->to.options.silent;
Api::FillMessagePostFlags(action, peer, flags);
if (silentPost) {
@ -412,8 +414,8 @@ void SendConfirmedFile(
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
}
const auto messageFromId = channelPost ? 0 : session->userPeerId();
const auto messagePostAuthor = channelPost
const auto messageFromId = anonymousPost ? 0 : session->userPeerId();
const auto messagePostAuthor = peer->isBroadcast()
? session->user()->name
: QString();

View file

@ -1495,9 +1495,13 @@ void ApiWrap::applyLastParticipantsList(
});
const auto adminCanEdit = (p.type() == mtpc_channelParticipantAdmin)
? p.c_channelParticipantAdmin().is_can_edit()
: (p.type() == mtpc_channelParticipantCreator)
? channel->amCreator()
: false;
const auto adminRights = (p.type() == mtpc_channelParticipantAdmin)
? p.c_channelParticipantAdmin().vadmin_rights()
: (p.type() == mtpc_channelParticipantCreator)
? p.c_channelParticipantCreator().vadmin_rights()
: emptyAdminRights;
const auto restrictedRights = (p.type() == mtpc_channelParticipantBanned)
? p.c_channelParticipantBanned().vbanned_rights()
@ -3898,9 +3902,9 @@ void ApiWrap::forwardMessages(
histories.readInbox(history);
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = action.options.silent
|| (channelPost && _session->data().notifySilentPosts(peer));
|| (peer->isBroadcast() && _session->data().notifySilentPosts(peer));
auto flags = MTPDmessage::Flags(0);
auto clientFlags = MTPDmessage_ClientFlags();
@ -3970,10 +3974,10 @@ void ApiWrap::forwardMessages(
peerToChannel(peer->id),
_session->data().nextLocalMessageId());
const auto self = _session->user();
const auto messageFromId = channelPost
const auto messageFromId = anonymousPost
? PeerId(0)
: self->id;
const auto messagePostAuthor = channelPost
const auto messagePostAuthor = peer->isBroadcast()
? self->name
: QString();
history->addNewLocalMessage(
@ -4043,7 +4047,7 @@ void ApiWrap::sendSharedContact(
const auto newId = FullMsgId(
history->channelId(),
_session->data().nextLocalMessageId());
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto anonymousPost = peer->amAnonymous();
auto flags = NewMessageFlags(peer) | MTPDmessage::Flag::f_media;
auto clientFlags = NewMessageClientFlags();
@ -4057,8 +4061,8 @@ void ApiWrap::sendSharedContact(
} else {
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
}
const auto messageFromId = channelPost ? 0 : _session->userPeerId();
const auto messagePostAuthor = channelPost
const auto messageFromId = anonymousPost ? 0 : _session->userPeerId();
const auto messagePostAuthor = peer->isBroadcast()
? _session->user()->name
: QString();
const auto vcard = QString();
@ -4100,7 +4104,9 @@ void ApiWrap::sendSharedContact(
MTP_string(lastName),
MTP_string(vcard));
auto options = action.options;
options.silent = _session->data().notifySilentPosts(peer);
if (_session->data().notifySilentPosts(peer)) {
options.silent = true;
}
sendMedia(item, media, options);
_session->data().sendHistoryChangeNotifications();
@ -4323,9 +4329,9 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
MTP_int(page->pendingTill)));
flags |= MTPDmessage::Flag::f_media;
}
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = action.options.silent
|| (channelPost && _session->data().notifySilentPosts(peer));
|| (peer->isBroadcast() && _session->data().notifySilentPosts(peer));
FillMessagePostFlags(action, peer, flags);
if (silentPost) {
sendFlags |= MTPmessages_SendMessage::Flag::f_silent;
@ -4345,8 +4351,8 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
history->clearCloudDraft();
history->setSentDraftText(QString());
}
auto messageFromId = channelPost ? 0 : _session->userPeerId();
auto messagePostAuthor = channelPost
auto messageFromId = anonymousPost ? 0 : _session->userPeerId();
auto messagePostAuthor = peer->isBroadcast()
? _session->user()->name
: QString();
if (action.options.scheduled) {
@ -4465,9 +4471,9 @@ void ApiWrap::sendInlineResult(
flags |= MTPDmessage::Flag::f_reply_to;
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_reply_to_msg_id;
}
bool channelPost = peer->isChannel() && !peer->isMegagroup();
bool silentPost = action.options.silent
|| (channelPost && _session->data().notifySilentPosts(peer));
const auto anonymousPost = peer->amAnonymous();
const auto silentPost = action.options.silent
|| (peer->isBroadcast() && _session->data().notifySilentPosts(peer));
FillMessagePostFlags(action, peer, flags);
if (silentPost) {
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_silent;
@ -4482,8 +4488,8 @@ void ApiWrap::sendInlineResult(
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
}
const auto messageFromId = channelPost ? 0 : _session->userPeerId();
const auto messagePostAuthor = channelPost
const auto messageFromId = anonymousPost ? 0 : _session->userPeerId();
const auto messagePostAuthor = peer->isBroadcast()
? _session->user()->name
: QString();
@ -5203,9 +5209,8 @@ void ApiWrap::createPoll(
history->clearLocalDraft();
history->clearCloudDraft();
}
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto silentPost = action.options.silent
|| (channelPost && _session->data().notifySilentPosts(peer));
|| (peer->isBroadcast() && _session->data().notifySilentPosts(peer));
if (silentPost) {
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
}

View file

@ -576,11 +576,7 @@ void AddSpecialBoxController::showAdmin(
}
// Finally show the admin.
const auto currentRights = _additional.isCreator(user)
? MTPChatAdminRights(MTP_chatAdminRights(
MTP_flags(~MTPDchatAdminRights::Flag::f_add_admins
| MTPDchatAdminRights::Flag::f_add_admins)))
: adminRights
const auto currentRights = adminRights
? *adminRights
: MTPChatAdminRights(MTP_chatAdminRights(MTP_flags(0)));
auto box = Box<EditAdminBox>(
@ -618,7 +614,7 @@ void AddSpecialBoxController::editAdminDone(
_additional.applyParticipant(MTP_channelParticipantCreator(
MTP_flags(rank.isEmpty() ? Flag(0) : Flag::f_rank),
MTP_int(user->bareId()),
MTP_chatAdminRights(MTP_flags(0)), // #TODO anonymous
rights,
MTP_string(rank)));
} else if (rights.c_chatAdminRights().vflags().v == 0) {
_additional.applyParticipant(MTP_channelParticipant(
@ -666,7 +662,7 @@ void AddSpecialBoxController::showRestricted(
} else if (_additional.adminRights(user).has_value()
|| _additional.isCreator(user)) {
// The user is an admin or creator.
if (_additional.canEditAdmin(user)) {
if (!_additional.isCreator(user) && _additional.canEditAdmin(user)) {
if (!sure) {
_editBox = Ui::show(
Box<ConfirmBox>(
@ -756,7 +752,7 @@ void AddSpecialBoxController::kickUser(
if (_additional.adminRights(user).has_value()
|| _additional.isCreator(user)) {
// The user is an admin or creator.
if (_additional.canEditAdmin(user)) {
if (!_additional.isCreator(user) && _additional.canEditAdmin(user)) {
if (!sure) {
_editBox = Ui::show(
Box<ConfirmBox>(

View file

@ -254,7 +254,7 @@ void EditAdminBox::prepare() {
const auto disabledMessages = [&] {
auto result = std::map<Flags, QString>();
if (!canSave() || (amCreator() && user()->isSelf())) {
if (!canSave()) {
result.emplace(
~Flags(0),
tr::lng_rights_about_admin_cant_edit(tr::now));
@ -263,7 +263,11 @@ void EditAdminBox::prepare() {
disabledByDefaults,
tr::lng_rights_permission_for_all(tr::now));
if (const auto channel = peer()->asChannel()) {
if (!channel->amCreator()) {
if (amCreator() && user()->isSelf()) {
result.emplace(
~Flag::f_anonymous,
tr::lng_rights_permission_cant_edit(tr::now));
} else if (!channel->amCreator()) {
result.emplace(
~channel->adminRights(),
tr::lng_rights_permission_cant_edit(tr::now));
@ -570,7 +574,9 @@ void EditAdminBox::sendTransferRequestFrom(
void EditAdminBox::refreshAboutAddAdminsText(bool canAddAdmins) {
_aboutAddAdmins->setText([&] {
if (!canSave() || (amCreator() && user()->isSelf())) {
if (amCreator() && user()->isSelf()) {
return QString();
} else if (!canSave()) {
return tr::lng_rights_about_admin_cant_edit(tr::now);
} else if (canAddAdmins) {
return tr::lng_rights_about_add_admins_yes(tr::now);

View file

@ -564,6 +564,12 @@ UserData *ParticipantsAdditionalData::applyCreator(
const MTPDchannelParticipantCreator &data) {
if (const auto user = applyRegular(data.vuser_id())) {
_creator = user;
_adminRights[user] = data.vadmin_rights();
if (user->isSelf()) {
_adminCanEdit.emplace(user);
} else {
_adminCanEdit.erase(user);
}
if (const auto rank = data.vrank()) {
_adminRanks[user] = qs(*rank);
} else {
@ -1459,11 +1465,7 @@ base::unique_qptr<Ui::PopupMenu> ParticipantsBoxController::rowContextMenu(
void ParticipantsBoxController::showAdmin(not_null<UserData*> user) {
const auto adminRights = _additional.adminRights(user);
const auto currentRights = _additional.isCreator(user)
? MTPChatAdminRights(MTP_chatAdminRights(
MTP_flags(~MTPDchatAdminRights::Flag::f_add_admins
| MTPDchatAdminRights::Flag::f_add_admins)))
: adminRights
const auto currentRights = adminRights
? *adminRights
: MTPChatAdminRights(MTP_chatAdminRights(MTP_flags(0)));
auto box = Box<EditAdminBox>(
@ -1504,7 +1506,7 @@ void ParticipantsBoxController::editAdminDone(
_additional.applyParticipant(MTP_channelParticipantCreator(
MTP_flags(rank.isEmpty() ? Flag(0) : Flag::f_rank),
MTP_int(user->bareId()),
MTP_chatAdminRights(MTP_flags(0)), // #TODO anonymous
rights,
MTP_string(rank)));
} else if (rights.c_chatAdminRights().vflags().v == 0) {
_additional.applyParticipant(MTP_channelParticipant(
@ -1784,6 +1786,7 @@ std::unique_ptr<PeerListRow> ParticipantsBoxController::createRow(
auto row = std::make_unique<PeerListRowWithLink>(user);
refreshCustomStatus(row.get());
if (_role == Role::Admins
&& !_additional.isCreator(user)
&& _additional.adminRights(user).has_value()
&& _additional.canEditAdmin(user)) {
row->setActionLink(tr::lng_profile_kick(tr::now));

View file

@ -135,6 +135,7 @@ std::vector<std::pair<ChatAdminRights, QString>> AdminRightLabels(
? tr::lng_rights_group_invite_link(tr::now)
: tr::lng_rights_group_invite(tr::now) },
{ Flag::f_pin_messages, tr::lng_rights_group_pin(tr::now) },
{ Flag::f_anonymous, tr::lng_rights_group_anonymous(tr::now) },
{ Flag::f_add_admins, tr::lng_rights_add_admins(tr::now) },
};
} else {

View file

@ -790,6 +790,12 @@ Data::RestrictionCheckResult PeerData::amRestricted(
return Result::Allowed();
}
bool PeerData::amAnonymous() const {
return isBroadcast()
|| (isChannel()
&& (asChannel()->adminRights() & ChatAdminRight::f_anonymous));
}
bool PeerData::canRevokeFullHistory() const {
return isUser()
&& !isSelf()

View file

@ -192,6 +192,7 @@ public:
[[nodiscard]] bool canWrite() const;
[[nodiscard]] Data::RestrictionCheckResult amRestricted(
ChatRestriction right) const;
[[nodiscard]] bool amAnonymous() const;
[[nodiscard]] bool canRevokeFullHistory() const;
[[nodiscard]] bool slowmodeApplied() const;
[[nodiscard]] int slowmodeSecondsLeft() const;

View file

@ -578,6 +578,7 @@ HistoryWidget::HistoryWidget(
if (flags & UpdateFlag::Rights) {
checkPreview();
updateStickersByEmoji();
updateFieldPlaceholder();
}
if (flags & UpdateFlag::Migration) {
handlePeerMigration();
@ -4031,23 +4032,32 @@ void HistoryWidget::onCheckFieldAutocomplete() {
}
void HistoryWidget::updateFieldPlaceholder() {
if (_editMsgId) {
_field->setPlaceholder(tr::lng_edit_message_text());
} else {
if (_inlineBot && !_inlineLookingUpBot) {
_field->setPlaceholder(
rpl::single(_inlineBot->botInfo->inlinePlaceholder.mid(1)),
_inlineBot->username.size() + 2);
} else {
const auto peer = _history ? _history->peer.get() : nullptr;
_field->setPlaceholder(
((peer && peer->isChannel() && !peer->isMegagroup())
? (session().data().notifySilentPosts(peer)
? tr::lng_broadcast_silent_ph()
: tr::lng_broadcast_ph())
: tr::lng_message_ph()));
}
if (!_editMsgId && _inlineBot && !_inlineLookingUpBot) {
_field->setPlaceholder(
rpl::single(_inlineBot->botInfo->inlinePlaceholder.mid(1)),
_inlineBot->username.size() + 2);
return;
}
_field->setPlaceholder([&] {
if (_editMsgId) {
return tr::lng_edit_message_text();
} else if (!_history) {
return tr::lng_message_ph();
} else if (const auto channel = _history->peer->asChannel()) {
if (channel->isBroadcast()) {
return session().data().notifySilentPosts(channel)
? tr::lng_broadcast_silent_ph()
: tr::lng_broadcast_ph();
} else if (channel->adminRights() & ChatAdminRight::f_anonymous) {
return tr::lng_send_anonymous_ph();
} else {
return tr::lng_message_ph();
}
} else {
return tr::lng_message_ph();
}
}());
updateSendButtonType();
}

View file

@ -732,7 +732,10 @@ void Message::paintFromName(
p.setFont(st::msgNameFont);
const auto nameText = [&]() -> const Ui::Text::String * {
const auto from = item->displayFrom();
if (item->isPost()) {
if (hasOutLayout()) {
p.setPen(selected ? st::msgOutServiceFgSelected : st::msgOutServiceFg);
return &from->nameText();
} else if (item->isPost()) {
p.setPen(selected ? st::msgInServiceFgSelected : st::msgInServiceFg);
return &from->nameText();
} else if (from) {
@ -1839,7 +1842,7 @@ bool Message::hasFromName() const {
return true;
case Context::History: {
const auto item = message();
return !hasOutLayout()
return (!hasOutLayout() || item->from()->isMegagroup())
&& (!item->history()->peer->isUser()
|| item->history()->peer->isSelf());
} break;