Skip to content

Commit

Permalink
Add simple files and contacts export.
Browse files Browse the repository at this point in the history
Also move all API calls in export to Export::ApiWrap.
  • Loading branch information
john-preston committed Jun 11, 2018
1 parent 0a1a5ed commit cec8114
Show file tree
Hide file tree
Showing 21 changed files with 936 additions and 292 deletions.
9 changes: 7 additions & 2 deletions Telegram/SourceFiles/base/optional.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,17 @@ class optional : public optional_variant<Type> {
public:
using parent::parent;

Type &operator*() {
Type &operator*() & {
Expects(parent::template is<Type>());

return parent::template get_unchecked<Type>();
}
const Type &operator*() const {
Type &&operator*() && {
Expects(parent::template is<Type>());

return std::move(parent::template get_unchecked<Type>());
}
const Type &operator*() const & {
Expects(parent::template is<Type>());

return parent::template get_unchecked<Type>();
Expand Down
198 changes: 164 additions & 34 deletions Telegram/SourceFiles/export/data/export_data_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,53 +18,183 @@ Utf8String ParseString(const MTPstring &data) {
return data.v;
}

PersonalInfo ParsePersonalInfo(const MTPUserFull &data) {
Expects(data.type() == mtpc_userFull);

const auto &fields = data.c_userFull();
const auto &small = fields.vuser.c_user();
auto result = PersonalInfo();
if (small.has_first_name()) {
result.firstName = ParseString(small.vfirst_name);
}
if (small.has_last_name()) {
result.lastName = ParseString(small.vlast_name);
}
if (small.has_phone()) {
result.phoneNumber = ParseString(small.vphone);
FileLocation ParseLocation(const MTPFileLocation &data) {
switch (data.type()) {
case mtpc_fileLocation: {
const auto &location = data.c_fileLocation();
return {
location.vdc_id.v,
MTP_inputFileLocation(
location.vvolume_id,
location.vlocal_id,
location.vsecret)
};
} break;
case mtpc_fileLocationUnavailable: {
const auto &location = data.c_fileLocationUnavailable();
return {
0,
MTP_inputFileLocation(
location.vvolume_id,
location.vlocal_id,
location.vsecret)
};
} break;
}
if (small.has_username()) {
result.username = ParseString(small.vusername);
Unexpected("Type in ParseLocation.");
}

File ParseMaxImage(
const MTPVector<MTPPhotoSize> &data,
const QString &suggestedPath) {
auto result = File();
result.suggestedPath = suggestedPath;

auto maxArea = int64(0);
for (const auto &size : data.v) {
switch (size.type()) {
case mtpc_photoSize: {
const auto &fields = size.c_photoSize();
const auto area = fields.vw.v * int64(fields.vh.v);
if (area > maxArea) {
result.location = ParseLocation(fields.vlocation);
result.size = fields.vsize.v;
result.content = QByteArray();
maxArea = area;
}
} break;

case mtpc_photoCachedSize: {
const auto &fields = size.c_photoCachedSize();
const auto area = fields.vw.v * int64(fields.vh.v);
if (area > maxArea) {
result.location = ParseLocation(fields.vlocation);
result.size = fields.vbytes.v.size();
result.content = fields.vbytes.v;
maxArea = area;
}
} break;
}
}
if (fields.has_about()) {
result.bio = ParseString(fields.vabout);
return result;
}

Photo ParsePhoto(const MTPPhoto &data, const QString &suggestedPath) {
auto result = Photo();
switch (data.type()) {
case mtpc_photo: {
const auto &photo = data.c_photo();
result.id = photo.vid.v;
result.date = QDateTime::fromTime_t(photo.vdate.v);
result.image = ParseMaxImage(photo.vsizes, suggestedPath);
} break;

case mtpc_photoEmpty: {
const auto &photo = data.c_photoEmpty();
result.id = photo.vid.v;
} break;

default: Unexpected("Photo type in ParsePhoto.");
}
return result;
}

Utf8String FormatDateTime(
const int32 date,
QChar dateSeparator,
QChar timeSeparator,
QChar separator) {
const auto value = QDateTime::fromTime_t(date);
return (QString("%1") + dateSeparator + "%2" + dateSeparator + "%3"
+ separator + "%4" + timeSeparator + "%5" + timeSeparator + "%6"
).arg(value.date().year()
).arg(value.date().month(), 2, 10, QChar('0')
).arg(value.date().day(), 2, 10, QChar('0')
).arg(value.time().hour(), 2, 10, QChar('0')
).arg(value.time().minute(), 2, 10, QChar('0')
).arg(value.time().second(), 2, 10, QChar('0')
).toUtf8();
}

UserpicsSlice ParseUserpicsSlice(const MTPVector<MTPPhoto> &data) {
const auto &list = data.v;
auto result = UserpicsSlice();
result.list.reserve(list.size());
for (const auto &photo : list) {
switch (photo.type()) {
case mtpc_photo: {
const auto &fields = photo.c_photo();
auto userpic = Userpic();
userpic.id = fields.vid.v;
userpic.date = QDateTime::fromTime_t(fields.vdate.v);
userpic.image = File{ "(not saved)" };
result.list.push_back(std::move(userpic));
} break;
const auto suggestedPath = "PersonalPhotos/Photo_"
+ (photo.type() == mtpc_photo
? QString::fromUtf8(
FormatDateTime(photo.c_photo().vdate.v, '_', '_', '_'))
: "Empty")
+ ".jpg";
result.list.push_back(ParsePhoto(photo, suggestedPath));
}
return result;
}

case mtpc_photoEmpty: {
const auto &fields = photo.c_photoEmpty();
auto userpic = Userpic();
userpic.id = fields.vid.v;
result.list.push_back(std::move(userpic));
} break;
User ParseUser(const MTPUser &data) {
auto result = User();
switch (data.type()) {
case mtpc_user: {
const auto &fields = data.c_user();
result.id = fields.vid.v;
if (fields.has_first_name()) {
result.firstName = ParseString(fields.vfirst_name);
}
if (fields.has_last_name()) {
result.lastName = ParseString(fields.vlast_name);
}
if (fields.has_phone()) {
result.phoneNumber = ParseString(fields.vphone);
}
if (fields.has_username()) {
result.username = ParseString(fields.vusername);
}
} break;

case mtpc_userEmpty: {
const auto &fields = data.c_userEmpty();
result.id = fields.vid.v;
} break;

default: Unexpected("Type in ParseUser.");
}
return result;
}

std::map<int, User> ParseUsersList(const MTPVector<MTPUser> &data) {
auto result = std::map<int, User>();
for (const auto &user : data.v) {
auto parsed = ParseUser(user);
result.emplace(parsed.id, std::move(parsed));
}
return result;
}

PersonalInfo ParsePersonalInfo(const MTPUserFull &data) {
Expects(data.type() == mtpc_userFull);

const auto &fields = data.c_userFull();
auto result = PersonalInfo();
result.user = ParseUser(fields.vuser);
if (fields.has_about()) {
result.bio = ParseString(fields.vabout);
}
return result;
}

ContactsList ParseContactsList(const MTPcontacts_Contacts &data) {
Expects(data.type() == mtpc_contacts_contacts);

default: Unexpected("Photo type in ParseUserpicsSlice.");
auto result = ContactsList();
const auto &contacts = data.c_contacts_contacts();
const auto map = ParseUsersList(contacts.vusers);
for (const auto &contact : contacts.vcontacts.v) {
const auto userId = contact.c_contact().vuser_id.v;
if (const auto i = map.find(userId); i != end(map)) {
result.list.push_back(i->second);
} else {
result.list.push_back(User());
}
}
return result;
Expand Down
52 changes: 38 additions & 14 deletions Telegram/SourceFiles/export/data/export_data_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ For license and copyright information please follow this link:
#pragma once

#include "scheme.h"
#include "base/optional.h"

#include <QtCore/QDateTime>
#include <QtCore/QString>
Expand All @@ -28,46 +29,64 @@ inline auto NumberToString(Type value)
return QByteArray(result.data(), int(result.size()));
}

struct PersonalInfo {
Utf8String firstName;
Utf8String lastName;
Utf8String phoneNumber;
Utf8String username;
Utf8String bio;
};

PersonalInfo ParsePersonalInfo(const MTPUserFull &data);

struct UserpicsInfo {
int count = 0;
};

struct FileLocation {
int dcId = 0;
MTPInputFileLocation data;
};

struct File {
FileLocation location;
int size = 0;
QByteArray content;

QString suggestedPath;

QString relativePath;
};

struct Userpic {
struct Photo {
uint64 id = 0;
QDateTime date;

int width = 0;
int height = 0;
File image;
};

struct UserpicsSlice {
std::vector<Userpic> list;
std::vector<Photo> list;
};

UserpicsSlice ParseUserpicsSlice(const MTPVector<MTPPhoto> &data);

struct Contact {
struct User {
int id = 0;
Utf8String firstName;
Utf8String lastName;
Utf8String phoneNumber;
Utf8String username;
};

User ParseUser(const MTPUser &user);
std::map<int, User> ParseUsersList(const MTPVector<MTPUser> &data);

struct PersonalInfo {
User user;
Utf8String bio;
};

PersonalInfo ParsePersonalInfo(const MTPUserFull &data);

struct ContactsList {
std::vector<Contact> list;
std::vector<User> list;
};

ContactsList ParseContactsList(const MTPcontacts_Contacts &data);

struct Session {
Utf8String platform;
Utf8String deviceModel;
Expand Down Expand Up @@ -108,6 +127,11 @@ struct MessagesSlice {
};

Utf8String FormatPhoneNumber(const Utf8String &phoneNumber);
Utf8String FormatDateTime(
const int32 date,
QChar dateSeparator = QChar('.'),
QChar timeSeparator = QChar(':'),
QChar separator = QChar(' '));

} // namespace Data
} // namespace Export
Loading

0 comments on commit cec8114

Please sign in to comment.