summary refs log tree commit diff
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2021-01-27 02:45:33 +0100
committerNicolas Werner <nicolas.werner@hotmail.de>2021-02-09 20:22:02 +0100
commitd6504812c71ff7251a5319113c580ab322469eb3 (patch)
tree24779b1c76ea9d6555130347781dee6a9d8c133c
parentSwitch to new relations format (diff)
downloadnheko-d6504812c71ff7251a5319113c580ab322469eb3.tar.xz
Render edits
Diffstat (limited to '')
-rw-r--r--src/Cache.cpp30
-rw-r--r--src/Cache_p.h2
-rw-r--r--src/timeline/EventStore.cpp54
-rw-r--r--src/timeline/EventStore.h4
4 files changed, 86 insertions, 4 deletions
diff --git a/src/Cache.cpp b/src/Cache.cpp
index 94b9a6a6..49861a9a 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -108,6 +108,11 @@ Cache::isHiddenEvent(lmdb::txn &txn,
                      const std::string &room_id)
 {
         using namespace mtx::events;
+
+        // Always hide edits
+        if (mtx::accessors::relations(e).replaces())
+                return true;
+
         if (auto encryptedEvent = std::get_if<EncryptedEvent<msg::Encrypted>>(&e)) {
                 MegolmSessionIndex index;
                 index.room_id    = room_id;
@@ -1891,6 +1896,31 @@ Cache::getTimelineIndex(const std::string &room_id, std::string_view event_id)
         return *val.data<uint64_t>();
 }
 
+std::optional<uint64_t>
+Cache::getArrivalIndex(const std::string &room_id, std::string_view event_id)
+{
+        auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
+
+        lmdb::dbi orderDb{0};
+        try {
+                orderDb = getEventToOrderDb(txn, room_id);
+        } catch (lmdb::runtime_error &e) {
+                nhlog::db()->error("Can't open db for room '{}', probably doesn't exist yet. ({})",
+                                   room_id,
+                                   e.what());
+                return {};
+        }
+
+        lmdb::val indexVal{event_id.data(), event_id.size()}, val;
+
+        bool success = lmdb::dbi_get(txn, orderDb, indexVal, val);
+        if (!success) {
+                return {};
+        }
+
+        return *val.data<uint64_t>();
+}
+
 std::optional<std::string>
 Cache::getTimelineEventId(const std::string &room_id, uint64_t index)
 {
diff --git a/src/Cache_p.h b/src/Cache_p.h
index e2ce1668..c96a3f30 100644
--- a/src/Cache_p.h
+++ b/src/Cache_p.h
@@ -205,6 +205,8 @@ public:
         std::optional<uint64_t> getTimelineIndex(const std::string &room_id,
                                                  std::string_view event_id);
         std::optional<std::string> getTimelineEventId(const std::string &room_id, uint64_t index);
+        std::optional<uint64_t> getArrivalIndex(const std::string &room_id,
+                                                std::string_view event_id);
 
         std::string previousBatchToken(const std::string &room_id);
         uint64_t saveOldMessages(const std::string &room_id, const mtx::responses::Messages &res);
diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp
index 4a90222f..ebf2f024 100644
--- a/src/timeline/EventStore.cpp
+++ b/src/timeline/EventStore.cpp
@@ -405,6 +405,41 @@ EventStore::handle_room_verification(mtx::events::collections::TimelineEvents ev
           event);
 }
 
+std::vector<mtx::events::collections::TimelineEvents>
+EventStore::edits(const std::string &event_id)
+{
+        auto event_ids = cache::client()->relatedEvents(room_id_, event_id);
+
+        auto original_event = get(event_id, "", false, false);
+        if (!original_event)
+                return {};
+
+        auto original_sender = mtx::accessors::sender(*original_event);
+
+        std::vector<mtx::events::collections::TimelineEvents> edits;
+        for (const auto &id : event_ids) {
+                auto related_event = get(id, event_id, false, false);
+                if (!related_event)
+                        continue;
+
+                auto edit_rel = mtx::accessors::relations(*related_event);
+                if (edit_rel.replaces() == event_id &&
+                    original_sender == mtx::accessors::sender(*related_event))
+                        edits.push_back(*related_event);
+        }
+
+        auto c = cache::client();
+        std::sort(edits.begin(),
+                  edits.end(),
+                  [this, c](const mtx::events::collections::TimelineEvents &a,
+                            const mtx::events::collections::TimelineEvents &b) {
+                          return c->getArrivalIndex(this->room_id_, mtx::accessors::event_id(a)) <
+                                 c->getArrivalIndex(this->room_id_, mtx::accessors::event_id(b));
+                  });
+
+        return edits;
+}
+
 QVariantList
 EventStore::reactions(const std::string &event_id)
 {
@@ -487,7 +522,13 @@ EventStore::get(int idx, bool decrypt)
                 if (!event_id)
                         return nullptr;
 
-                auto event = cache::client()->getEvent(room_id_, *event_id);
+                std::optional<mtx::events::collections::TimelineEvent> event;
+                auto edits_ = edits(*event_id);
+                if (edits_.empty())
+                        event = cache::client()->getEvent(room_id_, *event_id);
+                else
+                        event = {edits_.back()};
+
                 if (!event)
                         return nullptr;
                 else
@@ -714,7 +755,7 @@ EventStore::decryptEvent(const IdIndex &idx,
 }
 
 mtx::events::collections::TimelineEvents *
-EventStore::get(std::string_view id, std::string_view related_to, bool decrypt)
+EventStore::get(std::string_view id, std::string_view related_to, bool decrypt, bool resolve_edits)
 {
         if (this->thread() != QThread::currentThread())
                 nhlog::db()->warn("{} called from a different thread!", __func__);
@@ -722,7 +763,14 @@ EventStore::get(std::string_view id, std::string_view related_to, bool decrypt)
         if (id.empty())
                 return nullptr;
 
-        IdIndex index{room_id_, std::string(id.data(), id.size())};
+        std::string id_ = std::string(id);
+        if (resolve_edits) {
+                auto edits_ = edits(id_);
+                if (!edits_.empty())
+                        id_ = mtx::accessors::event_id(edits_.back());
+        }
+
+        IdIndex index{room_id_, id_};
 
         auto event_ptr = events_by_id_.object(index);
         if (!event_ptr) {
diff --git a/src/timeline/EventStore.h b/src/timeline/EventStore.h
index f8eff9a9..ced7bdc0 100644
--- a/src/timeline/EventStore.h
+++ b/src/timeline/EventStore.h
@@ -66,7 +66,8 @@ public:
         // relatedFetched event
         mtx::events::collections::TimelineEvents *get(std::string_view id,
                                                       std::string_view related_to,
-                                                      bool decrypt = true);
+                                                      bool decrypt       = true,
+                                                      bool resolve_edits = true);
         // always returns a proper event as long as the idx is valid
         mtx::events::collections::TimelineEvents *get(int idx, bool decrypt = true);
 
@@ -110,6 +111,7 @@ public slots:
         void clearTimeline();
 
 private:
+        std::vector<mtx::events::collections::TimelineEvents> edits(const std::string &event_id);
         mtx::events::collections::TimelineEvents *decryptEvent(
           const IdIndex &idx,
           const mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> &e);