Skip to content

Commit

Permalink
Add other additional data export.
Browse files Browse the repository at this point in the history
  • Loading branch information
john-preston committed Jun 24, 2018
1 parent 6231db1 commit 54cab2c
Show file tree
Hide file tree
Showing 20 changed files with 260 additions and 29 deletions.
10 changes: 8 additions & 2 deletions Telegram/Resources/langs/lang.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1660,8 +1660,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_export_option_info_about" = "Your chosen screen name, username, phone number and profile pictures.";
"lng_export_option_contacts" = "Contacts list";
"lng_export_option_contacts_about" = "If you allow access, contacts are continuously synced with Telegram. You can adjust this in Settings > Privacy & Security on mobile devices.";
"lng_export_option_sessions" = "Sessions list";
"lng_export_option_sessions" = "Active sessions";
"lng_export_option_sessions_about" = "We store this to display your connected devices in Settings > Privacy & Security > Active Sessions. Terminating a session removes this data from Telegram servers.";
"lng_export_header_other" = "Other";
"lng_export_option_other" = "Miscellaneous data";
"lng_export_option_other_about" = "Other types of data not mentioned above. (beta)";
"lng_export_header_chats" = "Chat export settings";
"lng_export_option_personal_chats" = "Personal chats";
"lng_export_option_bot_chats" = "Bot chats";
Expand Down Expand Up @@ -1705,7 +1708,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_export_total_size" = "Total size: {size}.";
"lng_export_folder" = "Choose export folder";
"lng_export_invalid" = "Sorry, you have started a new data export, so this data export is now cancelled.";
"lng_export_delay" = "Sorry, for security reasons, you will be able to begin downloading your data in 24 hours. We have notified all your devices about the export request to make sure it's authorized and give you time to react if it's not.\n\nPlease come back on {date} and repeat the request using the same device.";
"lng_export_delay" = "Sorry, for security reasons, you will be able to begin downloading your data in {hours}. We have notified all your devices about the export request to make sure it's authorized and give you time to react if it's not.\n\nPlease come back on {date} and repeat the request using the same device.";
"lng_export_delay_less_than_hour" = "less than an hour";
"lng_export_delay_hours#one" = "{count} hour";
"lng_export_delay_hours#other" = "{count} hours";
"lng_export_suggest_title" = "Data export ready";
"lng_export_suggest_text" = "You can now download the data you requested. Start exporting data?";
"lng_export_suggest_cancel" = "Not now";
Expand Down
1 change: 1 addition & 0 deletions Telegram/Resources/scheme.tl
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLo
inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation;
inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation;
inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation;
inputTakeoutFileLocation#29be5899 = InputFileLocation;

inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent;

Expand Down
4 changes: 4 additions & 0 deletions Telegram/SourceFiles/data/data_session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ Session::Session(not_null<AuthSession*> session)
}

void Session::startExport() {
if (_exportPanel) {
_exportPanel->activatePanel();
return;
}
_export = std::make_unique<Export::ControllerWrap>();
_exportPanel = std::make_unique<Export::View::PanelController>(
_export.get());
Expand Down
54 changes: 50 additions & 4 deletions Telegram/SourceFiles/export/export_api_wrap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ LocationKey ComputeLocationKey(const Data::FileLocation &value) {
}, [&](const MTPDinputEncryptedFileLocation &data) {
result.type |= (4ULL << 24);
result.id = data.vid.v;
}, [&](const MTPDinputTakeoutFileLocation &data) {
result.type |= (5ULL << 24);
});
return result;
}
Expand Down Expand Up @@ -140,6 +142,11 @@ struct ApiWrap::UserpicsProcess {
int fileIndex = -1;
};

struct ApiWrap::OtherDataProcess {
Data::File file;
FnMut<void(Data::File&&)> done;
};

