summary refs log tree commit diff
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2023-05-19 23:06:14 +0200
committerNicolas Werner <nicolas.werner@hotmail.de>2023-05-20 00:57:51 +0200
commit7fab9a1d73e628ca2371d2215b0198806aa85e94 (patch)
tree4c4e529617cae41a5d3c4ab0574f5cecf0c12f80
parentFix adding duplicate stickers and strip file extension (diff)
downloadnheko-7fab9a1d73e628ca2371d2215b0198806aa85e94.tar.xz
Prevent new packs from overwriting the default pack by accident
-rw-r--r--src/ImagePackListModel.cpp4
-rw-r--r--src/SingleImagePackModel.cpp42
-rw-r--r--src/SingleImagePackModel.h2
3 files changed, 47 insertions, 1 deletions
diff --git a/src/ImagePackListModel.cpp b/src/ImagePackListModel.cpp
index 368acd8c..4cf807a9 100644
--- a/src/ImagePackListModel.cpp
+++ b/src/ImagePackListModel.cpp
@@ -82,8 +82,10 @@ SingleImagePackModel *
 ImagePackListModel::newPack(bool inRoom)
 {
     ImagePackInfo info{};
-    if (inRoom)
+    if (inRoom) {
         info.source_room = room_id;
+        info.state_key   = SingleImagePackModel::unconflictingStatekey(room_id, "");
+    }
     return new SingleImagePackModel(info);
 }
 
diff --git a/src/SingleImagePackModel.cpp b/src/SingleImagePackModel.cpp
index b26396ba..99338f2e 100644
--- a/src/SingleImagePackModel.cpp
+++ b/src/SingleImagePackModel.cpp
@@ -8,6 +8,8 @@
 #include <QFileInfo>
 #include <QMimeDatabase>
 
+#include <unordered_set>
+
 #include <mtx/responses/media.hpp>
 
 #include "Cache_p.h"
@@ -237,6 +239,12 @@ SingleImagePackModel::setStatekey(QString val)
     auto val_ = val.toStdString();
     if (val_ != statekey_) {
         statekey_ = val_;
+
+        // prevent deleting current pack
+        if (!roomid_.empty() && statekey_ != old_statekey_) {
+            statekey_ = unconflictingStatekey(roomid_, statekey_);
+        }
+
         emit statekeyChanged();
     }
 }
@@ -290,6 +298,7 @@ SingleImagePackModel::save()
                         tr("Failed to delete old image pack: %1")
                           .arg(QString::fromStdString(e->matrix_error.error)));
               });
+            old_statekey_ = statekey_;
         }
 
         http::client()->send_state_event(
@@ -398,6 +407,7 @@ std::string
 SingleImagePackModel::unconflictingShortcode(const std::string &shortcode)
 {
     if (pack.images.count(shortcode)) {
+        // more images won't fit in an event anyway
         for (int i = 0; i < 64'000; i++) {
             auto tempCode = shortcode + std::to_string(i);
             if (!pack.images.count(tempCode)) {
@@ -408,6 +418,38 @@ SingleImagePackModel::unconflictingShortcode(const std::string &shortcode)
     return shortcode;
 }
 
+std::string
+SingleImagePackModel::unconflictingStatekey(const std::string &roomid, const std::string &key)
+{
+    if (roomid.empty())
+        return key;
+
+    std::unordered_set<std::string> statekeys;
+    auto currentPacks =
+      cache::client()->getStateEventsWithType<mtx::events::msc2545::ImagePack>(roomid);
+    for (const auto &pack : currentPacks) {
+        if (!pack.content.images.empty())
+            statekeys.insert(pack.state_key);
+    }
+    auto defaultPack = cache::client()->getStateEvent<mtx::events::msc2545::ImagePack>(roomid);
+    if (defaultPack && defaultPack->content.images.size()) {
+        statekeys.insert(defaultPack->state_key);
+    }
+
+    if (statekeys.count(key)) {
+        // arbitrary count. More than 64k image packs in a room are unlikely and if you have that,
+        // you probably know what you are doing :)
+        for (int i = 0; i < 64'000; i++) {
+            auto tempCode = key + std::to_string(i);
+            if (!statekeys.count(tempCode)) {
+                return tempCode;
+            }
+        }
+    }
+
+    return key;
+}
+
 void
 SingleImagePackModel::addImageCb(std::string uri, std::string filename, mtx::common::ImageInfo info)
 {
diff --git a/src/SingleImagePackModel.h b/src/SingleImagePackModel.h
index 65a27bcf..595f5a78 100644
--- a/src/SingleImagePackModel.h
+++ b/src/SingleImagePackModel.h
@@ -71,6 +71,8 @@ public:
     Q_INVOKABLE void remove(int index);
     Q_INVOKABLE void setAvatar(QUrl file);
 
+    static std::string unconflictingStatekey(const std::string &roomid, const std::string &key);
+
 signals:
     void globallyEnabledChanged();
     void statekeyChanged();