Skip to content
Snippets Groups Projects
Commit dd1cdd30 authored by Stepan Salenikovich's avatar Stepan Salenikovich Committed by Edric Milaret
Browse files

Load saved TextRecordings from .json files.

The main goal of this patch is to be able to recover ContactMethods
and conversations which have not been added to the users's contacts
and/or which have no call history. This happens in the case that the
users only sends chat messages to a ContactMethod.

Note that there is a possibility for more than one file to be
associated with the same CM, in the case the sha1 of that CM has
changed (eg: a contact UID has been associated with the CM at some
point). In this case, the most recent recording is used. However,
this is a problem which already exists and is unrelated to this patch.

Tuleap: #270
Change-Id: I5c67be83028af3fc3e1950909574ec947c55c50c
parent 8b68c493
No related branches found
No related tags found
No related merge requests found
......@@ -171,9 +171,57 @@ bool LocalTextRecordingCollection::isEnabled() const
bool LocalTextRecordingCollection::load()
{
//This collection is special as it use the history collection
//as its source, there is no loading
return true;
// load all text recordings so we can recover CMs that are not in the call history
QDir dir(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/text/");
if (dir.exists()) {
// get .json files, sorted by time, latest first
QStringList filters;
filters << "*.json";
auto list = dir.entryInfoList(filters, QDir::Files | QDir::NoSymLinks | QDir::Readable, QDir::Time);
for (int i = 0; i < list.size(); ++i) {
QFileInfo fileInfo = list.at(i);
QString content;
QFile file(fileInfo.absoluteFilePath());
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
content = QString::fromUtf8(file.readAll());
} else {
qWarning() << "Could not open text recording json file";
}
if (!content.isEmpty()) {
QJsonParseError err;
QJsonDocument loadDoc = QJsonDocument::fromJson(content.toUtf8(), &err);
if (err.error == QJsonParseError::ParseError::NoError) {
Media::TextRecording* r = Media::TextRecording::fromJson({loadDoc.object()});
editor<Media::Recording>()->addExisting(r);
r->setCollection(this);
// get CMs from recording
for (ContactMethod *cm : r->peers()) {
// since we load the recordings in order from newest to oldest, if there is
// more than one found associated with a CM, we take the newest one
if (!cm->d_ptr->m_pTextRecording) {
cm->d_ptr->setTextRecording(r);
} else {
qWarning() << "CM already has text recording" << cm;
}
}
} else {
qWarning() << "Error Decoding Text Message History Json" << err.errorString();
}
} else {
qWarning() << "Text recording file is empty";
}
}
}
// always return true, even if noting was loaded, since the collection can still be used to
// save files
return true;
}
bool LocalTextRecordingCollection::reload()
......
......@@ -208,6 +208,19 @@ void Media::TextRecording::setAllRead()
}
}
QVector<ContactMethod*> Media::TextRecording::peers() const
{
QVector<ContactMethod*> cms;
for (const Serializable::Peers* peers : d_ptr->m_lAssociatedPeers) {
for (const Serializable::Peer* peer : peers->peers) {
cms << peer->m_pContactMethod;
}
}
return cms;
}
/**
* I (Emmanuel Lepage) is in the process of writing a better one for this that
* can be upstreamed into Qt (there is interest in merging a generic QVariant
......@@ -304,40 +317,61 @@ QHash<QByteArray,QByteArray> Media::TextRecordingPrivate::toJsons() const
Media::TextRecording* Media::TextRecording::fromJson(const QList<QJsonObject>& items, const ContactMethod* cm)
{
TextRecording* t = new TextRecording();
TextRecording* t = new TextRecording();
//Load the history data
for (const QJsonObject& obj : items) {
Serializable::Peers* p = SerializableEntityManager::fromJson(obj,cm);
t->d_ptr->m_lAssociatedPeers << p;
}
//Load the history data
for (const QJsonObject& obj : items) {
Serializable::Peers* p = SerializableEntityManager::fromJson(obj,cm);
t->d_ptr->m_lAssociatedPeers << p;
}
//Create the model
t->instantMessagingModel();
//Reconstruct the conversation
//TODO do it right, right now it flatten the graph
for (const Serializable::Peers* p : t->d_ptr->m_lAssociatedPeers) {
for (const Serializable::Group* g : p->groups) {
for (Serializable::Message* m : g->messages) {
::TextMessageNode* n = new ::TextMessageNode();
n->m_pMessage = m ;
if (!n->m_pMessage->contactMethod) {
n->m_pMessage->contactMethod = const_cast<ContactMethod*>(cm); //TODO remove in 2016
n->m_pMessage->authorSha1 = cm->sha1();
if (p->peers.isEmpty())
addPeer(const_cast<Serializable::Peers*>(p), cm);
//Create the model
t->instantMessagingModel();
//Reconstruct the conversation
//TODO do it right, right now it flatten the graph
for (const Serializable::Peers* p : t->d_ptr->m_lAssociatedPeers) {
// TODO: for now assume the convo is with only 1 CM at a time
auto peerCM = p->peers.at(0)->m_pContactMethod;
// get the latest timestamp to set last used
time_t lastUsed = 0;
for (const Serializable::Group* g : p->groups) {
for (Serializable::Message* m : g->messages) {
::TextMessageNode* n = new ::TextMessageNode();
n->m_pMessage = m ;
if (!n->m_pMessage->contactMethod) {
if (cm) {
n->m_pMessage->contactMethod = const_cast<ContactMethod*>(cm); //TODO remove in 2016
n->m_pMessage->authorSha1 = cm->sha1();
if (p->peers.isEmpty())
addPeer(const_cast<Serializable::Peers*>(p), cm);
} else {
if (p->m_hSha1.contains(n->m_pMessage->authorSha1)) {
n->m_pMessage->contactMethod = p->m_hSha1[n->m_pMessage->authorSha1];
} else {
// message was outgoing and author sha1 was set to that of the sending account
n->m_pMessage->contactMethod = peerCM;
n->m_pMessage->authorSha1 = peerCM->sha1();
}
}
}
n->m_pContactMethod = m->contactMethod;
t->d_ptr->m_pImModel->addRowBegin();
t->d_ptr->m_lNodes << n;
t->d_ptr->m_pImModel->addRowEnd();
if (lastUsed < n->m_pMessage->timestamp)
lastUsed = n->m_pMessage->timestamp;
}
n->m_pContactMethod = m->contactMethod;
t->d_ptr->m_pImModel->addRowBegin();
t->d_ptr->m_lNodes << n;
t->d_ptr->m_pImModel->addRowEnd();
}
}
}
}
// update the timestamp of the CM
peerCM->setLastUsed(lastUsed);
}
return t;
return t;
}
void Media::TextRecordingPrivate::insertNewMessage(const QMap<QString,QString>& message, ContactMethod* cm, Media::Media::Direction direction)
......
......@@ -75,6 +75,7 @@ public:
bool isEmpty ( ) const;
bool hasMimeType ( const QString& mimeType ) const;
QStringList mimeTypes ( ) const;
QVector<ContactMethod*> peers ( ) const;
//Helper
void setAllRead();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment