Update API scheme to layer 126.

This commit is contained in:
John Preston 2021-03-19 18:01:21 +04:00
parent 0052c7938f
commit a0a13c3b86
18 changed files with 447 additions and 300 deletions

View file

@ -620,7 +620,7 @@ channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant;
channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant; channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant;
channelParticipantCreator#447dca4b flags:# user_id:int admin_rights:ChatAdminRights rank:flags.0?string = ChannelParticipant; channelParticipantCreator#447dca4b flags:# user_id:int admin_rights:ChatAdminRights rank:flags.0?string = ChannelParticipant;
channelParticipantAdmin#ccbebbaf flags:# can_edit:flags.0?true self:flags.1?true user_id:int inviter_id:flags.1?int promoted_by:int date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant; channelParticipantAdmin#ccbebbaf flags:# can_edit:flags.0?true self:flags.1?true user_id:int inviter_id:flags.1?int promoted_by:int date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant;
channelParticipantBanned#1c0facaf flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChatBannedRights = ChannelParticipant; channelParticipantBanned#50a1dfd6 flags:# left:flags.0?true peer:Peer kicked_by:int date:int banned_rights:ChatBannedRights = ChannelParticipant;
channelParticipantLeft#c3c6796b user_id:int = ChannelParticipant; channelParticipantLeft#c3c6796b user_id:int = ChannelParticipant;
channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter;
@ -632,10 +632,10 @@ channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter;
channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter; channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter;
channelParticipantsMentions#e04b5ceb flags:# q:flags.0?string top_msg_id:flags.1?int = ChannelParticipantsFilter; channelParticipantsMentions#e04b5ceb flags:# q:flags.0?string top_msg_id:flags.1?int = ChannelParticipantsFilter;
channels.channelParticipants#f56ee2a8 count:int participants:Vector<ChannelParticipant> users:Vector<User> = channels.ChannelParticipants; channels.channelParticipants#9ab0feaf count:int participants:Vector<ChannelParticipant> chats:Vector<Chat> users:Vector<User> = channels.ChannelParticipants;
channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants;
channels.channelParticipant#d0d9b163 participant:ChannelParticipant users:Vector<User> = channels.ChannelParticipant; channels.channelParticipant#dfb80317 participant:ChannelParticipant chats:Vector<Chat> users:Vector<User> = channels.ChannelParticipant;
help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector<MessageEntity> min_age_confirm:flags.1?int = help.TermsOfService; help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector<MessageEntity> min_age_confirm:flags.1?int = help.TermsOfService;
@ -1557,7 +1557,7 @@ channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = mes
channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector<int> = Bool; channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector<int> = Bool;
channels.getMessages#ad8c9a23 channel:InputChannel id:Vector<InputMessage> = messages.Messages; channels.getMessages#ad8c9a23 channel:InputChannel id:Vector<InputMessage> = messages.Messages;
channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:int = channels.ChannelParticipants; channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:int = channels.ChannelParticipants;
channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant; channels.getParticipant#a0ab6cc6 channel:InputChannel participant:InputPeer = channels.ChannelParticipant;
channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats; channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats;
channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull;
channels.createChannel#3d5fb10f flags:# broadcast:flags.0?true megagroup:flags.1?true for_import:flags.3?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string = Updates; channels.createChannel#3d5fb10f flags:# broadcast:flags.0?true megagroup:flags.1?true for_import:flags.3?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string = Updates;
@ -1573,7 +1573,7 @@ channels.deleteChannel#c0111fe3 channel:InputChannel = Updates;
channels.exportMessageLink#e63fadeb flags:# grouped:flags.0?true thread:flags.1?true channel:InputChannel id:int = ExportedMessageLink; channels.exportMessageLink#e63fadeb flags:# grouped:flags.0?true thread:flags.1?true channel:InputChannel id:int = ExportedMessageLink;
channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates; channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates;
channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true = messages.Chats; channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true = messages.Chats;
channels.editBanned#72796912 channel:InputChannel user_id:InputUser banned_rights:ChatBannedRights = Updates; channels.editBanned#96e6cd81 channel:InputChannel participant:InputPeer banned_rights:ChatBannedRights = Updates;
channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector<InputUser> max_id:long min_id:long limit:int = channels.AdminLogResults; channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector<InputUser> max_id:long min_id:long limit:int = channels.AdminLogResults;
channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool;
channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = Bool; channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = Bool;
@ -1645,4 +1645,4 @@ stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel
stats.getMessagePublicForwards#5630281b channel:InputChannel msg_id:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; stats.getMessagePublicForwards#5630281b channel:InputChannel msg_id:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats; stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats;
// LAYER 125 // LAYER 126

View file

