mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-04-01 00:08:02 +00:00
Merge old group with supergroup history in export.
This commit is contained in:
parent
1598165e2b
commit
8f80c19ae1
@ -36,6 +36,7 @@ namespace {
|
||||
constexpr auto kUserPeerIdShift = (1ULL << 32);
|
||||
constexpr auto kChatPeerIdShift = (2ULL << 32);
|
||||
constexpr auto kMaxImageSize = 10000;
|
||||
constexpr auto kMigratedMessagesIdShift = -1'000'000'000;
|
||||
|
||||
QString PrepareFileNameDatePart(TimeId date) {
|
||||
return date
|
||||
@ -712,6 +713,12 @@ Chat ParseChat(const MTPChat &data) {
|
||||
result.id = data.vid().v;
|
||||
result.title = ParseString(data.vtitle());
|
||||
result.input = MTP_inputPeerChat(MTP_int(result.id));
|
||||
if (const auto migratedTo = data.vmigrated_to()) {
|
||||
result.migratedToChannelId = migratedTo->match(
|
||||
[](const MTPDinputChannel &data) {
|
||||
return data.vchannel_id().v;
|
||||
}, [](auto&&) { return 0; });
|
||||
}
|
||||
}, [&](const MTPDchatEmpty &data) {
|
||||
result.id = data.vid().v;
|
||||
result.input = MTP_inputPeerChat(MTP_int(result.id));
|
||||
@ -1477,6 +1484,9 @@ DialogsInfo ParseDialogsInfo(const MTPmessages_Dialogs &data) {
|
||||
? peer.user()->info.lastName
|
||||
: Utf8String();
|
||||
info.input = peer.input();
|
||||
info.migratedToChannelId = peer.chat()
|
||||
? peer.chat()->migratedToChannelId
|
||||
: 0;
|
||||
}
|
||||
info.topMessageId = fields.vtop_message().v;
|
||||
const auto shift = IsChatPeerId(info.peerId)
|
||||
@ -1515,6 +1525,7 @@ DialogInfo DialogInfoFromChat(const Chat &data) {
|
||||
result.topMessageDate = 0;
|
||||
result.topMessageId = 0;
|
||||
result.type = DialogTypeFromChat(data);
|
||||
result.migratedToChannelId = data.migratedToChannelId;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1590,6 +1601,34 @@ DialogsInfo ParseDialogsInfo(
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AddMigrateFromSlice(
|
||||
DialogInfo &to,
|
||||
const DialogInfo &from,
|
||||
int splitIndex,
|
||||
int splitsCount) {
|
||||
Expects(splitIndex < splitsCount);
|
||||
|
||||
const auto good = to.migratedFromInput.match([](
|
||||
const MTPDinputPeerEmpty &) {
|
||||
return true;
|
||||
}, [&](const MTPDinputPeerChat & data) {
|
||||
return (ChatPeerId(data.vchat_id().v) == from.peerId);
|
||||
}, [](auto&&) { return false; });
|
||||
if (!good) {
|
||||
return false;
|
||||
}
|
||||
Assert(from.splits.size() == from.messagesCountPerSplit.size());
|
||||
for (auto i = 0, count = int(from.splits.size()); i != count; ++i) {
|
||||
Assert(from.splits[i] < splitsCount);
|
||||
to.splits.push_back(from.splits[i] - splitsCount);
|
||||
to.messagesCountPerSplit.push_back(from.messagesCountPerSplit[i]);
|
||||
}
|
||||
to.migratedFromInput = from.input;
|
||||
to.splits.push_back(splitIndex - splitsCount);
|
||||
to.messagesCountPerSplit.push_back(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
void FinalizeDialogsInfo(DialogsInfo &info, const Settings &settings) {
|
||||
auto &chats = info.chats;
|
||||
auto &left = info.left;
|
||||
@ -1619,7 +1658,7 @@ void FinalizeDialogsInfo(DialogsInfo &info, const Settings &settings) {
|
||||
}();
|
||||
dialog.onlyMyMessages = ((settings.fullChats & setting) != setting);
|
||||
|
||||
ranges::reverse(dialog.splits);
|
||||
ranges::sort(dialog.splits);
|
||||
}
|
||||
for (auto &dialog : left) {
|
||||
Assert(!settings.onlySinglePeer());
|
||||
@ -1647,6 +1686,16 @@ MessagesSlice ParseMessagesSlice(
|
||||
return result;
|
||||
}
|
||||
|
||||
MessagesSlice AdjustMigrateMessageIds(MessagesSlice slice) {
|
||||
for (auto &message : slice.list) {
|
||||
message.id += kMigratedMessagesIdShift;
|
||||
if (message.replyToMsgId) {
|
||||
message.replyToMsgId += kMigratedMessagesIdShift;
|
||||
}
|
||||
}
|
||||
return slice;
|
||||
}
|
||||
|
||||
TimeId SingleMessageDate(const MTPmessages_Messages &data) {
|
||||
return data.match([&](const MTPDmessages_messagesNotModified &data) {
|
||||
return 0;
|
||||
|
@ -220,6 +220,7 @@ std::map<int32, User> ParseUsersList(const MTPVector<MTPUser> &data);
|
||||
|
||||
struct Chat {
|
||||
int32 id = 0;
|
||||
int32 migratedToChannelId = 0;
|
||||
Utf8String title;
|
||||
Utf8String username;
|
||||
bool isBroadcast = false;
|
||||
@ -564,6 +565,9 @@ struct DialogInfo {
|
||||
TimeId topMessageDate = 0;
|
||||
PeerId peerId = 0;
|
||||
|
||||
MTPInputPeer migratedFromInput = MTP_inputPeerEmpty();
|
||||
int32 migratedToChannelId = 0;
|
||||
|
||||
// User messages splits which contained that dialog.
|
||||
std::vector<int> splits;
|
||||
|
||||
@ -594,6 +598,11 @@ DialogsInfo ParseDialogsInfo(
|
||||
const MTPInputPeer &singlePeer,
|
||||
const MTPmessages_Chats &data);
|
||||
DialogsInfo ParseLeftChannelsInfo(const MTPmessages_Chats &data);
|
||||
bool AddMigrateFromSlice(
|
||||
DialogInfo &to,
|
||||
const DialogInfo &from,
|
||||
int splitIndex,
|
||||
int splitsCount);
|
||||
void FinalizeDialogsInfo(DialogsInfo &info, const Settings &settings);
|
||||
|
||||
struct MessagesSlice {
|
||||
@ -607,6 +616,7 @@ MessagesSlice ParseMessagesSlice(
|
||||
const MTPVector<MTPUser> &users,
|
||||
const MTPVector<MTPChat> &chats,
|
||||
const QString &mediaFolder);
|
||||
MessagesSlice AdjustMigrateMessageIds(MessagesSlice slice);
|
||||
|
||||
bool SingleMessageBefore(
|
||||
const MTPmessages_Messages &data,
|
||||
|
@ -1047,34 +1047,9 @@ void ApiWrap::cancelExportFast() {
|
||||
}
|
||||
|
||||
void ApiWrap::requestSinglePeerDialog() {
|
||||
const auto isChannelType = [](Data::DialogInfo::Type type) {
|
||||
using Type = Data::DialogInfo::Type;
|
||||
return (type == Type::PrivateSupergroup)
|
||||
|| (type == Type::PublicSupergroup)
|
||||
|| (type == Type::PrivateChannel)
|
||||
|| (type == Type::PublicChannel);
|
||||
};
|
||||
auto doneSinglePeer = [=](const auto &result) {
|
||||
auto info = Data::ParseDialogsInfo(_settings->singlePeer, result);
|
||||
|
||||
_dialogsProcess->processedCount += info.chats.size();
|
||||
appendDialogsSlice(std::move(info));
|
||||
|
||||
const auto last = _dialogsProcess->splitIndexPlusOne - 1;
|
||||
for (auto &info : _dialogsProcess->info.chats) {
|
||||
if (isChannelType(info.type)) {
|
||||
continue;
|
||||
}
|
||||
for (auto i = last; i != 0; --i) {
|
||||
info.splits.push_back(i - 1);
|
||||
info.messagesCountPerSplit.push_back(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_dialogsProcess->progress(_dialogsProcess->processedCount)) {
|
||||
return;
|
||||
}
|
||||
finishDialogsList();
|
||||
appendSinglePeerDialogs(
|
||||
Data::ParseDialogsInfo(_settings->singlePeer, result));
|
||||
};
|
||||
const auto requestUser = [&](const MTPInputUser &data) {
|
||||
mainRequest(MTPusers_GetUsers(
|
||||
@ -1104,6 +1079,76 @@ void ApiWrap::requestSinglePeerDialog() {
|
||||
});
|
||||
}
|
||||
|
||||
mtpRequestId ApiWrap::requestSinglePeerMigrated(
|
||||
const Data::DialogInfo &info) {
|
||||
const auto input = info.input.match([&](
|
||||
const MTPDinputPeerChannel & data) {
|
||||
return MTP_inputChannel(
|
||||
data.vchannel_id(),
|
||||
data.vaccess_hash());
|
||||
}, [](auto&&) -> MTPinputChannel {
|
||||
Unexpected("Peer type in a supergroup.");
|
||||
});
|
||||
return mainRequest(MTPchannels_GetFullChannel(
|
||||
input
|
||||
)).done([=](const MTPmessages_ChatFull &result) {
|
||||
auto info = result.match([&](
|
||||
const MTPDmessages_chatFull &data) {
|
||||
const auto migratedChatId = data.vfull_chat().match([&](
|
||||
const MTPDchannelFull &data) {
|
||||
return data.vmigrated_from_chat_id().value_or_empty();
|
||||
}, [](auto &&other) {
|
||||
return 0;
|
||||
});
|
||||
return migratedChatId
|
||||
? Data::ParseDialogsInfo(
|
||||
MTP_inputPeerChat(MTP_int(migratedChatId)),
|
||||
MTP_messages_chats(data.vchats()))
|
||||
: Data::DialogsInfo();
|
||||
});
|
||||
appendSinglePeerDialogs(std::move(info));
|
||||
}).send();
|
||||
}
|
||||
|
||||
void ApiWrap::appendSinglePeerDialogs(Data::DialogsInfo &&info) {
|
||||
const auto isSupergroupType = [](Data::DialogInfo::Type type) {
|
||||
using Type = Data::DialogInfo::Type;
|
||||
return (type == Type::PrivateSupergroup)
|
||||
|| (type == Type::PublicSupergroup);
|
||||
};
|
||||
const auto isChannelType = [](Data::DialogInfo::Type type) {
|
||||
using Type = Data::DialogInfo::Type;
|
||||
return (type == Type::PrivateChannel)
|
||||
|| (type == Type::PublicChannel);
|
||||
};
|
||||
|
||||
auto migratedRequestId = mtpRequestId(0);
|
||||
const auto last = _dialogsProcess->splitIndexPlusOne - 1;
|
||||
for (auto &info : info.chats) {
|
||||
if (isSupergroupType(info.type) && !migratedRequestId) {
|
||||
migratedRequestId = requestSinglePeerMigrated(info);
|
||||
continue;
|
||||
} else if (isChannelType(info.type)) {
|
||||
continue;
|
||||
}
|
||||
for (auto i = last; i != 0; --i) {
|
||||
info.splits.push_back(i - 1);
|
||||
info.messagesCountPerSplit.push_back(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!migratedRequestId) {
|
||||
_dialogsProcess->processedCount += info.chats.size();
|
||||
}
|
||||
appendDialogsSlice(std::move(info));
|
||||
|
||||
if (migratedRequestId
|
||||
|| !_dialogsProcess->progress(_dialogsProcess->processedCount)) {
|
||||
return;
|
||||
}
|
||||
finishDialogsList();
|
||||
}
|
||||
|
||||
void ApiWrap::requestDialogsSlice() {
|
||||
Expects(_dialogsProcess != nullptr);
|
||||
|
||||
@ -1261,15 +1306,41 @@ void ApiWrap::appendChatsSlice(
|
||||
Expects(_settings != nullptr);
|
||||
|
||||
const auto types = _settings->types;
|
||||
const auto goodByTypes = [&](const Data::DialogInfo &info) {
|
||||
return ((types & SettingsFromDialogsType(info.type)) != 0);
|
||||
};
|
||||
auto filtered = ranges::view::all(
|
||||
from
|
||||
) | ranges::view::filter([&](const Data::DialogInfo &info) {
|
||||
return (types & SettingsFromDialogsType(info.type)) != 0;
|
||||
if (goodByTypes(info)) {
|
||||
return true;
|
||||
} else if (info.migratedToChannelId
|
||||
&& (((types & Settings::Type::PublicGroups) != 0)
|
||||
|| ((types & Settings::Type::PrivateGroups) != 0))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
to.reserve(to.size() + from.size());
|
||||
for (auto &info : filtered) {
|
||||
const auto nextIndex = to.size();
|
||||
const auto [i, ok] = process.indexByPeer.emplace(info.peerId, nextIndex);
|
||||
if (info.migratedToChannelId) {
|
||||
const auto toPeerId = Data::ChatPeerId(info.migratedToChannelId);
|
||||
const auto i = process.indexByPeer.find(toPeerId);
|
||||
if (i != process.indexByPeer.end()
|
||||
&& Data::AddMigrateFromSlice(
|
||||
to[i->second],
|
||||
info,
|
||||
splitIndex,
|
||||
int(_splits.size()))) {
|
||||
continue;
|
||||
} else if (!goodByTypes(info)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const auto [i, ok] = process.indexByPeer.emplace(
|
||||
info.peerId,
|
||||
nextIndex);
|
||||
if (ok) {
|
||||
to.push_back(std::move(info));
|
||||
}
|
||||
@ -1325,10 +1396,17 @@ void ApiWrap::requestChatMessages(
|
||||
|
||||
base::take(_chatProcess->requestDone)(std::move(result));
|
||||
};
|
||||
const auto splitsCount = int(_splits.size());
|
||||
const auto realPeerInput = (splitIndex >= 0)
|
||||
? _chatProcess->info.input
|
||||
: _chatProcess->info.migratedFromInput;
|
||||
const auto realSplitIndex = (splitIndex >= 0)
|
||||
? splitIndex
|
||||
: (splitsCount + splitIndex);
|
||||
if (_chatProcess->info.onlyMyMessages) {
|
||||
splitRequest(splitIndex, MTPmessages_Search(
|
||||
splitRequest(realSplitIndex, MTPmessages_Search(
|
||||
MTP_flags(MTPmessages_Search::Flag::f_from_id),
|
||||
_chatProcess->info.input,
|
||||
realPeerInput,
|
||||
MTP_string(), // query
|
||||
_user,
|
||||
MTP_inputMessagesFilterEmpty(),
|
||||
@ -1342,8 +1420,8 @@ void ApiWrap::requestChatMessages(
|
||||
MTP_int(0) // hash
|
||||
)).done(doneHandler).send();
|
||||
} else {
|
||||
splitRequest(splitIndex, MTPmessages_GetHistory(
|
||||
_chatProcess->info.input,
|
||||
splitRequest(realSplitIndex, MTPmessages_GetHistory(
|
||||
realPeerInput,
|
||||
MTP_int(offsetId),
|
||||
MTP_int(0), // offset_date
|
||||
MTP_int(addOffset),
|
||||
@ -1355,7 +1433,7 @@ void ApiWrap::requestChatMessages(
|
||||
Expects(_chatProcess != nullptr);
|
||||
|
||||
if (error.type() == qstr("CHANNEL_PRIVATE")) {
|
||||
if (_chatProcess->info.input.type() == mtpc_inputPeerChannel
|
||||
if (realPeerInput.type() == mtpc_inputPeerChannel
|
||||
&& !_chatProcess->info.onlyMyMessages) {
|
||||
|
||||
// Perhaps we just left / were kicked from channel.
|
||||
@ -1399,10 +1477,16 @@ Data::FileOrigin ApiWrap::currentFileMessageOrigin() const {
|
||||
Expects(_chatProcess != nullptr);
|
||||
Expects(_chatProcess->slice.has_value());
|
||||
|
||||
const auto splitIndex = _chatProcess->info.splits[
|
||||
_chatProcess->localSplitIndex];
|
||||
auto result = Data::FileOrigin();
|
||||
result.messageId = currentFileMessage()->id;
|
||||
result.peer = _chatProcess->info.input;
|
||||
result.split = _chatProcess->info.splits[_chatProcess->localSplitIndex];
|
||||
result.split = (splitIndex >= 0)
|
||||
? splitIndex
|
||||
: (int(_splits.size()) + splitIndex);
|
||||
result.peer = (splitIndex >= 0)
|
||||
? _chatProcess->info.input
|
||||
: _chatProcess->info.migratedFromInput;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1452,6 +1536,11 @@ void ApiWrap::finishMessagesSlice() {
|
||||
auto slice = *base::take(_chatProcess->slice);
|
||||
if (!slice.list.empty()) {
|
||||
_chatProcess->largestIdPlusOne = slice.list.back().id + 1;
|
||||
const auto splitIndex = _chatProcess->info.splits[
|
||||
_chatProcess->localSplitIndex];
|
||||
if (splitIndex < 0) {
|
||||
slice = AdjustMigrateMessageIds(std::move(slice));
|
||||
}
|
||||
if (!_chatProcess->handleSlice(std::move(slice))) {
|
||||
return;
|
||||
}
|
||||
|
@ -126,6 +126,8 @@ private:
|
||||
void appendDialogsSlice(Data::DialogsInfo &&info);
|
||||
void finishDialogsList();
|
||||
void requestSinglePeerDialog();
|
||||
mtpRequestId requestSinglePeerMigrated(const Data::DialogInfo &info);
|
||||
void appendSinglePeerDialogs(Data::DialogsInfo &&info);
|
||||
|
||||
void requestLeftChannelsIfNeeded();
|
||||
void requestLeftChannelsList(
|
||||
|
@ -352,7 +352,9 @@ void ControllerObject::initialized(const ApiWrap::StartInfo &info) {
|
||||
void ControllerObject::collectDialogsList() {
|
||||
setState(stateDialogsList(0));
|
||||
_api.requestDialogsList([=](int count) {
|
||||
setState(stateDialogsList(count));
|
||||
if (count > 0) {
|
||||
setState(stateDialogsList(count - 1));
|
||||
}
|
||||
return true;
|
||||
}, [=](Data::DialogsInfo &&result) {
|
||||
_dialogsInfo = std::move(result);
|
||||
|
Loading…
Reference in New Issue
Block a user