From 01ab6e6d4db71ad1ef1774ca076643018e2de861 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 10 Sep 2020 14:19:48 +0300 Subject: [PATCH] Support anonymous group admins. --- Telegram/Resources/langs/lang.strings | 2 + Telegram/SourceFiles/api/api_sending.cpp | 28 ++++++------ Telegram/SourceFiles/apiwrap.cpp | 43 +++++++++++-------- .../boxes/peers/add_participants_box.cpp | 12 ++---- .../boxes/peers/edit_participant_box.cpp | 12 ++++-- .../boxes/peers/edit_participants_box.cpp | 15 ++++--- .../boxes/peers/edit_peer_permissions_box.cpp | 1 + Telegram/SourceFiles/data/data_peer.cpp | 6 +++ Telegram/SourceFiles/data/data_peer.h | 1 + .../SourceFiles/history/history_widget.cpp | 42 +++++++++++------- .../history/view/history_view_message.cpp | 7 ++- 11 files changed, 102 insertions(+), 67 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 4d97e1d2b..3f548a70d 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -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"; diff --git a/Telegram/SourceFiles/api/api_sending.cpp b/Telegram/SourceFiles/api/api_sending.cpp index 7beb8b54f..6d569ad4f 100644 --- a/Telegram/SourceFiles/api/api_sending.cpp +++ b/Telegram/SourceFiles/api/api_sending.cpp @@ -39,10 +39,12 @@ void InnerFillMessagePostFlags( const Api::SendOptions &options, not_null 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(); diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 56cbec2b3..3d03bea73 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -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; } diff --git a/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp b/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp index 8293ed24d..dda179e00 100644 --- a/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp @@ -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( @@ -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( @@ -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( diff --git a/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp index d5fd059d9..d23abb04c 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp @@ -254,7 +254,7 @@ void EditAdminBox::prepare() { const auto disabledMessages = [&] { auto result = std::map(); - 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); diff --git a/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp index a6a0c0ca5..9fb27894a 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp @@ -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 ParticipantsBoxController::rowContextMenu( void ParticipantsBoxController::showAdmin(not_null 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( @@ -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 ParticipantsBoxController::createRow( auto row = std::make_unique(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)); diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp index 91c7431b6..29ac53e51 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp @@ -135,6 +135,7 @@ std::vector> 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 { diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 1ebed16e2..5d7ca49f6 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -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() diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index d6c992cec..cd78adeaa 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -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; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 46ffd69aa..88553c622 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -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(); } diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index e598b4d13..10589de66 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -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;