From 96c00ff019b3fe41582e3e25b30d4bdfaa6c9a09 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois-Simon=20Fauteux-Chapleau?=
 <francois-simon.fauteux-chapleau@savoirfairelinux.com>
Date: Thu, 22 Aug 2024 11:22:16 -0400
Subject: [PATCH] interaction: set body and transferStatus of DATA_TRANSFER
 messages

This patch adds code in the interaction::Info::init function so that the
"body" and "transferStatus" fields are always set when an Info struct is
constructed for a message of type DATA_TRANSFER.

This removes some code duplication in conversationmodel.cpp, where these
fields were being set as an extra step after construction in three
different places.

It also fixes a bug in the ConversationModelPimpl::slotMessageUpdated
function, which did *not* set the "body" of DATA_TRANSFER messages. The
body was therefore empty instead of containing a file path, which is
what caused the image preview bug described in the following issue:
GitLab: #1671

The patch also reverts a change that was made in the
MessageListModel::update function by commit
d2eba1d91ebd25362364699200421912bd77bb66. This change was a workaround
for the above bug, but it is no longer necessary (and it broke message
deletion, which relies on the body of the deleted message being set to
the empty string).
GitLab: #1825

Change-Id: I5848b93a12c1ef7b3735c5c6db6b32a9bbc4041d
---
 src/libclient/api/interaction.h     | 41 ++++++++++++++++---
 src/libclient/conversationmodel.cpp | 61 +++--------------------------
 src/libclient/messagelistmodel.cpp  |  7 +---
 3 files changed, 43 insertions(+), 66 deletions(-)

diff --git a/src/libclient/api/interaction.h b/src/libclient/api/interaction.h
index f4ff6074c..5c184305e 100644
--- a/src/libclient/api/interaction.h
+++ b/src/libclient/api/interaction.h
@@ -20,9 +20,11 @@
 
 #include <QString>
 #include <QObject>
+#include <QFileInfo>
 
 #include <ctime>
 #include "typedefs.h"
+#include "../dbus/configurationmanager.h"
 
 namespace lrc {
 
@@ -454,7 +456,10 @@ struct Info
         return status == Status::SUCCESS || status == Status::DISPLAYED;
     }
 
-    void init(const MapStringString& message, const QString& accountURI)
+    void init(const MapStringString& message,
+              const QString& accountURI,
+              const QString& accountId,
+              const QString& conversationId)
     {
         type = to_type(message["type"]);
         if (message.contains("react-to") && type == Type::TEXT) {
@@ -482,16 +487,42 @@ struct Info
             duration = message["duration"].toInt() / 1000;
             if (message.contains("confId"))
                 confId = message["confId"];
+        } else if (type == Type::DATA_TRANSFER) {
+            QString path;
+            qlonglong bytesProgress, totalSize;
+            ConfigurationManager::instance().fileTransferInfo(accountId,
+                                                               conversationId,
+                                                               message["fileId"],
+                                                               path,
+                                                               totalSize,
+                                                               bytesProgress);
+            QFileInfo fi(path);
+            body = fi.isSymLink() ? fi.symLinkTarget() : path;
+            transferStatus = bytesProgress == 0 ? TransferStatus::TRANSFER_AWAITING_HOST
+                           : bytesProgress == totalSize ? TransferStatus::TRANSFER_FINISHED
+                                                            : TransferStatus::TRANSFER_ONGOING;
+
         }
         commit = message;
     }
 
-    Info(const MapStringString& message, const QString& accountURI)
+    // NOTE: The `accountId` and `conversationId` arguments are only used for messages of
+    // type DATA_TRANSFER. They can therefore be omitted if the caller knows that `message`
+    // is of a different type. They must be provided otherwise, as failure to do so would
+    // result in the `body` and `transferStatus` fields of the returned Info struct to
+    // contain incorrect information whenever `message` is of type DATA_TRANSFER.
+    Info(const MapStringString& message,
+         const QString& accountURI,
+         const QString& accountId = "",
+         const QString& conversationId = "")
     {
-        init(message, accountURI);
+        init(message, accountURI, accountId, conversationId);
     }
 