struct ApiWrap::FileProcess {
FileProcess(const QString &path, Output::Stats *stats);

Expand Down Expand Up @@ -259,7 +266,8 @@ auto ApiWrap::splitRequest(int index, Request &&request) {
}

auto ApiWrap::fileRequest(const Data::FileLocation &location, int offset) {
Expects(location.dcId != 0);
Expects(location.dcId != 0
|| location.data.type() == mtpc_inputTakeoutFileLocation);
Expects(_takeoutId.has_value());

return std::move(_mtp.request(MTPInvokeWithTakeout<MTPupload_GetFile>(
Expand All @@ -269,7 +277,14 @@ auto ApiWrap::fileRequest(const Data::FileLocation &location, int offset) {
MTP_int(offset),
MTP_int(kFileChunkSize))
)).fail([=](RPCError &&result) {
error(std::move(result));
if (result.type() == qstr("TAKEOUT_FILE_EMPTY")
&& _otherDataProcess != nullptr) {
filePartDone(0, MTP_upload_file(MTP_storage_filePartial(),
MTP_int(0),
MTP_bytes(QByteArray())));
} else {
error(std::move(result));
}
}).toDC(MTP::ShiftDcId(location.dcId, MTP::kExportMediaDcShift)));
}

Expand Down Expand Up @@ -376,6 +391,8 @@ void ApiWrap::requestSplitRanges() {
void ApiWrap::requestDialogsCount() {
Expects(_startProcess != nullptr);

validateSplits();

splitRequest(_startProcess->splitIndex, MTPmessages_GetDialogs(
MTP_flags(0),
MTP_int(0), // offset_date
Expand Down Expand Up @@ -467,7 +484,7 @@ void ApiWrap::requestDialogsList(
void ApiWrap::validateSplits() {
if (_splits.empty()) {
_splits.push_back(MTP_messageRange(
MTP_int(0),
MTP_int(1),
MTP_int(std::numeric_limits<int>::max())));
}
}
Expand Down Expand Up @@ -524,6 +541,29 @@ void ApiWrap::requestPersonalInfo(FnMut<void(Data::PersonalInfo&&)> done) {
}).send();
}

void ApiWrap::requestOtherData(
const QString &suggestedPath,
FnMut<void(Data::File&&)> done) {
Expects(_otherDataProcess == nullptr);

_otherDataProcess = std::make_unique<OtherDataProcess>();
_otherDataProcess->done = std::move(done);
_otherDataProcess->file.location.data = MTP_inputTakeoutFileLocation();
_otherDataProcess->file.suggestedPath = suggestedPath;
loadFile(
_otherDataProcess->file,
[](FileProgress progress) { return true; },
[=](const QString &result) { otherDataDone(result); });
}

void ApiWrap::otherDataDone(const QString &relativePath) {
Expects(_otherDataProcess != nullptr);

_otherDataProcess->file.relativePath = relativePath;
const auto process = base::take(_otherDataProcess);
process->done(std::move(process->file));
}

void ApiWrap::requestUserpics(
FnMut<bool(Data::UserpicsInfo&&)> start,
Fn<bool(DownloadProgress)> progress,
Expand Down Expand Up @@ -1185,7 +1225,8 @@ void ApiWrap::loadFile(
Fn<bool(FileProgress)> progress,
FnMut<void(QString)> done) {
Expects(_fileProcess == nullptr);
Expects(file.location.dcId != 0);
Expects(file.location.dcId != 0
|| file.location.data.type() == mtpc_inputTakeoutFileLocation);

_fileProcess = prepareFileProcess(file);
_fileProcess->progress = std::move(progress);
Expand Down Expand Up @@ -1265,6 +1306,11 @@ void ApiWrap::filePartDone(int offset, const MTPupload_File &result) {
error("Empty bytes received in file part.");
return;
}
const auto result = _fileProcess->file.writeBlock({});
if (!result) {
ioError(result);
return;
}
} else {
using Request = FileProcess::Request;
auto &requests = _fileProcess->requests;
Expand Down
8 changes: 8 additions & 0 deletions Telegram/SourceFiles/export/export_api_wrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ class ApiWrap {

void requestPersonalInfo(FnMut<void(Data::PersonalInfo&&)> done);

void requestOtherData(
const QString &suggestedPath,
FnMut<void(Data::File&&)> done);

struct DownloadProgress {
QString path;
int itemIndex = 0;
Expand Down Expand Up @@ -91,6 +95,7 @@ class ApiWrap {
struct StartProcess;
struct ContactsProcess;
struct UserpicsProcess;
struct OtherDataProcess;
struct FileProcess;
struct FileProgress;
struct ChatsProcess;
Expand All @@ -116,6 +121,8 @@ class ApiWrap {
void finishUserpicsSlice();
void finishUserpics();

void otherDataDone(const QString &relativePath);

void validateSplits();

void requestDialogsSlice();
Expand Down Expand Up @@ -186,6 +193,7 @@ class ApiWrap {
std::unique_ptr<LoadedFileCache> _fileCache;
std::unique_ptr<ContactsProcess> _contactsProcess;
std::unique_ptr<UserpicsProcess> _userpicsProcess;
std::unique_ptr<OtherDataProcess> _otherDataProcess;
std::unique_ptr<FileProcess> _fileProcess;
std::unique_ptr<LeftChannelsProcess> _leftChannelsProcess;
std::unique_ptr<DialogsProcess> _dialogsProcess;
Expand Down
30 changes: 29 additions & 1 deletion Telegram/SourceFiles/export/export_controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class Controller {
void exportUserpics();
void exportContacts();
void exportSessions();
void exportOtherData();
void exportDialogs();
void exportNextDialog();
void exportLeftChannels();
Expand All @@ -73,6 +74,7 @@ class Controller {
ProcessingState stateUserpics(const DownloadProgress &progress) const;
ProcessingState stateContacts() const;
ProcessingState stateSessions() const;
ProcessingState stateOtherData() const;
ProcessingState stateLeftChannels(
const DownloadProgress &progress) const;
ProcessingState stateDialogs(const DownloadProgress &progress) const;
Expand Down Expand Up @@ -250,6 +252,9 @@ void Controller::fillExportSteps() {
if (_settings.types & Type::Sessions) {
_steps.push_back(Step::Sessions);
}
if (_settings.types & Type::OtherData) {
_steps.push_back(Step::OtherData);
}
if (_settings.types & Type::AnyChatsMask) {
_steps.push_back(Step::Dialogs);
}
Expand Down Expand Up @@ -286,6 +291,9 @@ void Controller::fillSubstepsInSteps(const ApiWrap::StartInfo &info) {
if (_settings.types & Settings::Type::Sessions) {
push(Step::Sessions, 1);
}
if (_settings.types & Settings::Type::OtherData) {
push(Step::OtherData, 1);
}
if (_settings.types & Settings::Type::GroupsChannelsMask) {
push(Step::LeftChannels, info.leftChannelsCount);
}
Expand Down Expand Up @@ -321,6 +329,7 @@ void Controller::exportNext() {
case Step::Userpics: return exportUserpics();
case Step::Contacts: return exportContacts();
case Step::Sessions: return exportSessions();
case Step::OtherData: return exportOtherData();
case Step::LeftChannels: return exportLeftChannels();
case Step::Dialogs: return exportDialogs();
}
Expand All @@ -329,7 +338,6 @@ void Controller::exportNext() {

void Controller::initialize() {
setState(stateInitializing());

_api.startExport(_settings, &_stats, [=](ApiWrap::StartInfo info) {
if (ioCatchError(_writer->start(_settings, &_stats))) {
return;
Expand All @@ -340,6 +348,7 @@ void Controller::initialize() {
}

void Controller::collectLeftChannels() {
setState(stateLeftChannelsList(0));
_api.requestLeftChannelsList([=](int count) {
setState(stateLeftChannelsList(count));
return true;
Expand All @@ -350,6 +359,7 @@ void Controller::collectLeftChannels() {
}

void Controller::collectDialogsList() {
setState(stateDialogsList(0));
_api.requestDialogsList([=](int count) {
setState(stateDialogsList(count));
return true;
Expand All @@ -360,6 +370,7 @@ void Controller::collectDialogsList() {
}

void Controller::exportPersonalInfo() {
setState(statePersonalInfo());
_api.requestPersonalInfo([=](Data::PersonalInfo &&result) {
if (ioCatchError(_writer->writePersonal(result))) {
return;
Expand Down Expand Up @@ -395,6 +406,7 @@ void Controller::exportUserpics() {
}

void Controller::exportContacts() {
setState(stateContacts());
_api.requestContacts([=](Data::ContactsList &&result) {
if (ioCatchError(_writer->writeContactsList(result))) {
return;
Expand All @@ -404,6 +416,7 @@ void Controller::exportContacts() {
}

void Controller::exportSessions() {
setState(stateSessions());
_api.requestSessions([=](Data::SessionsList &&result) {
if (ioCatchError(_writer->writeSessionsList(result))) {
return;
Expand All @@ -412,6 +425,17 @@ void Controller::exportSessions() {
});
}

void Controller::exportOtherData() {
setState(stateOtherData());
const auto relativePath = "lists/other_data.json";
_api.requestOtherData(relativePath, [=](Data::File &&result) {
if (ioCatchError(_writer->writeOtherData(result))) {
return;
}
exportNext();
});
}

void Controller::exportDialogs() {
if (ioCatchError(_writer->writeDialogsStart(_dialogsInfo))) {
return;
Expand Down Expand Up @@ -573,6 +597,10 @@ ProcessingState Controller::stateSessions() const {
return prepareState(Step::Sessions);
}

ProcessingState Controller::stateOtherData() const {
return prepareState(Step::OtherData);
}

ProcessingState Controller::stateLeftChannels(
const DownloadProgress & progress) const {
const auto step = Step::LeftChannels;
Expand Down
1 change: 1 addition & 0 deletions Telegram/SourceFiles/export/export_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ struct ProcessingState {
Userpics,
Contacts,
Sessions,
OtherData,
LeftChannels,
Dialogs,
};
Expand Down
2 changes: 1 addition & 1 deletion Telegram/SourceFiles/export/export_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ bool Settings::validate() const {
return false;
} else if ((fullChats & MustNotBeFull) != 0) {
return false;
} else if (format != Format::Text && format != Format::Json) {
} else if (format != Format::Html && format != Format::Json) {
return false;
} else if (!media.validate()) {
return false;
Expand Down
15 changes: 8 additions & 7 deletions Telegram/SourceFiles/export/export_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,21 @@ struct Settings {
Userpics = 0x002,
Contacts = 0x004,
Sessions = 0x008,
PersonalChats = 0x010,
BotChats = 0x020,
PrivateGroups = 0x040,
PublicGroups = 0x080,
PrivateChannels = 0x100,
PublicChannels = 0x200,
OtherData = 0x010,
PersonalChats = 0x020,
BotChats = 0x040,
PrivateGroups = 0x080,
PublicGroups = 0x100,
PrivateChannels = 0x200,
PublicChannels = 0x400,

GroupsMask = PrivateGroups | PublicGroups,
ChannelsMask = PrivateChannels | PublicChannels,
GroupsChannelsMask = GroupsMask | ChannelsMask,
NonChannelChatsMask = PersonalChats | BotChats | PrivateGroups,
AnyChatsMask = PersonalChats | BotChats | GroupsChannelsMask,
NonChatsMask = PersonalInfo | Userpics | Contacts | Sessions,
AllMask = NonChatsMask | AnyChatsMask,
AllMask = NonChatsMask | OtherData | AnyChatsMask,
};
using Types = base::flags<Type>;
friend inline constexpr auto is_flag_type(Type) { return true; };
Expand Down
4 changes: 4 additions & 0 deletions Telegram/SourceFiles/export/output/export_output_abstract.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct SessionsList;
struct DialogsInfo;
struct DialogInfo;
struct MessagesSlice;
struct File;
} // namespace Data

struct Settings;
Expand Down Expand Up @@ -60,6 +61,9 @@ class AbstractWriter {
[[nodiscard]] virtual Result writeSessionsList(
const Data::SessionsList &data) = 0;

[[nodiscard]] virtual Result writeOtherData(
const Data::File &data) = 0;

[[nodiscard]] virtual Result writeDialogsStart(
const Data::DialogsInfo &data) = 0;
[[nodiscard]] virtual Result writeDialogStart(
Expand Down
Loading

0 comments on commit 54cab2c

Please sign in to comment.