@ -1526,8 +1526,11 @@ void ApiWrap::applyLastParticipantsList(
MTP_flags(0), MTP_flags(0),
MTP_int(0)); MTP_int(0));
for (const auto &p : list) { for (const auto &p : list) {
const auto userId = p.match([](const auto &data) { const auto participantId = p.match([](
return data.vuser_id().v; const MTPDchannelParticipantBanned &data) {
return peerFromMTP(data.vpeer());
}, [](const auto &data) {
return peerFromUser(data.vuser_id());
}); });
const auto adminCanEdit = (p.type() == mtpc_channelParticipantAdmin) const auto adminCanEdit = (p.type() == mtpc_channelParticipantAdmin)
? p.c_channelParticipantAdmin().is_can_edit() ? p.c_channelParticipantAdmin().is_can_edit()
@ -1542,27 +1545,32 @@ void ApiWrap::applyLastParticipantsList(
const auto restrictedRights = (p.type() == mtpc_channelParticipantBanned) const auto restrictedRights = (p.type() == mtpc_channelParticipantBanned)
? p.c_channelParticipantBanned().vbanned_rights() ? p.c_channelParticipantBanned().vbanned_rights()
: emptyRestrictedRights; : emptyRestrictedRights;
if (!userId) { if (!participantId) {
continue; continue;
} }
auto user = _session->data().user(userId); const auto participant = _session->data().peer(participantId);
const auto user = participant->asUser();
if (p.type() == mtpc_channelParticipantCreator) { if (p.type() == mtpc_channelParticipantCreator) {
Assert(user != nullptr);
const auto &creator = p.c_channelParticipantCreator(); const auto &creator = p.c_channelParticipantCreator();
const auto rank = qs(creator.vrank().value_or_empty()); const auto rank = qs(creator.vrank().value_or_empty());
channel->mgInfo->creator = user; channel->mgInfo->creator = user;
channel->mgInfo->creatorRank = rank; channel->mgInfo->creatorRank = rank;
if (!channel->mgInfo->admins.empty()) { if (!channel->mgInfo->admins.empty()) {
Data::ChannelAdminChanges(channel).add(userId, rank); Data::ChannelAdminChanges(channel).add(
peerToUser(participantId),
rank);
} }
} }
if (!base::contains(channel->mgInfo->lastParticipants, user)) { if (user
&& !base::contains(channel->mgInfo->lastParticipants, user)) {
channel->mgInfo->lastParticipants.push_back(user); channel->mgInfo->lastParticipants.push_back(user);
if (adminRights.c_chatAdminRights().vflags().v) { if (adminRights.c_chatAdminRights().vflags().v) {
channel->mgInfo->lastAdmins.emplace( channel->mgInfo->lastAdmins.emplace(
user, user,
MegagroupInfo::Admin{ adminRights, adminCanEdit }); MegagroupInfo::Admin{ adminRights, adminCanEdit });
} else if (restrictedRights.c_chatBannedRights().vflags().v != 0) { } else if (Data::ChatBannedRightsFlags(restrictedRights) != 0) {
channel->mgInfo->lastRestricted.emplace( channel->mgInfo->lastRestricted.emplace(
user, user,
MegagroupInfo::Restricted{ restrictedRights }); MegagroupInfo::Restricted{ restrictedRights });
@ -1607,22 +1615,27 @@ void ApiWrap::applyBotsList(
auto botStatus = channel->mgInfo->botStatus; auto botStatus = channel->mgInfo->botStatus;
auto keyboardBotFound = !history || !history->lastKeyboardFrom; auto keyboardBotFound = !history || !history->lastKeyboardFrom;
for (const auto &p : list) { for (const auto &p : list) {
const auto userId = p.match([](const auto &data) { const auto participantId = p.match([](
return data.vuser_id().v; const MTPDchannelParticipantBanned &data) {
return peerFromMTP(data.vpeer());
}, [](const auto &data) {
return peerFromUser(data.vuser_id());
}); });
if (!userId) { if (!participantId) {
continue; continue;
} }
auto user = _session->data().user(userId); const auto participant = _session->data().peer(participantId);
if (user->isBot()) { const auto user = participant->asUser();
if (user && user->isBot()) {
channel->mgInfo->bots.insert(user); channel->mgInfo->bots.insert(user);
botStatus = 2;// (botStatus > 0/* || !i.key()->botInfo->readsAllHistory*/) ? 2 : 1; botStatus = 2;// (botStatus > 0/* || !i.key()->botInfo->readsAllHistory*/) ? 2 : 1;
if (!user->botInfo->inited) { if (!user->botInfo->inited) {
needBotsInfos = true; needBotsInfos = true;
} }
} }
if (!keyboardBotFound && user->id == history->lastKeyboardFrom) { if (!keyboardBotFound
&& participant->id == history->lastKeyboardFrom) {
keyboardBotFound = true; keyboardBotFound = true;
} }
} }
@ -1657,7 +1670,7 @@ void ApiWrap::requestSelfParticipant(not_null<ChannelData*> channel) {
_selfParticipantRequests.emplace(channel); _selfParticipantRequests.emplace(channel);
request(MTPchannels_GetParticipant( request(MTPchannels_GetParticipant(
channel->inputChannel, channel->inputChannel,
MTP_inputUserSelf() MTP_inputPeerSelf()
)).done([=](const MTPchannels_ChannelParticipant &result) { )).done([=](const MTPchannels_ChannelParticipant &result) {
_selfParticipantRequests.erase(channel); _selfParticipantRequests.erase(channel);
result.match([&](const MTPDchannels_channelParticipant &data) { result.match([&](const MTPDchannels_channelParticipant &data) {
@ -1698,11 +1711,13 @@ void ApiWrap::requestSelfParticipant(not_null<ChannelData*> channel) {
void ApiWrap::kickParticipant( void ApiWrap::kickParticipant(
not_null<ChatData*> chat, not_null<ChatData*> chat,
not_null<UserData*> user) { not_null<PeerData*> participant) {
Expects(participant->isUser());
request(MTPmessages_DeleteChatUser( request(MTPmessages_DeleteChatUser(
MTP_flags(0), MTP_flags(0),
chat->inputChat, chat->inputChat,
user->inputUser participant->asUser()->inputUser
)).done([=](const MTPUpdates &result) { )).done([=](const MTPUpdates &result) {
applyUpdates(result); applyUpdates(result);
}).send(); }).send();
@ -1710,21 +1725,21 @@ void ApiWrap::kickParticipant(
void ApiWrap::kickParticipant( void ApiWrap::kickParticipant(
not_null<ChannelData*> channel, not_null<ChannelData*> channel,
not_null<UserData*> user, not_null<PeerData*> participant,
const MTPChatBannedRights &currentRights) { const MTPChatBannedRights &currentRights) {
const auto kick = KickRequest(channel, user); const auto kick = KickRequest(channel, participant);
if (_kickRequests.contains(kick)) return; if (_kickRequests.contains(kick)) return;
const auto rights = ChannelData::KickedRestrictedRights(); const auto rights = ChannelData::KickedRestrictedRights();
const auto requestId = request(MTPchannels_EditBanned( const auto requestId = request(MTPchannels_EditBanned(
channel->inputChannel, channel->inputChannel,
user->inputUser, participant->input,
rights rights
)).done([=](const MTPUpdates &result) { )).done([=](const MTPUpdates &result) {
applyUpdates(result); applyUpdates(result);
_kickRequests.remove(KickRequest(channel, user)); _kickRequests.remove(KickRequest(channel, participant));
channel->applyEditBanned(user, currentRights, rights); channel->applyEditBanned(participant, currentRights, rights);
}).fail([this, kick](const MTP::Error &error) { }).fail([this, kick](const MTP::Error &error) {
_kickRequests.remove(kick); _kickRequests.remove(kick);
}).send(); }).send();
@ -1734,20 +1749,20 @@ void ApiWrap::kickParticipant(
void ApiWrap::unblockParticipant( void ApiWrap::unblockParticipant(
not_null<ChannelData*> channel, not_null<ChannelData*> channel,
not_null<UserData*> user) { not_null<PeerData*> participant) {
const auto kick = KickRequest(channel, user); const auto kick = KickRequest(channel, participant);
if (_kickRequests.contains(kick)) { if (_kickRequests.contains(kick)) {
return; return;
} }
const auto requestId = request(MTPchannels_EditBanned( const auto requestId = request(MTPchannels_EditBanned(
channel->inputChannel, channel->inputChannel,
user->inputUser, participant->input,
MTP_chatBannedRights(MTP_flags(0), MTP_int(0)) MTP_chatBannedRights(MTP_flags(0), MTP_int(0))
)).done([=](const MTPUpdates &result) { )).done([=](const MTPUpdates &result) {
applyUpdates(result); applyUpdates(result);
_kickRequests.remove(KickRequest(channel, user)); _kickRequests.remove(KickRequest(channel, participant));
if (channel->kickedCount() > 0) { if (channel->kickedCount() > 0) {
channel->setKickedCount(channel->kickedCount() - 1); channel->setKickedCount(channel->kickedCount() - 1);
} else { } else {
@ -3183,12 +3198,18 @@ void ApiWrap::refreshChannelAdmins(
const QVector<MTPChannelParticipant> &participants) { const QVector<MTPChannelParticipant> &participants) {
Data::ChannelAdminChanges changes(channel); Data::ChannelAdminChanges changes(channel);
for (const auto &p : participants) { for (const auto &p : participants) {
const auto userId = p.match([](const auto &data) { const auto participantId = p.match([](
return data.vuser_id().v; const MTPDchannelParticipantBanned &data) {
return peerFromMTP(data.vpeer());
}, [](const auto &data) {
return peerFromUser(data.vuser_id());
}); });
const auto userId = peerToUser(participantId);
p.match([&](const MTPDchannelParticipantAdmin &data) { p.match([&](const MTPDchannelParticipantAdmin &data) {
Assert(peerIsUser(participantId));
changes.add(userId, qs(data.vrank().value_or_empty())); changes.add(userId, qs(data.vrank().value_or_empty()));
}, [&](const MTPDchannelParticipantCreator &data) { }, [&](const MTPDchannelParticipantCreator &data) {
Assert(peerIsUser(participantId));
const auto rank = qs(data.vrank().value_or_empty()); const auto rank = qs(data.vrank().value_or_empty());
if (const auto info = channel->mgInfo.get()) { if (const auto info = channel->mgInfo.get()) {
info->creator = channel->owner().userLoaded(userId); info->creator = channel->owner().userLoaded(userId);
@ -3196,7 +3217,9 @@ void ApiWrap::refreshChannelAdmins(
} }
changes.add(userId, rank); changes.add(userId, rank);
}, [&](const auto &data) { }, [&](const auto &data) {
changes.remove(userId); if (userId) {
changes.remove(userId);
}
}); });
} }
} }

View file

@ -249,14 +249,16 @@ public:
void markMediaRead(not_null<HistoryItem*> item); void markMediaRead(not_null<HistoryItem*> item);
void requestSelfParticipant(not_null<ChannelData*> channel); void requestSelfParticipant(not_null<ChannelData*> channel);
void kickParticipant(not_null<ChatData*> chat, not_null<UserData*> user); void kickParticipant(
not_null<ChatData*> chat,
not_null<PeerData*> participant);
void kickParticipant( void kickParticipant(
not_null<ChannelData*> channel, not_null<ChannelData*> channel,
not_null<UserData*> user, not_null<PeerData*> participant,
const MTPChatBannedRights &currentRights); const MTPChatBannedRights &currentRights);
void unblockParticipant( void unblockParticipant(
not_null<ChannelData*> channel, not_null<ChannelData*> channel,
not_null<UserData*> user); not_null<PeerData*> participant);
void deleteAllFromUser( void deleteAllFromUser(
not_null<ChannelData*> channel, not_null<ChannelData*> channel,
not_null<UserData*> from); not_null<UserData*> from);
@ -657,7 +659,7 @@ private:
using KickRequest = std::pair< using KickRequest = std::pair<
not_null<ChannelData*>, not_null<ChannelData*>,
not_null<UserData*>>; not_null<PeerData*>>;
base::flat_map<KickRequest, mtpRequestId> _kickRequests; base::flat_map<KickRequest, mtpRequestId> _kickRequests;
base::flat_set<not_null<ChannelData*>> _selfParticipantRequests; base::flat_set<not_null<ChannelData*>> _selfParticipantRequests;

View file

@ -467,8 +467,9 @@ void AddSpecialBoxController::loadMoreRows() {
int availableCount, int availableCount,
const QVector<MTPChannelParticipant> &list) { const QVector<MTPChannelParticipant> &list) {
for (const auto &data : list) { for (const auto &data : list) {
if (const auto user = _additional.applyParticipant(data)) { if (const auto participant = _additional.applyParticipant(
appendRow(user); data)) {
appendRow(participant);
} }
} }
if (const auto size = list.size()) { if (const auto size = list.size()) {
@ -502,9 +503,9 @@ void AddSpecialBoxController::rowClicked(not_null<PeerListRow*> row) {
template <typename Callback> template <typename Callback>
bool AddSpecialBoxController::checkInfoLoaded( bool AddSpecialBoxController::checkInfoLoaded(
not_null<UserData*> user, not_null<PeerData*> participant,
Callback callback) { Callback callback) {
if (_additional.infoLoaded(user)) { if (_additional.infoLoaded(participant)) {
return true; return true;
} }
@ -512,16 +513,15 @@ bool AddSpecialBoxController::checkInfoLoaded(
const auto channel = _peer->asChannel(); const auto channel = _peer->asChannel();
_api.request(MTPchannels_GetParticipant( _api.request(MTPchannels_GetParticipant(
channel->inputChannel, channel->inputChannel,
user->inputUser participant->input
)).done([=](const MTPchannels_ChannelParticipant &result) { )).done([=](const MTPchannels_ChannelParticipant &result) {
Expects(result.type() == mtpc_channels_channelParticipant); result.match([&](const MTPDchannels_channelParticipant &data) {
channel->owner().processUsers(data.vusers());
const auto &participant = result.c_channels_channelParticipant(); _additional.applyParticipant(data.vparticipant());
channel->owner().processUsers(participant.vusers()); });
_additional.applyParticipant(participant.vparticipant());
callback(); callback();
}).fail([=](const MTP::Error &error) { }).fail([=](const MTP::Error &error) {
_additional.setExternal(user); _additional.setExternal(participant);
callback(); callback();
}).send(); }).send();
return false; return false;
@ -732,7 +732,7 @@ void AddSpecialBoxController::showRestricted(
user, user,
_additional.adminRights(user).has_value(), _additional.adminRights(user).has_value(),
currentRights); currentRights);
if (_additional.canRestrictUser(user)) { if (_additional.canRestrictParticipant(user)) {
const auto done = crl::guard(this, [=]( const auto done = crl::guard(this, [=](
const MTPChatBannedRights &newRights) { const MTPChatBannedRights &newRights) {
editRestrictedDone(user, newRights); editRestrictedDone(user, newRights);
@ -749,50 +749,61 @@ void AddSpecialBoxController::showRestricted(
} }
void AddSpecialBoxController::editRestrictedDone( void AddSpecialBoxController::editRestrictedDone(
not_null<UserData*> user, not_null<PeerData*> participant,
const MTPChatBannedRights &rights) { const MTPChatBannedRights &rights) {
if (_editParticipantBox) { if (_editParticipantBox) {
_editParticipantBox->closeBox(); _editParticipantBox->closeBox();
} }
const auto date = base::unixtime::now(); // Incorrect, but ignored. const auto date = base::unixtime::now(); // Incorrect, but ignored.
if (rights.c_chatBannedRights().vflags().v == 0) { if (Data::ChatBannedRightsFlags(rights) == 0) {
_additional.applyParticipant(MTP_channelParticipant( if (const auto user = participant->asUser()) {
MTP_int(user->bareId()), _additional.applyParticipant(MTP_channelParticipant(
MTP_int(date))); MTP_int(user->bareId()),
MTP_int(date)));
} else {
_additional.setExternal(participant);
}
} else { } else {
const auto kicked = rights.c_chatBannedRights().is_view_messages(); const auto kicked = Data::ChatBannedRightsFlags(rights)
const auto alreadyRestrictedBy = _additional.restrictedBy(user); & ChatRestriction::f_view_messages;
const auto alreadyRestrictedBy = _additional.restrictedBy(
participant);
_additional.applyParticipant(MTP_channelParticipantBanned( _additional.applyParticipant(MTP_channelParticipantBanned(
MTP_flags(kicked MTP_flags(kicked
? MTPDchannelParticipantBanned::Flag::f_left ? MTPDchannelParticipantBanned::Flag::f_left
: MTPDchannelParticipantBanned::Flag(0)), : MTPDchannelParticipantBanned::Flag(0)),
MTP_int(user->bareId()), (participant->isUser()
? MTP_peerUser(MTP_int(participant->bareId()))
: participant->isChat()
? MTP_peerChat(MTP_int(participant->bareId()))
: MTP_peerChannel(MTP_int(participant->bareId()))),
MTP_int(alreadyRestrictedBy MTP_int(alreadyRestrictedBy
? alreadyRestrictedBy->bareId() ? alreadyRestrictedBy->bareId()
: user->session().userId()), : participant->session().userId()),
MTP_int(date), MTP_int(date),
rights)); rights));
} }
if (const auto callback = _bannedDoneCallback) { if (const auto callback = _bannedDoneCallback) {
callback(user, rights); callback(participant, rights);
} }
} }
void AddSpecialBoxController::kickUser( void AddSpecialBoxController::kickUser(
not_null<UserData*> user, not_null<PeerData*> participant,
bool sure) { bool sure) {
if (!checkInfoLoaded(user, [=] { kickUser(user); })) { if (!checkInfoLoaded(participant, [=] { kickUser(participant); })) {
return; return;
} }
const auto kickUserSure = crl::guard(this, [=] { const auto kickUserSure = crl::guard(this, [=] {
kickUser(user, true); kickUser(participant, true);
}); });
// Check restrictions. // Check restrictions.
if (_additional.adminRights(user).has_value() const auto user = participant->asUser();
|| _additional.isCreator(user)) { if (user && (_additional.adminRights(user).has_value()
|| (_additional.isCreator(user)))) {
// The user is an admin or creator. // The user is an admin or creator.
if (!_additional.isCreator(user) && _additional.canEditAdmin(user)) { if (!_additional.isCreator(user) && _additional.canEditAdmin(user)) {
if (!sure) { if (!sure) {
@ -818,14 +829,14 @@ void AddSpecialBoxController::kickUser(
: tr::lng_profile_sure_kick_channel)( : tr::lng_profile_sure_kick_channel)(
tr::now, tr::now,
lt_user, lt_user,
user->name); participant->name);
_editBox = Ui::show( _editBox = Ui::show(
Box<ConfirmBox>(text, kickUserSure), Box<ConfirmBox>(text, kickUserSure),
Ui::LayerOption::KeepOther); Ui::LayerOption::KeepOther);
return; return;
} }
const auto restrictedRights = _additional.restrictedRights(user); const auto restrictedRights = _additional.restrictedRights(participant);
const auto currentRights = restrictedRights const auto currentRights = restrictedRights
? *restrictedRights ? *restrictedRights
: MTPChatBannedRights(MTP_chatBannedRights( : MTPChatBannedRights(MTP_chatBannedRights(
@ -834,21 +845,25 @@ void AddSpecialBoxController::kickUser(
const auto done = crl::guard(this, [=]( const auto done = crl::guard(this, [=](
const MTPChatBannedRights &newRights) { const MTPChatBannedRights &newRights) {
editRestrictedDone(user, newRights); editRestrictedDone(participant, newRights);
}); });
const auto fail = crl::guard(this, [=] { const auto fail = crl::guard(this, [=] {
_editBox = nullptr; _editBox = nullptr;
}); });
const auto callback = SaveRestrictedCallback(_peer, user, done, fail); const auto callback = SaveRestrictedCallback(
_peer,
participant,
done,
fail);
callback(currentRights, ChannelData::KickedRestrictedRights()); callback(currentRights, ChannelData::KickedRestrictedRights());
} }
bool AddSpecialBoxController::appendRow(not_null<UserData*> user) { bool AddSpecialBoxController::appendRow(not_null<PeerData*> participant) {
if (delegate()->peerListFindRow(user->id) if (delegate()->peerListFindRow(participant->id)
|| (_excludeSelf && user->isSelf())) { || (_excludeSelf && participant->isSelf())) {
return false; return false;
} }
delegate()->peerListAppendRow(createRow(user)); delegate()->peerListAppendRow(createRow(participant));
return true; return true;
} }
@ -861,8 +876,8 @@ bool AddSpecialBoxController::prependRow(not_null<UserData*> user) {
} }
std::unique_ptr<PeerListRow> AddSpecialBoxController::createRow( std::unique_ptr<PeerListRow> AddSpecialBoxController::createRow(
not_null<UserData*> user) const { not_null<PeerData*> participant) const {
return std::make_unique<PeerListRow>(user); return std::make_unique<PeerListRow>(participant);
} }
AddSpecialBoxSearchController::AddSpecialBoxSearchController( AddSpecialBoxSearchController::AddSpecialBoxSearchController(

View file

@ -80,7 +80,7 @@ public:
const MTPChatAdminRights &adminRights, const MTPChatAdminRights &adminRights,
const QString &rank)>; const QString &rank)>;
using BannedDoneCallback = Fn<void( using BannedDoneCallback = Fn<void(
not_null<UserData*> user, not_null<PeerData*> participant,
const MTPChatBannedRights &bannedRights)>; const MTPChatBannedRights &bannedRights)>;
AddSpecialBoxController( AddSpecialBoxController(
not_null<PeerData*> peer, not_null<PeerData*> peer,
@ -101,7 +101,7 @@ public:
private: private:
template <typename Callback> template <typename Callback>
bool checkInfoLoaded(not_null<UserData*> user, Callback callback); bool checkInfoLoaded(not_null<PeerData*> participant, Callback callback);
void prepareChatRows(not_null<ChatData*> chat); void prepareChatRows(not_null<ChatData*> chat);
void rebuildChatRows(not_null<ChatData*> chat); void rebuildChatRows(not_null<ChatData*> chat);
@ -113,12 +113,13 @@ private:
const QString &rank); const QString &rank);
void showRestricted(not_null<UserData*> user, bool sure = false); void showRestricted(not_null<UserData*> user, bool sure = false);
void editRestrictedDone( void editRestrictedDone(
not_null<UserData*> user, not_null<PeerData*> participant,
const MTPChatBannedRights &rights); const MTPChatBannedRights &rights);
void kickUser(not_null<UserData*> user, bool sure = false); void kickUser(not_null<PeerData*> participant, bool sure = false);
bool appendRow(not_null<UserData*> user); bool appendRow(not_null<PeerData*> participant);
bool prependRow(not_null<UserData*> user); bool prependRow(not_null<UserData*> user);
std::unique_ptr<PeerListRow> createRow(not_null<UserData*> user) const; std::unique_ptr<PeerListRow> createRow(
not_null<PeerData*> participant) const;
void subscribeToMigration(); void subscribeToMigration();
void migrate(not_null<ChatData*> chat, not_null<ChannelData*> channel); void migrate(not_null<ChatData*> chat, not_null<ChannelData*> channel);

View file

@ -612,11 +612,11 @@ void EditRestrictedBox::prepare() {
const auto defaultRestrictions = chat const auto defaultRestrictions = chat
? chat->defaultRestrictions() ? chat->defaultRestrictions()
: channel->defaultRestrictions(); : channel->defaultRestrictions();
const auto prepareRights = _oldRights.c_chatBannedRights().vflags().v const auto prepareRights = Data::ChatBannedRightsFlags(_oldRights)
? _oldRights ? _oldRights
: defaultRights(); : defaultRights();
const auto prepareFlags = FixDependentRestrictions( const auto prepareFlags = FixDependentRestrictions(
prepareRights.c_chatBannedRights().vflags().v Data::ChatBannedRightsFlags(prepareRights)
| defaultRestrictions | defaultRestrictions
| ((channel && channel->isPublic()) | ((channel && channel->isPublic())
? (Flag::f_change_info | Flag::f_pin_messages) ? (Flag::f_change_info | Flag::f_pin_messages)
@ -647,7 +647,7 @@ void EditRestrictedBox::prepare() {
disabledMessages); disabledMessages);
addControl(std::move(checkboxes), QMargins()); addControl(std::move(checkboxes), QMargins());
_until = prepareRights.c_chatBannedRights().vuntil_date().v; _until = Data::ChatBannedRightsUntilDate(prepareRights);
addControl(object_ptr<Ui::BoxContentDivider>(this), st::rightsUntilMargin); addControl(object_ptr<Ui::BoxContentDivider>(this), st::rightsUntilMargin);
addControl( addControl(
object_ptr<Ui::FlatLabel>( object_ptr<Ui::FlatLabel>(
@ -767,7 +767,7 @@ void EditRestrictedBox::createUntilVariants() {
} }
}; };
auto addCurrentVariant = [&](TimeId from, TimeId to) { auto addCurrentVariant = [&](TimeId from, TimeId to) {
auto oldUntil = _oldRights.c_chatBannedRights().vuntil_date().v; auto oldUntil = Data::ChatBannedRightsUntilDate(_oldRights);
if (oldUntil < _until) { if (oldUntil < _until) {
addCustomVariant(oldUntil, from, to); addCustomVariant(oldUntil, from, to);
} }

View file

@ -146,18 +146,18 @@ void SaveChannelAdmin(
void SaveChannelRestriction( void SaveChannelRestriction(
not_null<ChannelData*> channel, not_null<ChannelData*> channel,
not_null<UserData*> user, not_null<PeerData*> participant,
const MTPChatBannedRights &oldRights, const MTPChatBannedRights &oldRights,
const MTPChatBannedRights &newRights, const MTPChatBannedRights &newRights,
Fn<void()> onDone, Fn<void()> onDone,
Fn<void()> onFail) { Fn<void()> onFail) {
channel->session().api().request(MTPchannels_EditBanned( channel->session().api().request(MTPchannels_EditBanned(
channel->inputChannel, channel->inputChannel,
user->inputUser, participant->input,
newRights newRights
)).done([=](const MTPUpdates &result) { )).done([=](const MTPUpdates &result) {
channel->session().api().applyUpdates(result); channel->session().api().applyUpdates(result);
channel->applyEditBanned(user, oldRights, newRights); channel->applyEditBanned(participant, oldRights, newRights);
if (onDone) { if (onDone) {
onDone(); onDone();
} }
@ -243,7 +243,7 @@ Fn<void(
const MTPChatBannedRights &oldRights, const MTPChatBannedRights &oldRights,
const MTPChatBannedRights &newRights)> SaveRestrictedCallback( const MTPChatBannedRights &newRights)> SaveRestrictedCallback(
not_null<PeerData*> peer, not_null<PeerData*> peer,
not_null<UserData*> user, not_null<PeerData*> participant,
Fn<void(const MTPChatBannedRights &newRights)> onDone, Fn<void(const MTPChatBannedRights &newRights)> onDone,
Fn<void()> onFail) { Fn<void()> onFail) {
return [=]( return [=](
@ -253,19 +253,21 @@ Fn<void(
const auto saveForChannel = [=](not_null<ChannelData*> channel) { const auto saveForChannel = [=](not_null<ChannelData*> channel) {
SaveChannelRestriction( SaveChannelRestriction(
channel, channel,
user, participant,
oldRights, oldRights,
newRights, newRights,
done, done,
onFail); onFail);
}; };
if (const auto chat = peer->asChatNotMigrated()) { if (const auto chat = peer->asChatNotMigrated()) {
const auto flags = newRights.match([]( const auto flags = Data::ChatBannedRightsFlags(newRights);
const MTPDchatBannedRights &data) { if (participant->isUser()
return data.vflags().v; && (flags & MTPDchatBannedRights::Flag::f_view_messages)) {
}); SaveChatParticipantKick(
if (flags & MTPDchatBannedRights::Flag::f_view_messages) { chat,
SaveChatParticipantKick(chat, user, done, onFail); participant->asUser(),
done,
onFail);
} else if (!flags) { } else if (!flags) {
done(); done();
} else { } else {
@ -313,9 +315,9 @@ ParticipantsAdditionalData::ParticipantsAdditionalData(
} }
bool ParticipantsAdditionalData::infoLoaded( bool ParticipantsAdditionalData::infoLoaded(
not_null<UserData*> user) const { not_null<PeerData*> participant) const {
return _peer->isChat() return _peer->isChat()
|| (_infoNotLoaded.find(user) == end(_infoNotLoaded)); || (_infoNotLoaded.find(participant) == end(_infoNotLoaded));
} }
bool ParticipantsAdditionalData::canEditAdmin( bool ParticipantsAdditionalData::canEditAdmin(
@ -342,9 +344,10 @@ bool ParticipantsAdditionalData::canAddOrEditAdmin(
Unexpected("Peer in ParticipantsAdditionalData::canAddOrEditAdmin."); Unexpected("Peer in ParticipantsAdditionalData::canAddOrEditAdmin.");
} }
bool ParticipantsAdditionalData::canRestrictUser( bool ParticipantsAdditionalData::canRestrictParticipant(
not_null<UserData*> user) const { not_null<PeerData*> participant) const {
if (!canEditAdmin(user) || user->isSelf()) { const auto user = participant->asUser();
if (user && (!canEditAdmin(user) || user->isSelf())) {
return false; return false;
} else if (const auto chat = _peer->asChat()) { } else if (const auto chat = _peer->asChat()) {
return chat->canBanMembers(); return chat->canBanMembers();
@ -354,12 +357,14 @@ bool ParticipantsAdditionalData::canRestrictUser(
Unexpected("Peer in ParticipantsAdditionalData::canRestrictUser."); Unexpected("Peer in ParticipantsAdditionalData::canRestrictUser.");
} }
bool ParticipantsAdditionalData::canRemoveUser( bool ParticipantsAdditionalData::canRemoveParticipant(
not_null<UserData*> user) const { not_null<PeerData*> participant) const {
if (canRestrictUser(user)) { const auto user = participant->asUser();
if (canRestrictParticipant(participant)) {
return true; return true;
} else if (const auto chat = _peer->asChat()) { } else if (const auto chat = _peer->asChat()) {
return !user->isSelf() return user
&& !user->isSelf()
&& chat->invitedByMe.contains(user) && chat->invitedByMe.contains(user)
&& (chat->amCreator() || !_admins.contains(user)); && (chat->amCreator() || !_admins.contains(user));
} }
@ -388,12 +393,12 @@ QString ParticipantsAdditionalData::adminRank(
} }
auto ParticipantsAdditionalData::restrictedRights( auto ParticipantsAdditionalData::restrictedRights(
not_null<UserData*> user) const not_null<PeerData*> participant) const
-> std::optional<MTPChatBannedRights> { -> std::optional<MTPChatBannedRights> {
if (_peer->isChat()) { if (_peer->isChat()) {
return std::nullopt; return std::nullopt;
} }
const auto i = _restrictedRights.find(user); const auto i = _restrictedRights.find(participant);
return (i != end(_restrictedRights)) return (i != end(_restrictedRights))
? std::make_optional(i->second) ? std::make_optional(i->second)
: std::nullopt; : std::nullopt;
@ -404,16 +409,18 @@ bool ParticipantsAdditionalData::isCreator(not_null<UserData*> user) const {
} }
bool ParticipantsAdditionalData::isExternal( bool ParticipantsAdditionalData::isExternal(
not_null<UserData*> user) const { not_null<PeerData*> participant) const {
return _peer->isChat() return _peer->isChat()
? !_members.contains(user) ? (participant->isUser()
: _external.find(user) != end(_external); && !_members.contains(participant->asUser()))
: _external.find(participant) != end(_external);
} }
bool ParticipantsAdditionalData::isKicked(not_null<UserData*> user) const { bool ParticipantsAdditionalData::isKicked(
not_null<PeerData*> participant) const {
return _peer->isChat() return _peer->isChat()
? false ? false
: _kicked.find(user) != end(_kicked); : _kicked.find(participant) != end(_kicked);
} }
UserData *ParticipantsAdditionalData::adminPromotedBy( UserData *ParticipantsAdditionalData::adminPromotedBy(
@ -426,29 +433,41 @@ UserData *ParticipantsAdditionalData::adminPromotedBy(
} }
UserData *ParticipantsAdditionalData::restrictedBy( UserData *ParticipantsAdditionalData::restrictedBy(
not_null<UserData*> user) const { not_null<PeerData*> participant) const {
if (_peer->isChat()) { if (_peer->isChat()) {
return nullptr; return nullptr;
} }
const auto i = _restrictedBy.find(user); const auto i = _restrictedBy.find(participant);
return (i != end(_restrictedBy)) ? i->second.get() : nullptr; return (i != end(_restrictedBy)) ? i->second.get() : nullptr;
} }
void ParticipantsAdditionalData::setExternal(not_null<UserData*> user) { void ParticipantsAdditionalData::setExternal(
_infoNotLoaded.erase(user); not_null<PeerData*> participant) {
_external.emplace(user); if (const auto user = participant->asUser()) {
_adminRights.erase(user);
_adminCanEdit.erase(user);
_adminPromotedBy.erase(user);
_admins.erase(user);
}
_restrictedRights.erase(participant);
_kicked.erase(participant);
_restrictedBy.erase(participant);
_infoNotLoaded.erase(participant);
_external.emplace(participant);
} }
void ParticipantsAdditionalData::checkForLoaded(not_null<UserData*> user) { void ParticipantsAdditionalData::checkForLoaded(
not_null<PeerData*> participant) {
const auto contains = [](const auto &map, const auto &value) { const auto contains = [](const auto &map, const auto &value) {
return map.find(value) != map.end(); return map.find(value) != map.end();
}; };
if (_creator != user const auto user = participant->asUser();
&& !contains(_adminRights, user) if (!(user && _creator == user)
&& !contains(_restrictedRights, user) && !(user && contains(_adminRights, user))
&& !contains(_external, user) && !contains(_restrictedRights, participant)
&& !contains(_kicked, user)) { && !contains(_external, participant)
_infoNotLoaded.emplace(user); && !contains(_kicked, participant)) {
_infoNotLoaded.emplace(participant);
} }
} }
@ -510,15 +529,15 @@ void ParticipantsAdditionalData::fillFromChannel(
} }
} }
UserData *ParticipantsAdditionalData::applyParticipant( PeerData *ParticipantsAdditionalData::applyParticipant(
const MTPChannelParticipant &data) { const MTPChannelParticipant &data) {
return applyParticipant(data, _role); return applyParticipant(data, _role);
} }
UserData *ParticipantsAdditionalData::applyParticipant( PeerData *ParticipantsAdditionalData::applyParticipant(
const MTPChannelParticipant &data, const MTPChannelParticipant &data,
Role overrideRole) { Role overrideRole) {
const auto logBad = [&]() -> UserData* { const auto logBad = [&]() -> PeerData* {
LOG(("API Error: Bad participant type %1 got " LOG(("API Error: Bad participant type %1 got "
"while requesting for participants, role: %2" "while requesting for participants, role: %2"
).arg(data.type() ).arg(data.type()
@ -526,27 +545,28 @@ UserData *ParticipantsAdditionalData::applyParticipant(
return nullptr; return nullptr;
}; };
return data.match([&](const MTPDchannelParticipantCreator &data) { return data.match([&](
const MTPDchannelParticipantCreator &data) -> PeerData* {
if (overrideRole != Role::Profile if (overrideRole != Role::Profile
&& overrideRole != Role::Members && overrideRole != Role::Members
&& overrideRole != Role::Admins) { && overrideRole != Role::Admins) {
return logBad(); return logBad();
} }
return applyCreator(data); return applyCreator(data);
}, [&](const MTPDchannelParticipantAdmin &data) { }, [&](const MTPDchannelParticipantAdmin &data) -> PeerData* {
if (overrideRole != Role::Profile if (overrideRole != Role::Profile
&& overrideRole != Role::Members && overrideRole != Role::Members
&& overrideRole != Role::Admins) { && overrideRole != Role::Admins) {
return logBad(); return logBad();
} }
return applyAdmin(data); return applyAdmin(data);
}, [&](const MTPDchannelParticipantSelf &data) { }, [&](const MTPDchannelParticipantSelf &data) -> PeerData* {
if (overrideRole != Role::Profile if (overrideRole != Role::Profile
&& overrideRole != Role::Members) { && overrideRole != Role::Members) {
return logBad(); return logBad();
} }
return applyRegular(data.vuser_id()); return applyRegular(data.vuser_id());
}, [&](const MTPDchannelParticipant &data) { }, [&](const MTPDchannelParticipant &data) -> PeerData* {
if (overrideRole != Role::Profile if (overrideRole != Role::Profile
&& overrideRole != Role::Members) { && overrideRole != Role::Members) {
return logBad(); return logBad();
@ -645,32 +665,35 @@ UserData *ParticipantsAdditionalData::applyRegular(MTPint userId) {
return user; return user;
} }
UserData *ParticipantsAdditionalData::applyBanned( PeerData *ParticipantsAdditionalData::applyBanned(
const MTPDchannelParticipantBanned &data) { const MTPDchannelParticipantBanned &data) {
const auto user = _peer->owner().userLoaded(data.vuser_id().v); const auto participant = _peer->owner().peerLoaded(
if (!user) { peerFromMTP(data.vpeer()));
if (!participant) {
return nullptr; return nullptr;
} }
_infoNotLoaded.erase(user); _infoNotLoaded.erase(participant);
_adminRights.erase(user); if (const auto user = participant->asUser()) {
_adminCanEdit.erase(user); _adminRights.erase(user);
_adminPromotedBy.erase(user); _adminCanEdit.erase(user);
if (data.is_left()) { _adminPromotedBy.erase(user);
_kicked.emplace(user);
} else {
_kicked.erase(user);
} }
_restrictedRights[user] = data.vbanned_rights(); if (data.is_left()) {
_kicked.emplace(participant);
} else {
_kicked.erase(participant);
}
_restrictedRights[participant] = data.vbanned_rights();
if (const auto by = _peer->owner().userLoaded(data.vkicked_by().v)) { if (const auto by = _peer->owner().userLoaded(data.vkicked_by().v)) {
const auto i = _restrictedBy.find(user); const auto i = _restrictedBy.find(participant);
if (i == _restrictedBy.end()) { if (i == _restrictedBy.end()) {
_restrictedBy.emplace(user, by); _restrictedBy.emplace(participant, by);
} else { } else {
i->second = by; i->second = by;
} }
} }
return user; return participant;
} }
void ParticipantsAdditionalData::migrate( void ParticipantsAdditionalData::migrate(
@ -922,9 +945,9 @@ void ParticipantsBoxController::addNewItem() {
editAdminDone(user, rights, rank); editAdminDone(user, rights, rank);
}); });
const auto restrictedDone = crl::guard(this, [=]( const auto restrictedDone = crl::guard(this, [=](
not_null<UserData*> user, not_null<PeerData*> participant,
const MTPChatBannedRights &rights) { const MTPChatBannedRights &rights) {
editRestrictedDone(user, rights); editRestrictedDone(participant, rights);
}); });
const auto initBox = [](not_null<PeerListBox*> box) { const auto initBox = [](not_null<PeerListBox*> box) {
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
@ -1316,8 +1339,9 @@ void ParticipantsBoxController::loadMoreRows() {
int availableCount, int availableCount,
const QVector<MTPChannelParticipant> &list) { const QVector<MTPChannelParticipant> &list) {
for (const auto &data : list) { for (const auto &data : list) {
if (const auto user = _additional.applyParticipant(data)) { if (const auto participant = _additional.applyParticipant(
appendRow(user); data)) {
appendRow(participant);
} }
} }
if (const auto size = list.size()) { if (const auto size = list.size()) {
@ -1398,17 +1422,18 @@ bool ParticipantsBoxController::feedMegagroupLastParticipants() {
} }
void ParticipantsBoxController::rowClicked(not_null<PeerListRow*> row) { void ParticipantsBoxController::rowClicked(not_null<PeerListRow*> row) {
Expects(row->peer()->isUser()); const auto participant = row->peer();
const auto user = participant->asUser();
const auto user = row->peer()->asUser();
if (_role == Role::Admins) { if (_role == Role::Admins) {
Assert(user != nullptr);
showAdmin(user); showAdmin(user);
} else if (_role == Role::Restricted } else if (_role == Role::Restricted
&& (_peer->isChat() || _peer->isMegagroup())) { && (_peer->isChat() || _peer->isMegagroup())
&& user) {
showRestricted(user); showRestricted(user);
} else { } else {
Assert(_navigation != nullptr); Assert(_navigation != nullptr);
_navigation->showPeerInfo(user); _navigation->showPeerInfo(participant);
} }
} }
@ -1433,28 +1458,30 @@ base::unique_qptr<Ui::PopupMenu> ParticipantsBoxController::rowContextMenu(
const auto chat = _peer->asChat(); const auto chat = _peer->asChat();
const auto channel = _peer->asChannel(); const auto channel = _peer->asChannel();
const auto user = row->peer()->asUser(); const auto participant = row->peer();
const auto user = participant->asUser();
auto result = base::make_unique_q<Ui::PopupMenu>(parent); auto result = base::make_unique_q<Ui::PopupMenu>(parent);
if (_navigation) { if (_navigation) {
result->addAction( result->addAction(
tr::lng_context_view_profile(tr::now), tr::lng_context_view_profile(tr::now),
crl::guard(this, [=] { _navigation->showPeerInfo(user); })); crl::guard(this, [=] {
_navigation->showPeerInfo(participant); }));
} }
if (_role == Role::Kicked) { if (_role == Role::Kicked) {
if (_peer->isMegagroup() if (_peer->isMegagroup()
&& _additional.canRestrictUser(user)) { && _additional.canRestrictParticipant(participant)) {
if (channel->canAddMembers()) { if (user && channel->canAddMembers()) {
result->addAction( result->addAction(
tr::lng_context_add_to_group(tr::now), tr::lng_context_add_to_group(tr::now),
crl::guard(this, [=] { unkickMember(user); })); crl::guard(this, [=] { unkickMember(user); }));
} }
result->addAction( result->addAction(
tr::lng_profile_delete_removed(tr::now), tr::lng_profile_delete_removed(tr::now),
crl::guard(this, [=] { removeKickedWithRow(user); })); crl::guard(this, [=] { removeKickedWithRow(participant); }));
} }
return result; return result;
} }
if (_additional.canAddOrEditAdmin(user)) { if (user && _additional.canAddOrEditAdmin(user)) {
const auto isAdmin = _additional.isCreator(user) const auto isAdmin = _additional.isCreator(user)
|| _additional.adminRights(user).has_value(); || _additional.adminRights(user).has_value();
result->addAction( result->addAction(
@ -1463,7 +1490,7 @@ base::unique_qptr<Ui::PopupMenu> ParticipantsBoxController::rowContextMenu(
: tr::lng_context_promote_admin)(tr::now), : tr::lng_context_promote_admin)(tr::now),
crl::guard(this, [=] { showAdmin(user); })); crl::guard(this, [=] { showAdmin(user); }));
} }
if (_additional.canRestrictUser(user)) { if (_additional.canRestrictParticipant(participant)) {
const auto canRestrictWithoutKick = [&] { const auto canRestrictWithoutKick = [&] {
if (const auto chat = _peer->asChat()) { if (const auto chat = _peer->asChat()) {
return chat->amCreator(); return chat->amCreator();
@ -1476,8 +1503,8 @@ base::unique_qptr<Ui::PopupMenu> ParticipantsBoxController::rowContextMenu(
crl::guard(this, [=] { showRestricted(user); })); crl::guard(this, [=] { showRestricted(user); }));
} }
} }
if (_additional.canRemoveUser(user)) { if (_additional.canRemoveParticipant(participant)) {
if (!_additional.isKicked(user)) { if (!_additional.isKicked(participant)) {
const auto isGroup = _peer->isChat() || _peer->isMegagroup(); const auto isGroup = _peer->isChat() || _peer->isMegagroup();
result->addAction( result->addAction(
(isGroup (isGroup
@ -1580,7 +1607,7 @@ void ParticipantsBoxController::showRestricted(not_null<UserData*> user) {
currentRights); currentRights);
const auto chat = _peer->asChat(); const auto chat = _peer->asChat();
const auto channel = _peer->asChannel(); const auto channel = _peer->asChannel();
if (_additional.canRestrictUser(user)) { if (_additional.canRestrictParticipant(user)) {
const auto done = crl::guard(this, [=]( const auto done = crl::guard(this, [=](
const MTPChatBannedRights &newRights) { const MTPChatBannedRights &newRights) {
editRestrictedDone(user, newRights); editRestrictedDone(user, newRights);
@ -1597,29 +1624,40 @@ void ParticipantsBoxController::showRestricted(not_null<UserData*> user) {
} }
void ParticipantsBoxController::editRestrictedDone( void ParticipantsBoxController::editRestrictedDone(
not_null<UserData*> user, not_null<PeerData*> participant,
const MTPChatBannedRights &rights) { const MTPChatBannedRights &rights) {
_addBox = nullptr; _addBox = nullptr;
if (_editParticipantBox) { if (_editParticipantBox) {
_editParticipantBox->closeBox(); _editParticipantBox->closeBox();
} }
const auto user = participant->asUser();
const auto date = base::unixtime::now(); // Incorrect, but ignored. const auto date = base::unixtime::now(); // Incorrect, but ignored.
if (rights.c_chatBannedRights().vflags().v == 0) { if (Data::ChatBannedRightsFlags(rights) == 0) {
_additional.applyParticipant(MTP_channelParticipant( if (user) {
MTP_int(user->bareId()), _additional.applyParticipant(MTP_channelParticipant(
MTP_int(date))); MTP_int(user->bareId()),
MTP_int(date)));
} else {
_additional.setExternal(participant);
}
if (_role == Role::Kicked || _role == Role::Restricted) { if (_role == Role::Kicked || _role == Role::Restricted) {
removeRow(user); removeRow(participant);
} }
} else { } else {
const auto kicked = rights.c_chatBannedRights().is_view_messages(); const auto kicked = Data::ChatBannedRightsFlags(rights)
const auto alreadyRestrictedBy = _additional.restrictedBy(user); & ChatRestriction::f_view_messages;
const auto alreadyRestrictedBy = _additional.restrictedBy(
participant);
_additional.applyParticipant(MTP_channelParticipantBanned( _additional.applyParticipant(MTP_channelParticipantBanned(
MTP_flags(kicked MTP_flags(kicked
? MTPDchannelParticipantBanned::Flag::f_left ? MTPDchannelParticipantBanned::Flag::f_left
: MTPDchannelParticipantBanned::Flag(0)), : MTPDchannelParticipantBanned::Flag(0)),
MTP_int(user->bareId()), (participant->isUser()
? MTP_peerUser(MTP_int(participant->bareId()))
: participant->isChat()
? MTP_peerChat(MTP_int(participant->bareId()))
: MTP_peerChannel(MTP_int(participant->bareId()))),
MTP_int(alreadyRestrictedBy MTP_int(alreadyRestrictedBy
? alreadyRestrictedBy->bareId() ? alreadyRestrictedBy->bareId()
: user->session().userId()), : user->session().userId()),
@ -1647,18 +1685,19 @@ void ParticipantsBoxController::editRestrictedDone(
delegate()->peerListRefreshRows(); delegate()->peerListRefreshRows();
} }
void ParticipantsBoxController::kickMember(not_null<UserData*> user) { void ParticipantsBoxController::kickMember(not_null<PeerData*> participant) {
const auto user = participant->asUser();
const auto text = ((_peer->isChat() || _peer->isMegagroup()) const auto text = ((_peer->isChat() || _peer->isMegagroup())
? tr::lng_profile_sure_kick ? tr::lng_profile_sure_kick
: tr::lng_profile_sure_kick_channel)( : tr::lng_profile_sure_kick_channel)(
tr::now, tr::now,
lt_user, lt_user,
user->firstName); user ? user->firstName : participant->name);
_editBox = Ui::show( _editBox = Ui::show(
Box<ConfirmBox>( Box<ConfirmBox>(
text, text,
tr::lng_box_remove(tr::now), tr::lng_box_remove(tr::now),
crl::guard(this, [=] { kickMemberSure(user); })), crl::guard(this, [=] { kickMemberSure(participant); })),
Ui::LayerOption::KeepOther); Ui::LayerOption::KeepOther);
} }
@ -1671,25 +1710,26 @@ void ParticipantsBoxController::unkickMember(not_null<UserData*> user) {
_peer->session().api().addChatParticipants(_peer, { 1, user }); _peer->session().api().addChatParticipants(_peer, { 1, user });
} }
void ParticipantsBoxController::kickMemberSure(not_null<UserData*> user) { void ParticipantsBoxController::kickMemberSure(
not_null<PeerData*> participant) {
_editBox = nullptr; _editBox = nullptr;
const auto restrictedRights = _additional.restrictedRights(user); const auto restrictedRights = _additional.restrictedRights(participant);
const auto currentRights = restrictedRights const auto currentRights = restrictedRights
? *restrictedRights ? *restrictedRights
: MTPChatBannedRights(MTP_chatBannedRights( : MTPChatBannedRights(MTP_chatBannedRights(
MTP_flags(0), MTP_flags(0),
MTP_int(0))); MTP_int(0)));
if (const auto row = delegate()->peerListFindRow(user->id)) { if (const auto row = delegate()->peerListFindRow(participant->id)) {
delegate()->peerListRemoveRow(row); delegate()->peerListRemoveRow(row);
delegate()->peerListRefreshRows(); delegate()->peerListRefreshRows();
} }
auto &session = _peer->session(); auto &session = _peer->session();
if (const auto chat = _peer->asChat()) { if (const auto chat = _peer->asChat()) {
session.api().kickParticipant(chat, user); session.api().kickParticipant(chat, participant);
} else if (const auto channel = _peer->asChannel()) { } else if (const auto channel = _peer->asChannel()) {
session.api().kickParticipant(channel, user, currentRights); session.api().kickParticipant(channel, participant, currentRights);
} }
} }
@ -1730,36 +1770,37 @@ void ParticipantsBoxController::removeAdminSure(not_null<UserData*> user) {
} }
void ParticipantsBoxController::removeKickedWithRow( void ParticipantsBoxController::removeKickedWithRow(
not_null<UserData*> user) { not_null<PeerData*> participant) {
if (const auto row = delegate()->peerListFindRow(user->id)) { if (const auto row = delegate()->peerListFindRow(participant->id)) {
removeKicked(row, user); removeKicked(row, participant);
} else { } else {
removeKicked(user); removeKicked(participant);
} }
} }
void ParticipantsBoxController::removeKicked(not_null<UserData*> user) { void ParticipantsBoxController::removeKicked(
not_null<PeerData*> participant) {
if (const auto channel = _peer->asChannel()) { if (const auto channel = _peer->asChannel()) {
channel->session().api().unblockParticipant(channel, user); channel->session().api().unblockParticipant(channel, participant);
} }
} }
void ParticipantsBoxController::removeKicked( void ParticipantsBoxController::removeKicked(
not_null<PeerListRow*> row, not_null<PeerListRow*> row,
not_null<UserData*> user) { not_null<PeerData*> participant) {
delegate()->peerListRemoveRow(row); delegate()->peerListRemoveRow(row);
if (_role != Role::Kicked if (_role != Role::Kicked
&& !delegate()->peerListFullRowsCount()) { && !delegate()->peerListFullRowsCount()) {
setDescriptionText(tr::lng_blocked_list_not_found(tr::now)); setDescriptionText(tr::lng_blocked_list_not_found(tr::now));
} }
delegate()->peerListRefreshRows(); delegate()->peerListRefreshRows();
removeKicked(user); removeKicked(participant);
} }
bool ParticipantsBoxController::appendRow(not_null<UserData*> user) { bool ParticipantsBoxController::appendRow(not_null<PeerData*> participant) {
if (delegate()->peerListFindRow(user->id)) { if (delegate()->peerListFindRow(participant->id)) {
recomputeTypeFor(user); recomputeTypeFor(participant);
return false; return false;
} else if (auto row = createRow(user)) { } else if (auto row = createRow(participant)) {
delegate()->peerListAppendRow(std::move(row)); delegate()->peerListAppendRow(std::move(row));
if (_role != Role::Kicked) { if (_role != Role::Kicked) {
setDescriptionText(QString()); setDescriptionText(QString());
@ -1788,8 +1829,8 @@ bool ParticipantsBoxController::prependRow(not_null<UserData*> user) {
return false; return false;
} }
bool ParticipantsBoxController::removeRow(not_null<UserData*> user) { bool ParticipantsBoxController::removeRow(not_null<PeerData*> participant) {
if (auto row = delegate()->peerListFindRow(user->id)) { if (auto row = delegate()->peerListFindRow(participant->id)) {
if (_role == Role::Admins) { if (_role == Role::Admins) {
// Perhaps we are removing an admin from search results. // Perhaps we are removing an admin from search results.
row->setCustomStatus(tr::lng_channel_admin_status_not_admin(tr::now)); row->setCustomStatus(tr::lng_channel_admin_status_not_admin(tr::now));
@ -1807,24 +1848,28 @@ bool ParticipantsBoxController::removeRow(not_null<UserData*> user) {
} }
std::unique_ptr<PeerListRow> ParticipantsBoxController::createRow( std::unique_ptr<PeerListRow> ParticipantsBoxController::createRow(
not_null<UserData*> user) const { not_null<PeerData*> participant) const {
const auto user = participant->asUser();
if (_role == Role::Profile) { if (_role == Role::Profile) {
Assert(user != nullptr);
return std::make_unique<Row>(user, computeType(user)); return std::make_unique<Row>(user, computeType(user));
} }
const auto chat = _peer->asChat(); const auto chat = _peer->asChat();
const auto channel = _peer->asChannel(); const auto channel = _peer->asChannel();
auto row = std::make_unique<PeerListRowWithLink>(user); auto row = std::make_unique<PeerListRowWithLink>(participant);
refreshCustomStatus(row.get()); refreshCustomStatus(row.get());
if (_role == Role::Admins if (_role == Role::Admins
&& user
&& !_additional.isCreator(user) && !_additional.isCreator(user)
&& _additional.adminRights(user).has_value() && _additional.adminRights(user).has_value()
&& _additional.canEditAdmin(user)) { && _additional.canEditAdmin(user)) {
row->setActionLink(tr::lng_profile_kick(tr::now)); row->setActionLink(tr::lng_profile_kick(tr::now));
} else if (_role == Role::Kicked || _role == Role::Restricted) { } else if (_role == Role::Kicked || _role == Role::Restricted) {
if (_additional.canRestrictUser(user)) { if (_additional.canRestrictParticipant(participant)) {
row->setActionLink(tr::lng_profile_delete_removed(tr::now)); row->setActionLink(tr::lng_profile_delete_removed(tr::now));
} }
} else if (_role == Role::Members) { } else if (_role == Role::Members) {
Assert(user != nullptr);
if ((chat ? chat->canBanMembers() : channel->canBanMembers()) if ((chat ? chat->canBanMembers() : channel->canBanMembers())
&& !_additional.isCreator(user) && !_additional.isCreator(user)
&& (!_additional.adminRights(user) && (!_additional.adminRights(user)
@ -1842,31 +1887,34 @@ std::unique_ptr<PeerListRow> ParticipantsBoxController::createRow(
} }
auto ParticipantsBoxController::computeType( auto ParticipantsBoxController::computeType(
not_null<UserData*> user) const -> Type { not_null<PeerData*> participant) const -> Type {
const auto user = participant->asUser();
auto result = Type(); auto result = Type();
result.rights = _additional.isCreator(user) result.rights = (user && _additional.isCreator(user))
? Rights::Creator ? Rights::Creator
: _additional.adminRights(user).has_value() : (user && _additional.adminRights(user).has_value())
? Rights::Admin ? Rights::Admin
: Rights::Normal; : Rights::Normal;
result.canRemove = _additional.canRemoveUser(user); result.canRemove = _additional.canRemoveParticipant(participant);
return result; return result;
} }
void ParticipantsBoxController::recomputeTypeFor( void ParticipantsBoxController::recomputeTypeFor(
not_null<UserData*> user) { not_null<PeerData*> participant) {
if (_role != Role::Profile) { if (_role != Role::Profile) {
return; return;
} }
if (const auto row = delegate()->peerListFindRow(user->id)) { if (const auto row = delegate()->peerListFindRow(participant->id)) {
static_cast<Row*>(row)->setType(computeType(user)); static_cast<Row*>(row)->setType(computeType(participant));
} }
} }
void ParticipantsBoxController::refreshCustomStatus( void ParticipantsBoxController::refreshCustomStatus(
not_null<PeerListRow*> row) const { not_null<PeerListRow*> row) const {
const auto user = row->peer()->asUser(); const auto participant = row->peer();
const auto user = participant->asUser();
if (_role == Role::Admins) { if (_role == Role::Admins) {
Assert(user != nullptr);
if (const auto by = _additional.adminPromotedBy(user)) { if (const auto by = _additional.adminPromotedBy(user)) {
row->setCustomStatus(tr::lng_channel_admin_status_promoted_by( row->setCustomStatus(tr::lng_channel_admin_status_promoted_by(
tr::now, tr::now,
@ -1882,7 +1930,7 @@ void ParticipantsBoxController::refreshCustomStatus(
} }
} }
} else if (_role == Role::Kicked || _role == Role::Restricted) { } else if (_role == Role::Kicked || _role == Role::Restricted) {
const auto by = _additional.restrictedBy(user); const auto by = _additional.restrictedBy(participant);
row->setCustomStatus((_role == Role::Kicked row->setCustomStatus((_role == Role::Kicked
? tr::lng_channel_banned_status_removed_by ? tr::lng_channel_banned_status_removed_by
: tr::lng_channel_banned_status_restricted_by)( : tr::lng_channel_banned_status_restricted_by)(

View file

@ -33,7 +33,7 @@ Fn<void(
const MTPChatBannedRights &oldRights, const MTPChatBannedRights &oldRights,
const MTPChatBannedRights &newRights)> SaveRestrictedCallback( const MTPChatBannedRights &newRights)> SaveRestrictedCallback(
not_null<PeerData*> peer, not_null<PeerData*> peer,
not_null<UserData*> user, not_null<PeerData*> participant,
Fn<void(const MTPChatBannedRights &newRights)> onDone, Fn<void(const MTPChatBannedRights &newRights)> onDone,
Fn<void()> onFail); Fn<void()> onFail);
@ -77,29 +77,31 @@ public:
ParticipantsAdditionalData(not_null<PeerData*> peer, Role role); ParticipantsAdditionalData(not_null<PeerData*> peer, Role role);
UserData *applyParticipant(const MTPChannelParticipant &data); PeerData *applyParticipant(const MTPChannelParticipant &data);
UserData *applyParticipant( PeerData *applyParticipant(
const MTPChannelParticipant &data, const MTPChannelParticipant &data,
Role overrideRole); Role overrideRole);
void setExternal(not_null<UserData*> user); void setExternal(not_null<PeerData*> participant);
void checkForLoaded(not_null<UserData*> user); void checkForLoaded(not_null<PeerData*> participant);
void fillFromPeer(); void fillFromPeer();
[[nodiscard]] bool infoLoaded(not_null<UserData*> user) const; [[nodiscard]] bool infoLoaded(not_null<PeerData*> participant) const;
[[nodiscard]] bool canEditAdmin(not_null<UserData*> user) const; [[nodiscard]] bool canEditAdmin(not_null<UserData*> user) const;
[[nodiscard]] bool canAddOrEditAdmin(not_null<UserData*> user) const; [[nodiscard]] bool canAddOrEditAdmin(not_null<UserData*> user) const;
[[nodiscard]] bool canRestrictUser(not_null<UserData*> user) const; [[nodiscard]] bool canRestrictParticipant(
[[nodiscard]] bool canRemoveUser(not_null<UserData*> user) const; not_null<PeerData*> participant) const;
[[nodiscard]] bool canRemoveParticipant(
not_null<PeerData*> participant) const;
[[nodiscard]] std::optional<MTPChatAdminRights> adminRights( [[nodiscard]] std::optional<MTPChatAdminRights> adminRights(
not_null<UserData*> user) const; not_null<UserData*> user) const;
QString adminRank(not_null<UserData*> user) const; QString adminRank(not_null<UserData*> user) const;
[[nodiscard]] std::optional<MTPChatBannedRights> restrictedRights( [[nodiscard]] std::optional<MTPChatBannedRights> restrictedRights(
not_null<UserData*> user) const; not_null<PeerData*> participant) const;
[[nodiscard]] bool isCreator(not_null<UserData*> user) const; [[nodiscard]] bool isCreator(not_null<UserData*> user) const;
[[nodiscard]] bool isExternal(not_null<UserData*> user) const; [[nodiscard]] bool isExternal(not_null<PeerData*> participant) const;
[[nodiscard]] bool isKicked(not_null<UserData*> user) const; [[nodiscard]] bool isKicked(not_null<PeerData*> participant) const;
[[nodiscard]] UserData *adminPromotedBy(not_null<UserData*> user) const; [[nodiscard]] UserData *adminPromotedBy(not_null<UserData*> user) const;
[[nodiscard]] UserData *restrictedBy(not_null<UserData*> user) const; [[nodiscard]] UserData *restrictedBy(not_null<PeerData*> participant) const;
void migrate(not_null<ChatData*> chat, not_null<ChannelData*> channel); void migrate(not_null<ChatData*> chat, not_null<ChannelData*> channel);
@ -107,7 +109,7 @@ private:
UserData *applyCreator(const MTPDchannelParticipantCreator &data); UserData *applyCreator(const MTPDchannelParticipantCreator &data);
UserData *applyAdmin(const MTPDchannelParticipantAdmin &data); UserData *applyAdmin(const MTPDchannelParticipantAdmin &data);
UserData *applyRegular(MTPint userId); UserData *applyRegular(MTPint userId);
UserData *applyBanned(const MTPDchannelParticipantBanned &data); PeerData *applyBanned(const MTPDchannelParticipantBanned &data);
void fillFromChat(not_null<ChatData*> chat); void fillFromChat(not_null<ChatData*> chat);
void fillFromChannel(not_null<ChannelData*> channel); void fillFromChannel(not_null<ChannelData*> channel);
@ -124,11 +126,11 @@ private:
base::flat_map<not_null<UserData*>, QString> _adminRanks; base::flat_map<not_null<UserData*>, QString> _adminRanks;
base::flat_set<not_null<UserData*>> _adminCanEdit; base::flat_set<not_null<UserData*>> _adminCanEdit;
base::flat_map<not_null<UserData*>, not_null<UserData*>> _adminPromotedBy; base::flat_map<not_null<UserData*>, not_null<UserData*>> _adminPromotedBy;
std::map<not_null<UserData*>, MTPChatBannedRights> _restrictedRights; std::map<not_null<PeerData*>, MTPChatBannedRights> _restrictedRights;
std::set<not_null<UserData*>> _kicked; std::set<not_null<PeerData*>> _kicked;
std::map<not_null<UserData*>, not_null<UserData*>> _restrictedBy; std::map<not_null<PeerData*>, not_null<UserData*>> _restrictedBy;
std::set<not_null<UserData*>> _external; std::set<not_null<PeerData*>> _external;
std::set<not_null<UserData*>> _infoNotLoaded; std::set<not_null<PeerData*>> _infoNotLoaded;
}; };
@ -181,7 +183,7 @@ protected:
Role role); Role role);
virtual std::unique_ptr<PeerListRow> createRow( virtual std::unique_ptr<PeerListRow> createRow(
not_null<UserData*> user) const; not_null<PeerData*> participant) const;
private: private:
using Row = Info::Profile::MemberListRow; using Row = Info::Profile::MemberListRow;
@ -223,23 +225,25 @@ private:
const QString &rank); const QString &rank);
void showRestricted(not_null<UserData*> user); void showRestricted(not_null<UserData*> user);
void editRestrictedDone( void editRestrictedDone(
not_null<UserData*> user, not_null<PeerData*> participant,
const MTPChatBannedRights &rights); const MTPChatBannedRights &rights);
void removeKicked(not_null<PeerListRow*> row, not_null<UserData*> user); void removeKicked(
void removeKickedWithRow(not_null<UserData*> user); not_null<PeerListRow*> row,
void removeKicked(not_null<UserData*> user); not_null<PeerData*> participant);
void kickMember(not_null<UserData*> user); void removeKickedWithRow(not_null<PeerData*> participant);
void kickMemberSure(not_null<UserData*> user); void removeKicked(not_null<PeerData*> participant);
void kickMember(not_null<PeerData*> participant);
void kickMemberSure(not_null<PeerData*> participant);
void unkickMember(not_null<UserData*> user); void unkickMember(not_null<UserData*> user);
void removeAdmin(not_null<UserData*> user); void removeAdmin(not_null<UserData*> user);
void removeAdminSure(not_null<UserData*> user); void removeAdminSure(not_null<UserData*> user);
bool appendRow(not_null<UserData*> user); bool appendRow(not_null<PeerData*> participant);
bool prependRow(not_null<UserData*> user); bool prependRow(not_null<UserData*> user);
bool removeRow(not_null<UserData*> user); bool removeRow(not_null<PeerData*> participant);
void refreshCustomStatus(not_null<PeerListRow*> row) const; void refreshCustomStatus(not_null<PeerListRow*> row) const;
bool feedMegagroupLastParticipants(); bool feedMegagroupLastParticipants();
Type computeType(not_null<UserData*> user) const; Type computeType(not_null<PeerData*> participant) const;
void recomputeTypeFor(not_null<UserData*> user); void recomputeTypeFor(not_null<PeerData*> participant);
void subscribeToMigration(); void subscribeToMigration();
void migrate(not_null<ChatData*> chat, not_null<ChannelData*> channel); void migrate(not_null<ChatData*> chat, not_null<ChannelData*> channel);

View file

@ -1144,7 +1144,8 @@ void GroupCall::broadcastPartStart(std::shared_ptr<LoadPartTask> task) {
rejoin(); rejoin();
return; return;
} }
const auto status = MTP::IsFloodError(error) const auto status = (MTP::IsFloodError(error)
|| error.type() == u"TIME_TOO_BIG"_q)
? Status::NotReady ? Status::NotReady
: Status::ResyncNeeded; : Status::ResyncNeeded;
finish({ finish({

View file

@ -82,7 +82,7 @@ private:
[[nodiscard]] bool isAlreadyIn(not_null<UserData*> user) const; [[nodiscard]] bool isAlreadyIn(not_null<UserData*> user) const;
std::unique_ptr<PeerListRow> createRow( std::unique_ptr<PeerListRow> createRow(
not_null<UserData*> user) const override; not_null<PeerData*> participant) const override;
not_null<PeerData*> _peer; not_null<PeerData*> _peer;
const base::flat_set<not_null<UserData*>> _alreadyIn; const base::flat_set<not_null<UserData*>> _alreadyIn;
@ -190,8 +190,9 @@ bool InviteController::isAlreadyIn(not_null<UserData*> user) const {
} }
std::unique_ptr<PeerListRow> InviteController::createRow( std::unique_ptr<PeerListRow> InviteController::createRow(
not_null<UserData*> user) const { not_null<PeerData*> participant) const {
if (user->isSelf() || user->isBot()) { const auto user = participant->asUser();
if (!user || user->isSelf() || user->isBot()) {
return nullptr; return nullptr;
} }
auto result = std::make_unique<PeerListRow>(user); auto result = std::make_unique<PeerListRow>(user);

View file

@ -267,11 +267,17 @@ void ChannelData::applyEditAdmin(
session().changes().peerUpdated(this, UpdateFlag::Admins); session().changes().peerUpdated(this, UpdateFlag::Admins);
} }
void ChannelData::applyEditBanned(not_null<UserData*> user, const MTPChatBannedRights &oldRights, const MTPChatBannedRights &newRights) { void ChannelData::applyEditBanned(
not_null<PeerData*> participant,
const MTPChatBannedRights &oldRights,
const MTPChatBannedRights &newRights) {
auto flags = UpdateFlag::BannedUsers | UpdateFlag::None; auto flags = UpdateFlag::BannedUsers | UpdateFlag::None;
auto isKicked = (newRights.c_chatBannedRights().vflags().v & MTPDchatBannedRights::Flag::f_view_messages); auto isKicked = Data::ChatBannedRightsFlags(newRights)
auto isRestricted = !isKicked && (newRights.c_chatBannedRights().vflags().v != 0); & ChatRestriction::f_view_messages;
if (mgInfo) { auto isRestricted = !isKicked
&& (Data::ChatBannedRightsFlags(newRights) != 0);
const auto user = participant->asUser();
if (mgInfo && user) {
// If rights are empty - still remove admin? TODO check // If rights are empty - still remove admin? TODO check
if (mgInfo->lastAdmins.contains(user)) { if (mgInfo->lastAdmins.contains(user)) {
mgInfo->lastAdmins.remove(user); mgInfo->lastAdmins.remove(user);
@ -284,7 +290,9 @@ void ChannelData::applyEditBanned(not_null<UserData*> user, const MTPChatBannedR
auto it = mgInfo->lastRestricted.find(user); auto it = mgInfo->lastRestricted.find(user);
if (isRestricted) { if (isRestricted) {
if (it == mgInfo->lastRestricted.cend()) { if (it == mgInfo->lastRestricted.cend()) {
mgInfo->lastRestricted.emplace(user, MegagroupInfo::Restricted { newRights }); mgInfo->lastRestricted.emplace(
user,
MegagroupInfo::Restricted { newRights });
setRestrictedCount(restrictedCount() + 1); setRestrictedCount(restrictedCount() + 1);
} else { } else {
it->second.rights = newRights; it->second.rights = newRights;
@ -297,7 +305,9 @@ void ChannelData::applyEditBanned(not_null<UserData*> user, const MTPChatBannedR
} }
} }
if (isKicked) { if (isKicked) {
auto i = ranges::find(mgInfo->lastParticipants, user); auto i = ranges::find(
mgInfo->lastParticipants,
not_null{ user });
if (i != mgInfo->lastParticipants.end()) { if (i != mgInfo->lastParticipants.end()) {
mgInfo->lastParticipants.erase(i); mgInfo->lastParticipants.erase(i);
} }
@ -319,9 +329,9 @@ void ChannelData::applyEditBanned(not_null<UserData*> user, const MTPChatBannedR
} }
} }
Data::ChannelAdminChanges(this).remove(peerToUser(user->id)); Data::ChannelAdminChanges(this).remove(peerToUser(user->id));
} else { } else if (!mgInfo) {
if (isKicked) { if (isKicked) {
if (membersCount() > 1) { if (user && membersCount() > 1) {
setMembersCount(membersCount() - 1); setMembersCount(membersCount() - 1);
flags |= UpdateFlag::Members; flags |= UpdateFlag::Members;
} }
@ -543,12 +553,14 @@ void ChannelData::setAdminRights(const MTPChatAdminRights &rights) {
} }
void ChannelData::setRestrictions(const MTPChatBannedRights &rights) { void ChannelData::setRestrictions(const MTPChatBannedRights &rights) {
if (rights.c_chatBannedRights().vflags().v == restrictions() const auto restrictedFlags = Data::ChatBannedRightsFlags(rights);
&& rights.c_chatBannedRights().vuntil_date().v == _restrictedUntil) { const auto restrictedUntilDate = Data::ChatBannedRightsUntilDate(rights);
if (restrictedFlags == restrictions()
&& restrictedUntilDate == _restrictedUntil) {
return; return;
} }
_restrictedUntil = rights.c_chatBannedRights().vuntil_date().v; _restrictedUntil = restrictedUntilDate;
_restrictions.set(rights.c_chatBannedRights().vflags().v); _restrictions.set(restrictedFlags);
if (isMegagroup()) { if (isMegagroup()) {
const auto self = session().user(); const auto self = session().user();
if (hasRestrictions()) { if (hasRestrictions()) {
@ -568,10 +580,11 @@ void ChannelData::setRestrictions(const MTPChatBannedRights &rights) {
} }
void ChannelData::setDefaultRestrictions(const MTPChatBannedRights &rights) { void ChannelData::setDefaultRestrictions(const MTPChatBannedRights &rights) {
if (rights.c_chatBannedRights().vflags().v == defaultRestrictions()) { const auto restrictionFlags = Data::ChatBannedRightsFlags(rights);
if (restrictionFlags == defaultRestrictions()) {
return; return;
} }
_defaultRestrictions.set(rights.c_chatBannedRights().vflags().v); _defaultRestrictions.set(restrictionFlags);
session().changes().peerUpdated(this, UpdateFlag::Rights); session().changes().peerUpdated(this, UpdateFlag::Rights);
} }
@ -903,8 +916,11 @@ void ApplyMegagroupAdmins(
auto admins = ranges::make_subrange( auto admins = ranges::make_subrange(
list.begin(), list.end() list.begin(), list.end()
) | ranges::views::transform([](const MTPChannelParticipant &p) { ) | ranges::views::transform([](const MTPChannelParticipant &p) {
const auto userId = p.match([](const auto &data) { const auto participantId = p.match([](
return data.vuser_id().v; const MTPDchannelParticipantBanned &data) {
return peerFromMTP(data.vpeer());
}, [](const auto &data) {
return peerFromUser(data.vuser_id());
}); });
const auto rank = p.match([](const MTPDchannelParticipantAdmin &data) { const auto rank = p.match([](const MTPDchannelParticipantAdmin &data) {
return qs(data.vrank().value_or_empty()); return qs(data.vrank().value_or_empty());
@ -913,10 +929,13 @@ void ApplyMegagroupAdmins(
}, [](const auto &data) { }, [](const auto &data) {
return QString(); return QString();
}); });
return std::make_pair(userId, rank); return std::make_pair(participantId, rank);
}) | ranges::views::filter([](const auto &pair) {
return peerIsUser(pair.first);
}); });
for (const auto &[userId, rank] : admins) { for (const auto &[participantId, rank] : admins) {
adding.emplace(userId, rank); Assert(peerIsUser(participantId));
adding.emplace(peerToUser(participantId), rank);
} }
if (channel->mgInfo->creator) { if (channel->mgInfo->creator) {
adding.emplace( adding.emplace(

View file

@ -220,7 +220,7 @@ public:
const MTPChatAdminRights &newRights, const MTPChatAdminRights &newRights,
const QString &rank); const QString &rank);
void applyEditBanned( void applyEditBanned(
not_null<UserData*> user, not_null<PeerData*> participant,
const MTPChatBannedRights &oldRights, const MTPChatBannedRights &oldRights,
const MTPChatBannedRights &newRights); const MTPChatBannedRights &newRights);

View file

@ -156,10 +156,11 @@ void ChatData::setAdminRights(const MTPChatAdminRights &rights) {
} }
void ChatData::setDefaultRestrictions(const MTPChatBannedRights &rights) { void ChatData::setDefaultRestrictions(const MTPChatBannedRights &rights) {
if (rights.c_chatBannedRights().vflags().v == defaultRestrictions()) { const auto restrictionFlags = Data::ChatBannedRightsFlags(rights);
if (restrictionFlags == defaultRestrictions()) {
return; return;
} }
_defaultRestrictions.set(rights.c_chatBannedRights().vflags().v); _defaultRestrictions.set(restrictionFlags);
session().changes().peerUpdated(this, UpdateFlag::Rights); session().changes().peerUpdated(this, UpdateFlag::Rights);
} }

View file

@ -1172,4 +1172,16 @@ std::optional<int> ResolvePinnedCount(
: std::nullopt; : std::nullopt;
} }
ChatRestrictions ChatBannedRightsFlags(const MTPChatBannedRights &rights) {
return rights.match([](const MTPDchatBannedRights &data) {
return data.vflags().v;
});
}
TimeId ChatBannedRightsUntilDate(const MTPChatBannedRights &rights) {
return rights.match([](const MTPDchatBannedRights &data) {
return data.vuntil_date().v;
});
}
} // namespace Data } // namespace Data

View file

@ -95,6 +95,11 @@ struct UnavailableReason {
} }
}; };
[[nodiscard]] ChatRestrictions ChatBannedRightsFlags(
const MTPChatBannedRights &rights);
[[nodiscard]] TimeId ChatBannedRightsUntilDate(
const MTPChatBannedRights &rights);
} // namespace Data } // namespace Data
class PeerClickHandler : public ClickHandler { class PeerClickHandler : public ClickHandler {

View file

@ -432,8 +432,11 @@ void InnerWidget::requestAdmins() {
auto filtered = ( auto filtered = (
list list
) | ranges::views::transform([&](const MTPChannelParticipant &p) { ) | ranges::views::transform([&](const MTPChannelParticipant &p) {
const auto userId = p.match([](const auto &data) { const auto participantId = p.match([](
return data.vuser_id().v; const MTPDchannelParticipantBanned &data) {
return peerFromMTP(data.vpeer());
}, [](const auto &data) {
return peerFromUser(data.vuser_id());
}); });
const auto canEdit = p.match([]( const auto canEdit = p.match([](
const MTPDchannelParticipantAdmin &data) { const MTPDchannelParticipantAdmin &data) {
@ -441,10 +444,13 @@ void InnerWidget::requestAdmins() {
}, [](const auto &) { }, [](const auto &) {
return false; return false;
}); });
return std::make_pair(userId, canEdit); return std::make_pair(participantId, canEdit);
}) | ranges::views::transform([&](auto &&pair) { }) | ranges::views::transform([&](auto &&pair) {
return std::make_pair( return std::make_pair(
session().data().userLoaded(pair.first), (peerIsUser(pair.first)
? session().data().userLoaded(
peerToUser(pair.first))
: nullptr),
pair.second); pair.second);
}) | ranges::views::filter([&](auto &&pair) { }) | ranges::views::filter([&](auto &&pair) {
return (pair.first != nullptr); return (pair.first != nullptr);
@ -1308,7 +1314,7 @@ void InnerWidget::suggestRestrictUser(not_null<UserData*> user) {
} else { } else {
_api.request(MTPchannels_GetParticipant( _api.request(MTPchannels_GetParticipant(
_channel->inputChannel, _channel->inputChannel,
user->inputUser user->input
)).done([=](const MTPchannels_ChannelParticipant &result) { )).done([=](const MTPchannels_ChannelParticipant &result) {
Expects(result.type() == mtpc_channels_channelParticipant); Expects(result.type() == mtpc_channels_channelParticipant);
@ -1352,8 +1358,7 @@ void InnerWidget::restrictUser(
} }
void InnerWidget::restrictUserDone(not_null<UserData*> user, const MTPChatBannedRights &rights) { void InnerWidget::restrictUserDone(not_null<UserData*> user, const MTPChatBannedRights &rights) {
Expects(rights.type() == mtpc_chatBannedRights); if (Data::ChatBannedRightsFlags(rights)) {
if (rights.c_chatBannedRights().vflags().v) {
_admins.erase(std::remove(_admins.begin(), _admins.end(), user), _admins.end()); _admins.erase(std::remove(_admins.begin(), _admins.end(), user), _admins.end());
_adminsCanEdit.erase(std::remove(_adminsCanEdit.begin(), _adminsCanEdit.end(), user), _adminsCanEdit.end()); _adminsCanEdit.erase(std::remove(_adminsCanEdit.begin(), _adminsCanEdit.end(), user), _adminsCanEdit.end());
} }

View file

@ -204,14 +204,11 @@ TextWithEntities GenerateAdminChangeText(
QString GenerateBannedChangeText( QString GenerateBannedChangeText(
const MTPChatBannedRights *newRights, const MTPChatBannedRights *newRights,
const MTPChatBannedRights *prevRights) { const MTPChatBannedRights *prevRights) {
Expects(!newRights || newRights->type() == mtpc_chatBannedRights);
Expects(!prevRights || prevRights->type() == mtpc_chatBannedRights);
using Flag = MTPDchatBannedRights::Flag; using Flag = MTPDchatBannedRights::Flag;
using Flags = MTPDchatBannedRights::Flags; using Flags = MTPDchatBannedRights::Flags;
auto newFlags = newRights ? newRights->c_chatBannedRights().vflags().v : Flags(0); auto newFlags = newRights ? Data::ChatBannedRightsFlags(*newRights) : Flags(0);
auto prevFlags = prevRights ? prevRights->c_chatBannedRights().vflags().v : Flags(0); auto prevFlags = prevRights ? Data::ChatBannedRightsFlags(*prevRights) : Flags(0);
static auto phraseMap = std::map<Flags, tr::phrase<>>{ static auto phraseMap = std::map<Flags, tr::phrase<>>{
{ Flag::f_view_messages, tr::lng_admin_log_banned_view_messages }, { Flag::f_view_messages, tr::lng_admin_log_banned_view_messages },
{ Flag::f_send_messages, tr::lng_admin_log_banned_send_messages }, { Flag::f_send_messages, tr::lng_admin_log_banned_send_messages },
@ -233,13 +230,11 @@ TextWithEntities GenerateBannedChangeText(
const TextWithEntities &user, const TextWithEntities &user,
const MTPChatBannedRights *newRights, const MTPChatBannedRights *newRights,
const MTPChatBannedRights *prevRights) { const MTPChatBannedRights *prevRights) {
Expects(!newRights || newRights->type() == mtpc_chatBannedRights);
using Flag = MTPDchatBannedRights::Flag; using Flag = MTPDchatBannedRights::Flag;
using Flags = MTPDchatBannedRights::Flags; using Flags = MTPDchatBannedRights::Flags;
auto newFlags = newRights ? newRights->c_chatBannedRights().vflags().v : Flags(0); auto newFlags = newRights ? Data::ChatBannedRightsFlags(*newRights) : Flags(0);
auto newUntil = newRights ? newRights->c_chatBannedRights().vuntil_date().v : TimeId(0); auto newUntil = newRights ? Data::ChatBannedRightsUntilDate(*newRights) : TimeId(0);
auto indefinitely = ChannelData::IsRestrictedForever(newUntil); auto indefinitely = ChannelData::IsRestrictedForever(newUntil);
if (newFlags & Flag::f_view_messages) { if (newFlags & Flag::f_view_messages) {
return tr::lng_admin_log_banned(tr::now, lt_user, user, Ui::Text::WithEntities); return tr::lng_admin_log_banned(tr::now, lt_user, user, Ui::Text::WithEntities);
@ -344,21 +339,23 @@ TextWithEntities GenerateInviteLinkChangeText(
return result; return result;
}; };
auto GenerateUserString( auto GenerateParticipantString(
not_null<Main::Session*> session, not_null<Main::Session*> session,
MTPint userId) { PeerId peerId) {
// User name in "User name (@username)" format with entities. // User name in "User name (@username)" format with entities.
auto user = session->data().user(userId.v); auto peer = session->data().peer(peerId);
auto name = TextWithEntities { user->name }; auto name = TextWithEntities { peer->name };
auto entityData = QString::number(user->id) if (const auto user = peer->asUser()) {
+ '.' auto entityData = QString::number(user->id)
+ QString::number(user->accessHash()); + '.'
name.entities.push_back({ + QString::number(user->accessHash());
EntityType::MentionName, name.entities.push_back({
0, EntityType::MentionName,
name.text.size(), 0,
entityData }); name.text.size(),
auto username = user->userName(); entityData });
}
auto username = peer->userName();
if (username.isEmpty()) { if (username.isEmpty()) {
return name; return name;
} }
@ -386,10 +383,14 @@ auto GenerateParticipantChangeTextInner(
return tr::lng_admin_log_transferred( return tr::lng_admin_log_transferred(
tr::now, tr::now,
lt_user, lt_user,
GenerateUserString(&channel->session(), data.vuser_id()), GenerateParticipantString(
&channel->session(),
peerFromUser(data.vuser_id())),
Ui::Text::WithEntities); Ui::Text::WithEntities);
}, [&](const MTPDchannelParticipantAdmin &data) { }, [&](const MTPDchannelParticipantAdmin &data) {
auto user = GenerateUserString(&channel->session(), data.vuser_id()); const auto user = GenerateParticipantString(
&channel->session(),
peerFromUser(data.vuser_id()));
return GenerateAdminChangeText( return GenerateAdminChangeText(
channel, channel,
user, user,
@ -398,7 +399,9 @@ auto GenerateParticipantChangeTextInner(
? &oldParticipant->c_channelParticipantAdmin().vadmin_rights() ? &oldParticipant->c_channelParticipantAdmin().vadmin_rights()
: nullptr); : nullptr);
}, [&](const MTPDchannelParticipantBanned &data) { }, [&](const MTPDchannelParticipantBanned &data) {
auto user = GenerateUserString(&channel->session(), data.vuser_id()); const auto user = GenerateParticipantString(
&channel->session(),
peerFromMTP(data.vpeer()));
return GenerateBannedChangeText( return GenerateBannedChangeText(
user, user,
&data.vbanned_rights(), &data.vbanned_rights(),
@ -406,7 +409,9 @@ auto GenerateParticipantChangeTextInner(
? &oldParticipant->c_channelParticipantBanned().vbanned_rights() ? &oldParticipant->c_channelParticipantBanned().vbanned_rights()
: nullptr); : nullptr);
}, [&](const auto &data) { }, [&](const auto &data) {
auto user = GenerateUserString(&channel->session(), data.vuser_id()); auto user = GenerateParticipantString(
&channel->session(),
peerFromUser(data.vuser_id()));
if (oldType == mtpc_channelParticipantAdmin) { if (oldType == mtpc_channelParticipantAdmin) {
return GenerateAdminChangeText( return GenerateAdminChangeText(
channel, channel,

View file

@ -1068,11 +1068,16 @@ void PeerMenuAddChannelMembers(
auto already = ( auto already = (
list list
) | ranges::views::transform([](const MTPChannelParticipant &p) { ) | ranges::views::transform([](const MTPChannelParticipant &p) {
return p.match([](const auto &data) { return p.match([](const MTPDchannelParticipantBanned &data) {
return data.vuser_id().v; return peerFromMTP(data.vpeer());
}, [](const auto &data) {
return peerFromUser(data.vuser_id());
}); });
}) | ranges::views::transform([&](UserId userId) { }) | ranges::views::transform([&](PeerId participantId) {
return channel->owner().userLoaded(userId); return peerIsUser(participantId)
? channel->owner().userLoaded(
peerToUser(participantId))
: nullptr;
}) | ranges::views::filter([](UserData *user) { }) | ranges::views::filter([](UserData *user) {
return (user != nullptr); return (user != nullptr);
}) | ranges::to_vector; }) | ranges::to_vector;