-    Info(const SwarmMessage& msg, const QString& accountUri)
+    Info(const SwarmMessage& msg,
+         const QString& accountUri,
+         const QString& accountId,
+         const QString& conversationId)
     {
         MapStringString msgBody;
         for (auto it = msg.body.cbegin(); it != msg.body.cend(); ++it) {
@@ -499,7 +530,7 @@ struct Info
             const auto& value = it.value();
             msgBody.insert(key, value);
         }
-        init(msgBody, accountUri);
+        init(msgBody, accountUri, accountId, conversationId);
         parentId = msg.linearizedParent;
         type = to_type(msg.type);
         for (const auto& edition : msg.editions)
diff --git a/src/libclient/conversationmodel.cpp b/src/libclient/conversationmodel.cpp
index bfcf74251..6c182309e 100644
--- a/src/libclient/conversationmodel.cpp
+++ b/src/libclient/conversationmodel.cpp
@@ -2285,31 +2285,14 @@ ConversationModelPimpl::slotSwarmLoaded(uint32_t requestId,
         auto& conversation = getConversationForUid(conversationId).get();
         for (const auto& message : messages) {
             QString msgId = message.id;
-            auto msg = interaction::Info(message, linked.owner.profileInfo.uri);
+            auto msg = interaction::Info(message, linked.owner.profileInfo.uri, accountId, conversationId);
             auto downloadFile = false;
             if (msg.type == interaction::Type::INITIAL) {
                 allLoaded = true;
             } else if (msg.type == interaction::Type::DATA_TRANSFER) {
                 QString fileId = message.body.value("fileId");
-                QString path;
-                qlonglong bytesProgress, totalSize;
-                linked.owner.dataTransferModel->fileTransferInfo(accountId,
-                                                                 conversationId,
-                                                                 fileId,
-                                                                 path,
-                                                                 totalSize,
-                                                                 bytesProgress);
-                QFileInfo fi(path);
-                if (fi.isSymLink()) {
-                    msg.body = fi.symLinkTarget();
-                } else {
-                    msg.body = path;
-                }
-                msg.transferStatus = bytesProgress == 0 ? interaction::TransferStatus::TRANSFER_AWAITING_HOST
-                                   : bytesProgress == totalSize ? interaction::TransferStatus::TRANSFER_FINISHED
-                                                                : interaction::TransferStatus::TRANSFER_ONGOING;
                 linked.owner.dataTransferModel->registerTransferId(fileId, msgId);
-                downloadFile = (bytesProgress == 0);
+                downloadFile = (msg.transferStatus == interaction::TransferStatus::TRANSFER_AWAITING_HOST);
             }
 
             // If message is loaded, insert message at beginning
@@ -2351,25 +2334,12 @@ ConversationModelPimpl::slotMessagesFound(uint32_t requestId,
     QMap<QString, interaction::Info> messageDetailedInformation;
     if (requestId == mediaResearchRequestId) {
         Q_FOREACH (const MapStringString& msg, messageIds) {
-            auto intInfo = interaction::Info(msg, "");
-            if (intInfo.type == interaction::Type::DATA_TRANSFER) {
-                auto fileId = msg["fileId"];
-
-                QString path;
-                qlonglong bytesProgress, totalSize;
-                linked.owner.dataTransferModel->fileTransferInfo(accountId,
-                                                                 conversationId,
-                                                                 fileId,
-                                                                 path,
-                                                                 totalSize,
-                                                                 bytesProgress);
-                intInfo.body = path;
-            }
+            auto intInfo = interaction::Info(msg, "", accountId, conversationId);
             messageDetailedInformation[msg["id"]] = std::move(intInfo);
         }
     } else if (requestId == msgResearchRequestId) {
         Q_FOREACH (const MapStringString& msg, messageIds) {
-            auto intInfo = interaction::Info(msg, "");
+            auto intInfo = interaction::Info(msg, "", accountId, conversationId);
             if (intInfo.type == interaction::Type::TEXT) {
                 messageDetailedInformation[msg["id"]] = std::move(intInfo);
             }
@@ -2395,33 +2365,14 @@ ConversationModelPimpl::slotMessageReceived(const QString& accountId,
             }
         }
         QString msgId = message.id;
-        auto msg = interaction::Info(message, linked.owner.profileInfo.uri);
+        auto msg = interaction::Info(message, linked.owner.profileInfo.uri, accountId, conversationId);
 
         if (msg.type == interaction::Type::CALL) {
             msg.body = interaction::getCallInteractionString(msg.authorUri
                                                                  == linked.owner.profileInfo.uri,
                                                              msg);
         } else if (msg.type == interaction::Type::DATA_TRANSFER) {
-            // save data transfer interaction to db and assosiate daemon id with interaction id,
-            // conversation id and db id
             QString fileId = message.body.value("fileId");
-            QString path;
-            qlonglong bytesProgress, totalSize;
-            linked.owner.dataTransferModel->fileTransferInfo(accountId,
-                                                             conversationId,
-                                                             fileId,
-                                                             path,
-                                                             totalSize,
-                                                             bytesProgress);
-            QFileInfo fi(path);
-            if (fi.isSymLink()) {
-                msg.body = fi.symLinkTarget();
-            } else {
-                msg.body = path;
-            }
-            msg.transferStatus = bytesProgress == 0         ? interaction::TransferStatus::TRANSFER_AWAITING_HOST
-                               : bytesProgress == totalSize ? interaction::TransferStatus::TRANSFER_FINISHED
-                                                            : interaction::TransferStatus::TRANSFER_ONGOING;
             linked.owner.dataTransferModel->registerTransferId(fileId, msgId);
         }
 
@@ -2473,7 +2424,7 @@ ConversationModelPimpl::slotMessageUpdated(const QString& accountId,
     try {
         auto& conversation = getConversationForUid(conversationId).get();
         QString msgId = message.id;
-        auto msg = interaction::Info(message, linked.owner.profileInfo.uri);
+        auto msg = interaction::Info(message, linked.owner.profileInfo.uri, accountId, conversationId);
 
         if (!conversation.interactions->update(msgId, msg)) {
             qDebug() << "Message not found or cannot be reparented.";
diff --git a/src/libclient/messagelistmodel.cpp b/src/libclient/messagelistmodel.cpp
index 75c4299f3..be4ae6c49 100644
--- a/src/libclient/messagelistmodel.cpp
+++ b/src/libclient/messagelistmodel.cpp
@@ -201,12 +201,7 @@ MessageListModel::update(const QString& id, const interaction::Info& interaction
             return true;
         }
     }
-    // TODO: look into why this update with an empty body is broadcasted just
-    // after loading the messages. This is a workaround to avoid the empty
-    // file transfer path. Until then, don't update the body if it's empty.
-    if (!interaction.body.isEmpty()) {
-        current.body = interaction.body;
-    }
+    current.body = interaction.body;
     current.commit = interaction.commit;
     current.previousBodies = interaction.previousBodies;
     current.parsedBody = interaction.parsedBody;
-- 
GitLab