From d8c0d4874bb1864a677ae451d93727ab75484f84 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 11 Jun 2021 13:12:43 +0200 Subject: Render community items --- src/Cache.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/Cache.cpp') diff --git a/src/Cache.cpp b/src/Cache.cpp index 4a99dd59..5684de37 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -3451,6 +3451,10 @@ Cache::updateUserKeys(const std::string &sync_token, const mtx::responses::Query if (!updateToWrite.master_keys.keys.empty() && update.master_keys.keys != updateToWrite.master_keys.keys) { + nhlog::db()->debug("Master key of {} changed:\nold: {}\nnew: {}", + user, + updateToWrite.master_keys.keys.size(), + update.master_keys.keys.size()); updateToWrite.master_key_changed = true; } -- cgit 1.5.1 From e6878ee298525ac7808595418c4b84b93788ff2e Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 12 Jun 2021 16:05:45 +0200 Subject: Don't read avatarUrl from local profile, if no global avatar is set --- resources/qml/RoomList.qml | 12 +++++++----- src/Cache.cpp | 3 ++- src/ui/UserProfile.cpp | 8 +++----- 3 files changed, 12 insertions(+), 11 deletions(-) (limited to 'src/Cache.cpp') diff --git a/resources/qml/RoomList.qml b/resources/qml/RoomList.qml index 09fb3701..f31fce60 100644 --- a/resources/qml/RoomList.qml +++ b/resources/qml/RoomList.qml @@ -447,6 +447,8 @@ Page { RowLayout { id: userInfoGrid + property var profile: Nheko.currentUser + spacing: Nheko.paddingMedium anchors.fill: parent anchors.margins: Nheko.paddingMedium @@ -457,9 +459,9 @@ Page { Layout.alignment: Qt.AlignVCenter Layout.preferredWidth: fontMetrics.lineSpacing * 2 Layout.preferredHeight: fontMetrics.lineSpacing * 2 - url: Nheko.currentUser.avatarUrl.replace("mxc://", "image://MxcImage/") - displayName: Nheko.currentUser.displayName - userid: Nheko.currentUser.userid + url: (userInfoGrid.profile ? userInfoGrid.profile.avatarUrl : "").replace("mxc://", "image://MxcImage/") + displayName: userInfoGrid.profile ? userInfoGrid.profile.displayName : "" + userid: userInfoGrid.profile ? userInfoGrid.profile.userid : "" } ColumnLayout { @@ -476,7 +478,7 @@ Page { Layout.alignment: Qt.AlignBottom font.pointSize: fontMetrics.font.pointSize * 1.1 font.weight: Font.DemiBold - fullText: Nheko.currentUser.displayName + fullText: userInfoGrid.profile ? userInfoGrid.profile.displayName : "" elideWidth: col.width } @@ -486,7 +488,7 @@ Page { font.weight: Font.Thin font.pointSize: fontMetrics.font.pointSize * 0.9 elideWidth: col.width - fullText: Nheko.currentUser.userid + fullText: userInfoGrid.profile ? userInfoGrid.profile.userid : "" } } diff --git a/src/Cache.cpp b/src/Cache.cpp index 5684de37..0d75ac51 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -2479,7 +2479,8 @@ Cache::getMember(const std::string &room_id, const std::string &user_id) return m; } } catch (std::exception &e) { - nhlog::db()->warn("Failed to read member ({}): {}", user_id, e.what()); + nhlog::db()->warn( + "Failed to read member ({}) in room ({}): {}", user_id, room_id, e.what()); } return std::nullopt; } diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp index da130242..3d9c4b6a 100644 --- a/src/ui/UserProfile.cpp +++ b/src/ui/UserProfile.cpp @@ -39,7 +39,8 @@ UserProfile::UserProfile(QString roomid, getGlobalProfileData(); } - if (!cache::client() || !cache::client()->isDatabaseReady()) + if (!cache::client() || !cache::client()->isDatabaseReady() || + !ChatPage::instance()->timelineManager()) return; connect(cache::client(), @@ -127,10 +128,7 @@ UserProfile::displayName() QString UserProfile::avatarUrl() { - return (isGlobalUserProfile() && globalAvatarUrl != "") - ? globalAvatarUrl - : cache::avatarUrl(roomid_, userid_); - ; + return isGlobalUserProfile() ? globalAvatarUrl : cache::avatarUrl(roomid_, userid_); } bool -- cgit 1.5.1 From 9f798e76ede3672d91276b1be7dd20de5459c9df Mon Sep 17 00:00:00 2001 From: Alexander Bantyev Date: Thu, 17 Jun 2021 22:27:37 +0300 Subject: Allow editing unsent messages As of 0db4d71ec2483c7ac5a7b536737fee8fc53a76d7 (Prevent edits of unsent messages), messages that are edits of (or replies to) unsent messages were not allowed. This change was made because otherwise the edits were discarded due to use of txnid rather than mxid in the "m.relates_to" object. Remove this restriction and fix the issue by replacing txnid with mxid in all related events when the message is sent (and we obtain mxid from the server). --- src/Cache.cpp | 21 +++++++++++++++++++++ src/Cache_p.h | 3 +++ src/timeline/EventStore.cpp | 32 ++++++++++++++++++++++++++++++++ src/timeline/TimelineModel.cpp | 18 +++++++++++------- 4 files changed, 67 insertions(+), 7 deletions(-) (limited to 'src/Cache.cpp') diff --git a/src/Cache.cpp b/src/Cache.cpp index 0d75ac51..2178bbfb 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -1681,6 +1681,27 @@ Cache::storeEvent(const std::string &room_id, txn.commit(); } +void +Cache::replaceEvent(const std::string &room_id, + const std::string &event_id, + const mtx::events::collections::TimelineEvent &event) +{ + auto txn = lmdb::txn::begin(env_); + auto eventsDb = getEventsDb(txn, room_id); + auto relationsDb = getRelationsDb(txn, room_id); + auto event_json = mtx::accessors::serialize_event(event.data).dump(); + + { + eventsDb.del(txn, event_id); + eventsDb.put(txn, event_id, event_json); + for (auto relation : mtx::accessors::relations(event.data).relations) { + relationsDb.put(txn, relation.event_id, event_id); + } + } + + txn.commit(); +} + std::vector Cache::relatedEvents(const std::string &room_id, const std::string &event_id) { diff --git a/src/Cache_p.h b/src/Cache_p.h index f2911622..669f1895 100644 --- a/src/Cache_p.h +++ b/src/Cache_p.h @@ -184,6 +184,9 @@ public: void storeEvent(const std::string &room_id, const std::string &event_id, const mtx::events::collections::TimelineEvent &event); + void replaceEvent(const std::string &room_id, + const std::string &event_id, + const mtx::events::collections::TimelineEvent &event); std::vector relatedEvents(const std::string &room_id, const std::string &event_id); diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp index 4a9f0fff..3667433b 100644 --- a/src/timeline/EventStore.cpp +++ b/src/timeline/EventStore.cpp @@ -185,6 +185,33 @@ EventStore::EventStore(std::string room_id, QObject *) [this](std::string txn_id, std::string event_id) { nhlog::ui()->debug("sent {}", txn_id); + // Replace the event_id in pending edits/replies/redactions with the actual + // event_id of this event + for (auto related_event_id : cache::client()->relatedEvents(room_id_, txn_id)) { + if (cache::client()->getEvent(room_id_, related_event_id)) { + auto related_event = + cache::client()->getEvent(room_id_, related_event_id).value(); + auto relations = mtx::accessors::relations(related_event.data); + + for (mtx::common::Relation &rel : relations.relations) { + if (rel.event_id == txn_id) + rel.event_id = event_id; + } + + mtx::accessors::set_relations(related_event.data, relations); + + cache::client()->replaceEvent( + room_id_, related_event_id, related_event); + + auto id = idToIndex(event_id); + + events_by_id_.remove({room_id_, related_event_id}); + events_.remove({room_id_, toInternalIdx(*id)}); + + emit dataChanged(*id, *id); + } + } + http::client()->read_event( room_id_, event_id, [this, event_id](mtx::http::RequestErr err) { if (err) { @@ -193,6 +220,11 @@ EventStore::EventStore(std::string room_id, QObject *) } }); + auto id = idToIndex(event_id); + + if (id) + emit dataChanged(id.value(), id.value()); + cache::client()->removePendingStatus(room_id_, txn_id); this->current_txn = ""; this->current_txn_error_count = 0; diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index f29f929e..e2e5551b 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -375,6 +375,15 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj connect(&events, &EventStore::updateFlowEventId, this, [this](std::string event_id) { this->updateFlowEventId(event_id); }); + connect(&events, + &EventStore::messageSent, + this, + [this](std::string txn_id, std::string event_id) { + if (edit_.toStdString() == txn_id) { + edit_ = QString::fromStdString(event_id); + emit editChanged(edit_); + } + }); showEventTimer.callOnTimeout(this, &TimelineModel::scrollTimerEvent); } @@ -568,10 +577,8 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r case IsEdited: return QVariant(relations(event).replaces().has_value()); case IsEditable: - return QVariant(!is_state_event(event) && - mtx::accessors::sender(event) == - http::client()->user_id().to_string() && - !event_id(event).empty() && event_id(event).front() == '$'); + return QVariant(!is_state_event(event) && mtx::accessors::sender(event) == + http::client()->user_id().to_string()); case IsEncrypted: { auto id = event_id(event); auto encrypted_event = events.get(id, "", false); @@ -1796,9 +1803,6 @@ TimelineModel::formatMemberEvent(QString id) void TimelineModel::setEdit(QString newEdit) { - if (edit_.startsWith('m')) - return; - if (newEdit.isEmpty()) { resetEdit(); return; -- cgit 1.5.1 From 12ce7686ce8a7cae411c280d30a12934b8707550 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Wed, 16 Jun 2021 00:09:45 +0200 Subject: Show some spaces in the community sidebar --- src/Cache.cpp | 321 ++++++++++++++++++++++++++++---------- src/Cache.h | 6 - src/CacheStructs.h | 2 + src/Cache_p.h | 72 +++++++-- src/timeline/CommunitiesModel.cpp | 42 +++-- src/timeline/CommunitiesModel.h | 4 + 6 files changed, 341 insertions(+), 106 deletions(-) (limited to 'src/Cache.cpp') diff --git a/src/Cache.cpp b/src/Cache.cpp index 2178bbfb..0bd6fe0d 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -55,6 +55,10 @@ constexpr auto BATCH_SIZE = 100; //! Format: room_id -> RoomInfo constexpr auto ROOMS_DB("rooms"); constexpr auto INVITES_DB("invites"); +//! maps each room to its parent space (id->id) +constexpr auto SPACES_PARENTS_DB("space_parents"); +//! maps each space to its current children (id->id) +constexpr auto SPACES_CHILDREN_DB("space_children"); //! Information that must be kept between sync requests. constexpr auto SYNC_STATE_DB("sync_state"); //! Read receipts per room/event. @@ -237,12 +241,14 @@ Cache::setup() env_.open(cacheDirectory_.toStdString().c_str()); } - auto txn = lmdb::txn::begin(env_); - syncStateDb_ = lmdb::dbi::open(txn, SYNC_STATE_DB, MDB_CREATE); - roomsDb_ = lmdb::dbi::open(txn, ROOMS_DB, MDB_CREATE); - invitesDb_ = lmdb::dbi::open(txn, INVITES_DB, MDB_CREATE); - readReceiptsDb_ = lmdb::dbi::open(txn, READ_RECEIPTS_DB, MDB_CREATE); - notificationsDb_ = lmdb::dbi::open(txn, NOTIFICATIONS_DB, MDB_CREATE); + auto txn = lmdb::txn::begin(env_); + syncStateDb_ = lmdb::dbi::open(txn, SYNC_STATE_DB, MDB_CREATE); + roomsDb_ = lmdb::dbi::open(txn, ROOMS_DB, MDB_CREATE); + spacesChildrenDb_ = lmdb::dbi::open(txn, SPACES_CHILDREN_DB, MDB_CREATE | MDB_DUPSORT); + spacesParentsDb_ = lmdb::dbi::open(txn, SPACES_PARENTS_DB, MDB_CREATE | MDB_DUPSORT); + invitesDb_ = lmdb::dbi::open(txn, INVITES_DB, MDB_CREATE); + readReceiptsDb_ = lmdb::dbi::open(txn, READ_RECEIPTS_DB, MDB_CREATE); + notificationsDb_ = lmdb::dbi::open(txn, NOTIFICATIONS_DB, MDB_CREATE); // Device management devicesDb_ = lmdb::dbi::open(txn, DEVICES_DB, MDB_CREATE); @@ -1194,6 +1200,9 @@ Cache::saveState(const mtx::responses::Sync &res) auto userKeyCacheDb = getUserKeysDb(txn); + std::set spaces_with_updates; + std::set rooms_with_space_updates; + // Save joined rooms for (const auto &room : res.rooms.join) { auto statesdb = getStatesDb(txn, room.first); @@ -1212,6 +1221,41 @@ Cache::saveState(const mtx::responses::Sync &res) updatedInfo.topic = getRoomTopic(txn, statesdb).toStdString(); updatedInfo.avatar_url = getRoomAvatarUrl(txn, statesdb, membersdb).toStdString(); updatedInfo.version = getRoomVersion(txn, statesdb).toStdString(); + updatedInfo.is_space = getRoomIsSpace(txn, statesdb); + + if (updatedInfo.is_space) { + bool space_updates = false; + for (const auto &e : room.second.state.events) + if (std::holds_alternative>(e) || + std::holds_alternative>(e)) + space_updates = true; + for (const auto &e : room.second.timeline.events) + if (std::holds_alternative>(e) || + std::holds_alternative>(e)) + space_updates = true; + + if (space_updates) + spaces_with_updates.insert(room.first); + } + + { + bool room_has_space_update = false; + for (const auto &e : room.second.state.events) { + if (auto se = std::get_if>(&e)) { + spaces_with_updates.insert(se->state_key); + room_has_space_update = true; + } + } + for (const auto &e : room.second.timeline.events) { + if (auto se = std::get_if>(&e)) { + spaces_with_updates.insert(se->state_key); + room_has_space_update = true; + } + } + + if (room_has_space_update) + rooms_with_space_updates.insert(room.first); + } bool has_new_tags = false; // Process the account_data associated with this room @@ -1291,6 +1335,8 @@ Cache::saveState(const mtx::responses::Sync &res) removeLeftRooms(txn, res.rooms.leave); + updateSpaces(txn, spaces_with_updates, std::move(rooms_with_space_updates)); + txn.commit(); std::map readStatus; @@ -1339,6 +1385,7 @@ Cache::saveInvites(lmdb::txn &txn, const std::map -Cache::roomsWithTagUpdates(const mtx::responses::Sync &res) -{ - using namespace mtx::events; - - std::vector rooms; - for (const auto &room : res.rooms.join) { - bool hasUpdates = false; - for (const auto &evt : room.second.account_data.events) { - if (std::holds_alternative>(evt)) { - hasUpdates = true; - } - } - - if (hasUpdates) - rooms.emplace_back(room.first); - } - - return rooms; -} - RoomInfo Cache::singleRoomInfo(const std::string &room_id) { @@ -2337,6 +2363,29 @@ Cache::getRoomVersion(lmdb::txn &txn, lmdb::dbi &statesdb) return QString("1"); } +bool +Cache::getRoomIsSpace(lmdb::txn &txn, lmdb::dbi &statesdb) +{ + using namespace mtx::events; + using namespace mtx::events::state; + + std::string_view event; + bool res = statesdb.get(txn, to_string(mtx::events::EventType::RoomCreate), event); + + if (res) { + try { + StateEvent msg = json::parse(event); + + return msg.content.type == mtx::events::state::room_type::space; + } catch (const json::exception &e) { + nhlog::db()->warn("failed to parse m.room.create event: {}", e.what()); + } + } + + nhlog::db()->warn("m.room.create event is missing room version, assuming version \"1\""); + return false; +} + std::optional Cache::getRoomAliases(const std::string &roomid) { @@ -2464,6 +2513,27 @@ Cache::getInviteRoomTopic(lmdb::txn &txn, lmdb::dbi &db) return QString(); } +bool +Cache::getInviteRoomIsSpace(lmdb::txn &txn, lmdb::dbi &db) +{ + using namespace mtx::events; + using namespace mtx::events::state; + + std::string_view event; + bool res = db.get(txn, to_string(mtx::events::EventType::RoomCreate), event); + + if (res) { + try { + StrippedEvent msg = json::parse(event); + return msg.content.type == mtx::events::state::room_type::space; + } catch (const json::exception &e) { + nhlog::db()->warn("failed to parse m.room.topic event: {}", e.what()); + } + } + + return false; +} + std::vector Cache::joinedRooms() { @@ -2506,42 +2576,6 @@ Cache::getMember(const std::string &room_id, const std::string &user_id) return std::nullopt; } -std::vector -Cache::searchRooms(const std::string &query, std::uint8_t max_items) -{ - std::multimap> items; - - auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY); - auto cursor = lmdb::cursor::open(txn, roomsDb_); - - std::string_view room_id, room_data; - while (cursor.get(room_id, room_data, MDB_NEXT)) { - RoomInfo tmp = json::parse(room_data); - - const int score = utils::levenshtein_distance( - query, QString::fromStdString(tmp.name).toLower().toStdString()); - items.emplace(score, std::make_pair(room_id, tmp)); - } - - cursor.close(); - - auto end = items.begin(); - - if (items.size() >= max_items) - std::advance(end, max_items); - else if (items.size() > 0) - std::advance(end, items.size()); - - std::vector results; - for (auto it = items.begin(); it != end; it++) { - results.push_back(RoomSearchResult{it->second.first, it->second.second}); - } - - txn.commit(); - - return results; -} - std::vector Cache::getMembers(const std::string &room_id, std::size_t startIndex, std::size_t len) { @@ -3203,6 +3237,147 @@ Cache::deleteOldData() noexcept } } +void +Cache::updateSpaces(lmdb::txn &txn, + const std::set &spaces_with_updates, + std::set rooms_with_updates) +{ + if (spaces_with_updates.empty() && rooms_with_updates.empty()) + return; + + for (const auto &space : spaces_with_updates) { + // delete old entries + { + auto cursor = lmdb::cursor::open(txn, spacesChildrenDb_); + bool first = true; + std::string_view sp = space, space_child = ""; + + if (cursor.get(sp, space_child, MDB_SET)) { + while (cursor.get( + sp, space_child, first ? MDB_FIRST_DUP : MDB_NEXT_DUP)) { + first = false; + spacesParentsDb_.del(txn, space_child, space); + } + } + cursor.close(); + spacesChildrenDb_.del(txn, space); + } + + for (const auto &event : + getStateEventsWithType(txn, space)) { + if (event.content.via.has_value() && event.state_key.size() > 3 && + event.state_key.at(0) == '!') { + spacesChildrenDb_.put(txn, space, event.state_key); + spacesParentsDb_.put(txn, event.state_key, space); + } + } + } + + const auto space_event_type = to_string(mtx::events::EventType::RoomPowerLevels); + + for (const auto &room : rooms_with_updates) { + for (const auto &event : + getStateEventsWithType(txn, room)) { + if (event.content.via.has_value() && event.state_key.size() > 3 && + event.state_key.at(0) == '!') { + const std::string &space = event.state_key; + + auto pls = + getStateEvent(txn, space); + + if (!pls) + continue; + + if (pls->content.user_level(event.sender) >= + pls->content.state_level(space_event_type)) { + spacesChildrenDb_.put(txn, space, room); + spacesParentsDb_.put(txn, room, space); + } + } + } + } +} + +QMap> +Cache::spaces() +{ + auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY); + + QMap> ret; + { + auto cursor = lmdb::cursor::open(txn, spacesChildrenDb_); + bool first = true; + std::string_view space_id, space_child; + while (cursor.get(space_id, space_child, first ? MDB_FIRST : MDB_NEXT)) { + first = false; + + if (!space_child.empty()) { + std::string_view room_data; + if (roomsDb_.get(txn, space_id, room_data)) { + RoomInfo tmp = json::parse(std::move(room_data)); + ret.insert( + QString::fromUtf8(space_id.data(), space_id.size()), tmp); + } else { + ret.insert( + QString::fromUtf8(space_id.data(), space_id.size()), + std::nullopt); + } + } + } + cursor.close(); + } + + return ret; +} + +std::vector +Cache::getParentRoomIds(const std::string &room_id) +{ + auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY); + + std::vector roomids; + { + auto cursor = lmdb::cursor::open(txn, spacesParentsDb_); + bool first = true; + std::string_view sp = room_id, space_parent; + if (cursor.get(sp, space_parent, MDB_SET)) { + while (cursor.get(sp, space_parent, first ? MDB_FIRST_DUP : MDB_NEXT_DUP)) { + first = false; + + if (!space_parent.empty()) + roomids.emplace_back(space_parent); + } + } + cursor.close(); + } + + return roomids; +} + +std::vector +Cache::getChildRoomIds(const std::string &room_id) +{ + auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY); + + std::vector roomids; + { + auto cursor = lmdb::cursor::open(txn, spacesChildrenDb_); + bool first = true; + std::string_view sp = room_id, space_child; + if (cursor.get(sp, space_child, MDB_SET)) { + while (cursor.get(sp, space_child, first ? MDB_FIRST_DUP : MDB_NEXT_DUP)) { + first = false; + + if (!space_child.empty()) + roomids.emplace_back(space_child); + } + } + cursor.close(); + } + + return roomids; +} + std::optional Cache::getAccountData(lmdb::txn &txn, mtx::events::EventType type, const std::string &room_id) { @@ -3884,6 +4059,7 @@ to_json(json &j, const RoomInfo &info) j["avatar_url"] = info.avatar_url; j["version"] = info.version; j["is_invite"] = info.is_invite; + j["is_space"] = info.is_space; j["join_rule"] = info.join_rule; j["guest_access"] = info.guest_access; @@ -3903,6 +4079,7 @@ from_json(const json &j, RoomInfo &info) info.version = j.value( "version", QCoreApplication::translate("RoomInfo", "no version stored").toStdString()); info.is_invite = j.at("is_invite"); + info.is_space = j.value("is_space", false); info.join_rule = j.at("join_rule"); info.guest_access = j.at("guest_access"); @@ -4158,12 +4335,6 @@ getRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb) return instance_->getRoomAvatarUrl(txn, statesdb, membersdb); } -QString -getRoomVersion(lmdb::txn &txn, lmdb::dbi &statesdb) -{ - return instance_->getRoomVersion(txn, statesdb); -} - std::vector getMembers(const std::string &room_id, std::size_t startIndex, std::size_t len) { @@ -4305,11 +4476,7 @@ roomsWithStateUpdates(const mtx::responses::Sync &res) { return instance_->roomsWithStateUpdates(res); } -std::vector -roomsWithTagUpdates(const mtx::responses::Sync &res) -{ - return instance_->roomsWithTagUpdates(res); -} + std::map getRoomInfo(const std::vector &rooms) { @@ -4329,12 +4496,6 @@ calculateRoomReadStatus() instance_->calculateRoomReadStatus(); } -std::vector -searchRooms(const std::string &query, std::uint8_t max_items) -{ - return instance_->searchRooms(query, max_items); -} - void markSentNotification(const std::string &event_id) { diff --git a/src/Cache.h b/src/Cache.h index 74ec9695..b0520f6b 100644 --- a/src/Cache.h +++ b/src/Cache.h @@ -79,9 +79,6 @@ getRoomTopic(lmdb::txn &txn, lmdb::dbi &statesdb); //! Retrieve the room avatar's url if any. QString getRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb); -//! Retrieve the version of the room if any. -QString -getRoomVersion(lmdb::txn &txn, lmdb::dbi &statesdb); //! Retrieve member info from a room. std::vector @@ -166,9 +163,6 @@ calculateRoomReadStatus(const std::string &room_id); void calculateRoomReadStatus(); -std::vector -searchRooms(const std::string &query, std::uint8_t max_items = 5); - void markSentNotification(const std::string &event_id); //! Removes an event from the sent notifications. diff --git a/src/CacheStructs.h b/src/CacheStructs.h index f7d6f0e2..1d0f0d70 100644 --- a/src/CacheStructs.h +++ b/src/CacheStructs.h @@ -76,6 +76,8 @@ struct RoomInfo std::string version; //! Whether or not the room is an invite. bool is_invite = false; + //! Wheter or not the room is a space + bool is_space = false; //! Total number of members in the room. size_t member_count = 0; //! Who can access to the room. diff --git a/src/Cache_p.h b/src/Cache_p.h index 669f1895..064f4882 100644 --- a/src/Cache_p.h +++ b/src/Cache_p.h @@ -72,6 +72,7 @@ public: std::optional getRoomAliases(const std::string &roomid); QHash invites(); std::optional invite(std::string_view roomid); + QMap> spaces(); //! Calculate & return the name of the room. QString getRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb); @@ -84,6 +85,8 @@ public: QString getRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb); //! Retrieve the version of the room if any. QString getRoomVersion(lmdb::txn &txn, lmdb::dbi &statesdb); + //! Retrieve if the room is a space + bool getRoomIsSpace(lmdb::txn &txn, lmdb::dbi &statesdb); //! Get a specific state event template @@ -146,7 +149,6 @@ public: RoomInfo singleRoomInfo(const std::string &room_id); std::vector roomsWithStateUpdates(const mtx::responses::Sync &res); - std::vector roomsWithTagUpdates(const mtx::responses::Sync &res); std::map getRoomInfo(const std::vector &rooms); //! Calculates which the read status of a room. @@ -154,9 +156,6 @@ public: bool calculateRoomReadStatus(const std::string &room_id); void calculateRoomReadStatus(); - std::vector searchRooms(const std::string &query, - std::uint8_t max_items = 5); - void markSentNotification(const std::string &event_id); //! Removes an event from the sent notifications. void removeReadNotification(const std::string &event_id); @@ -222,6 +221,8 @@ public: void deleteOldData() noexcept; //! Retrieve all saved room ids. std::vector getRoomIds(lmdb::txn &txn); + std::vector getParentRoomIds(const std::string &room_id); + std::vector getChildRoomIds(const std::string &room_id); //! Mark a room that uses e2e encryption. void setEncryptedRoom(lmdb::txn &txn, const std::string &room_id); @@ -327,6 +328,7 @@ private: QString getInviteRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb); QString getInviteRoomTopic(lmdb::txn &txn, lmdb::dbi &statesdb); QString getInviteRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb); + bool getInviteRoomIsSpace(lmdb::txn &txn, lmdb::dbi &db); std::optional getMember(const std::string &room_id, const std::string &user_id); @@ -430,20 +432,22 @@ private: if (room_id.empty()) return std::nullopt; + const auto typeStr = to_string(type); std::string_view value; if (state_key.empty()) { auto db = getStatesDb(txn, room_id); - if (!db.get(txn, to_string(type), value)) { + if (!db.get(txn, typeStr, value)) { return std::nullopt; } } else { - auto db = getStatesKeyDb(txn, room_id); - std::string d = json::object({{"key", state_key}}).dump(); - std::string_view data = d; + auto db = getStatesKeyDb(txn, room_id); + std::string d = json::object({{"key", state_key}}).dump(); + std::string_view data = d; + std::string_view typeStrV = typeStr; auto cursor = lmdb::cursor::open(txn, db); - if (!cursor.get(state_key, data, MDB_GET_BOTH)) + if (!cursor.get(typeStrV, data, MDB_GET_BOTH)) return std::nullopt; try { @@ -463,6 +467,47 @@ private: } } + template + std::vector> getStateEventsWithType(lmdb::txn &txn, + const std::string &room_id) + + { + constexpr auto type = mtx::events::state_content_to_type; + static_assert(type != mtx::events::EventType::Unsupported, + "Not a supported type in state events."); + + if (room_id.empty()) + return {}; + + std::vector> events; + + { + auto db = getStatesKeyDb(txn, room_id); + auto eventsDb = getEventsDb(txn, room_id); + const auto typeStr = to_string(type); + std::string_view typeStrV = typeStr; + std::string_view data; + std::string_view value; + + auto cursor = lmdb::cursor::open(txn, db); + bool first = true; + if (cursor.get(typeStrV, data, MDB_SET)) { + while (cursor.get( + typeStrV, data, first ? MDB_FIRST_DUP : MDB_NEXT_DUP)) { + first = false; + + if (eventsDb.get(txn, + json::parse(data)["id"].get(), + value)) + events.push_back( + json::parse(value) + .get>()); + } + } + } + + return events; + } void saveInvites(lmdb::txn &txn, const std::map &rooms); @@ -482,6 +527,10 @@ private: } } + void updateSpaces(lmdb::txn &txn, + const std::set &spaces_with_updates, + std::set rooms_with_updates); + lmdb::dbi getPendingReceiptsDb(lmdb::txn &txn) { return lmdb::dbi::open(txn, "pending_receipts", MDB_CREATE); @@ -548,8 +597,8 @@ private: lmdb::dbi getStatesKeyDb(lmdb::txn &txn, const std::string &room_id) { - auto db = - lmdb::dbi::open(txn, std::string(room_id + "/state_by_key").c_str(), MDB_CREATE); + auto db = lmdb::dbi::open( + txn, std::string(room_id + "/state_by_key").c_str(), MDB_CREATE | MDB_DUPSORT); lmdb::dbi_set_dupsort(txn, db, compare_state_key); return db; } @@ -611,6 +660,7 @@ private: lmdb::env env_; lmdb::dbi syncStateDb_; lmdb::dbi roomsDb_; + lmdb::dbi spacesChildrenDb_, spacesParentsDb_; lmdb::dbi invitesDb_; lmdb::dbi readReceiptsDb_; lmdb::dbi notificationsDb_; diff --git a/src/timeline/CommunitiesModel.cpp b/src/timeline/CommunitiesModel.cpp index 6c236784..88464bf9 100644 --- a/src/timeline/CommunitiesModel.cpp +++ b/src/timeline/CommunitiesModel.cpp @@ -44,8 +44,23 @@ CommunitiesModel::data(const QModelIndex &index, int role) const case CommunitiesModel::Roles::Id: return ""; } - } else if (index.row() - 1 < tags_.size()) { - auto tag = tags_.at(index.row() - 1); + } else if (index.row() - 1 < spaceOrder_.size()) { + auto id = spaceOrder_.at(index.row() - 1); + switch (role) { + case CommunitiesModel::Roles::AvatarUrl: + return QString::fromStdString(spaces_.at(id).avatar_url); + case CommunitiesModel::Roles::DisplayName: + case CommunitiesModel::Roles::Tooltip: + return QString::fromStdString(spaces_.at(id).name); + case CommunitiesModel::Roles::ChildrenHidden: + return true; + case CommunitiesModel::Roles::Hidden: + return hiddentTagIds_.contains("space:" + id); + case CommunitiesModel::Roles::Id: + return "space:" + id; + } + } else if (index.row() - 1 < tags_.size() + spaceOrder_.size()) { + auto tag = tags_.at(index.row() - 1 - spaceOrder_.size()); if (tag == "m.favourite") { switch (role) { case CommunitiesModel::Roles::AvatarUrl: @@ -78,7 +93,6 @@ CommunitiesModel::data(const QModelIndex &index, int role) const case CommunitiesModel::Roles::AvatarUrl: return QString(":/icons/icons/ui/tag.png"); case CommunitiesModel::Roles::DisplayName: - return tag.mid(2); case CommunitiesModel::Roles::Tooltip: return tag.mid(2); } @@ -99,17 +113,27 @@ CommunitiesModel::data(const QModelIndex &index, int role) const void CommunitiesModel::initializeSidebar() { + beginResetModel(); + tags_.clear(); + spaceOrder_.clear(); + spaces_.clear(); + std::set ts; - for (const auto &e : cache::roomInfo()) { - for (const auto &t : e.tags) { - if (t.find("u.") == 0 || t.find("m." == 0)) { - ts.insert(t); + std::vector tempSpaces; + auto infos = cache::roomInfo(); + for (auto it = infos.begin(); it != infos.end(); it++) { + if (it.value().is_space) { + spaceOrder_.push_back(it.key()); + spaces_[it.key()] = it.value(); + } else { + for (const auto &t : it.value().tags) { + if (t.find("u.") == 0 || t.find("m." == 0)) { + ts.insert(t); + } } } } - beginResetModel(); - tags_.clear(); for (const auto &t : ts) tags_.push_back(QString::fromStdString(t)); diff --git a/src/timeline/CommunitiesModel.h b/src/timeline/CommunitiesModel.h index 66d6b21b..8c40ec5b 100644 --- a/src/timeline/CommunitiesModel.h +++ b/src/timeline/CommunitiesModel.h @@ -11,6 +11,8 @@ #include +#include "CacheStructs.h" + class CommunitiesModel : public QAbstractListModel { Q_OBJECT @@ -71,4 +73,6 @@ private: QStringList tags_; QString currentTagId_; QStringList hiddentTagIds_; + QStringList spaceOrder_; + std::map spaces_; }; -- cgit 1.5.1 From 6bfa6c4c793f1cd74df64d593ff2060ff94f176f Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Wed, 16 Jun 2021 22:59:41 +0200 Subject: Allow filtering by space --- src/Cache.cpp | 36 +++++++++++++++++++++++++----------- src/Cache_p.h | 12 +++++++++--- src/timeline/CommunitiesModel.cpp | 9 +++++++++ src/timeline/RoomlistModel.cpp | 24 ++++++++++++++++++++++++ src/timeline/RoomlistModel.h | 3 +++ 5 files changed, 70 insertions(+), 14 deletions(-) (limited to 'src/Cache.cpp') diff --git a/src/Cache.cpp b/src/Cache.cpp index 0bd6fe0d..8b1798d6 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -905,7 +905,9 @@ Cache::runMigrations() std::reverse(oldMessages.events.begin(), oldMessages.events.end()); // save messages using the new method - saveTimelineMessages(txn, room_id, oldMessages); + auto eventsDb = getEventsDb(txn, room_id); + saveTimelineMessages( + txn, eventsDb, room_id, oldMessages); } // delete old messages db @@ -1208,13 +1210,24 @@ Cache::saveState(const mtx::responses::Sync &res) auto statesdb = getStatesDb(txn, room.first); auto stateskeydb = getStatesKeyDb(txn, room.first); auto membersdb = getMembersDb(txn, room.first); - - saveStateEvents( - txn, statesdb, stateskeydb, membersdb, room.first, room.second.state.events); - saveStateEvents( - txn, statesdb, stateskeydb, membersdb, room.first, room.second.timeline.events); - - saveTimelineMessages(txn, room.first, room.second.timeline); + auto eventsDb = getEventsDb(txn, room.first); + + saveStateEvents(txn, + statesdb, + stateskeydb, + membersdb, + eventsDb, + room.first, + room.second.state.events); + saveStateEvents(txn, + statesdb, + stateskeydb, + membersdb, + eventsDb, + room.first, + room.second.timeline.events); + + saveTimelineMessages(txn, eventsDb, room.first, room.second.timeline); RoomInfo updatedInfo; updatedInfo.name = getRoomName(txn, statesdb, membersdb).toStdString(); @@ -2634,11 +2647,12 @@ void Cache::savePendingMessage(const std::string &room_id, const mtx::events::collections::TimelineEvent &message) { - auto txn = lmdb::txn::begin(env_); + auto txn = lmdb::txn::begin(env_); + auto eventsDb = getEventsDb(txn, room_id); mtx::responses::Timeline timeline; timeline.events.push_back(message.data); - saveTimelineMessages(txn, room_id, timeline); + saveTimelineMessages(txn, eventsDb, room_id, timeline); auto pending = getPendingMessagesDb(txn, room_id); @@ -2706,13 +2720,13 @@ Cache::removePendingStatus(const std::string &room_id, const std::string &txn_id void Cache::saveTimelineMessages(lmdb::txn &txn, + lmdb::dbi &eventsDb, const std::string &room_id, const mtx::responses::Timeline &res) { if (res.events.empty()) return; - auto eventsDb = getEventsDb(txn, room_id); auto relationsDb = getRelationsDb(txn, room_id); auto orderDb = getEventOrderDb(txn, room_id); diff --git a/src/Cache_p.h b/src/Cache_p.h index 064f4882..e35e78ec 100644 --- a/src/Cache_p.h +++ b/src/Cache_p.h @@ -335,6 +335,7 @@ private: std::string getLastEventId(lmdb::txn &txn, const std::string &room_id); DescInfo getLastMessageInfo(lmdb::txn &txn, const std::string &room_id); void saveTimelineMessages(lmdb::txn &txn, + lmdb::dbi &eventsDb, const std::string &room_id, const mtx::responses::Timeline &res); @@ -353,11 +354,12 @@ private: lmdb::dbi &statesdb, lmdb::dbi &stateskeydb, lmdb::dbi &membersdb, + lmdb::dbi &eventsDb, const std::string &room_id, const std::vector &events) { for (const auto &e : events) - saveStateEvent(txn, statesdb, stateskeydb, membersdb, room_id, e); + saveStateEvent(txn, statesdb, stateskeydb, membersdb, eventsDb, room_id, e); } template @@ -365,6 +367,7 @@ private: lmdb::dbi &statesdb, lmdb::dbi &stateskeydb, lmdb::dbi &membersdb, + lmdb::dbi &eventsDb, const std::string &room_id, const T &event) { @@ -401,8 +404,10 @@ private: } std::visit( - [&txn, &statesdb, &stateskeydb](auto e) { - if constexpr (isStateEvent(e)) + [&txn, &statesdb, &stateskeydb, &eventsDb](auto e) { + if constexpr (isStateEvent(e)) { + eventsDb.put(txn, e.event_id, json(e).dump()); + if (e.type != EventType::Unsupported) { if (e.state_key.empty()) statesdb.put( @@ -417,6 +422,7 @@ private: }) .dump()); } + } }, event); } diff --git a/src/timeline/CommunitiesModel.cpp b/src/timeline/CommunitiesModel.cpp index 88464bf9..6ff953d2 100644 --- a/src/timeline/CommunitiesModel.cpp +++ b/src/timeline/CommunitiesModel.cpp @@ -185,6 +185,15 @@ CommunitiesModel::setCurrentTagId(QString tagId) return; } } + } else if (tagId.startsWith("space:")) { + auto tag = tagId.mid(6); + for (const auto &t : spaceOrder_) { + if (t == tag) { + this->currentTagId_ = tagId; + emit currentTagIdChanged(currentTagId_); + return; + } + } } this->currentTagId_ = ""; diff --git a/src/timeline/RoomlistModel.cpp b/src/timeline/RoomlistModel.cpp index 0f980c6c..3b6ad54a 100644 --- a/src/timeline/RoomlistModel.cpp +++ b/src/timeline/RoomlistModel.cpp @@ -530,6 +530,30 @@ FilteredRoomlistModel::filterAcceptsRow(int sourceRow, const QModelIndex &) cons return false; } return true; + } else if (filterType == FilterBy::Space) { + auto roomid = sourceModel() + ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::RoomId) + .toString(); + auto tags = sourceModel() + ->data(sourceModel()->index(sourceRow, 0), RoomlistModel::Tags) + .toStringList(); + + auto contains = [](const std::vector &v, const std::string &str) { + for (const auto &e : v) + if (e == str) + return true; + return false; + }; + auto parents = cache::client()->getParentRoomIds(roomid.toStdString()); + + if (!contains(parents, filterStr.toStdString())) + return false; + else if (!hiddenTags.empty()) { + for (const auto &t : tags) + if (hiddenTags.contains(t)) + return false; + } + return true; } else { return true; } diff --git a/src/timeline/RoomlistModel.h b/src/timeline/RoomlistModel.h index b0244886..5f8b8bd8 100644 --- a/src/timeline/RoomlistModel.h +++ b/src/timeline/RoomlistModel.h @@ -134,6 +134,9 @@ public slots: if (tagId.startsWith("tag:")) { filterType = FilterBy::Tag; filterStr = tagId.mid(4); + } else if (tagId.startsWith("space:")) { + filterType = FilterBy::Space; + filterStr = tagId.mid(6); } else { filterType = FilterBy::Nothing; filterStr.clear(); -- cgit 1.5.1 From 884fb74d2d1386c7355a709b3972619f5bd0f78a Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 18 Jun 2021 16:22:06 +0200 Subject: Add a basic 'Space page' --- resources/qml/ChatPage.qml | 2 +- resources/qml/RoomList.qml | 2 +- resources/qml/TimelineView.qml | 63 +++++++++++++++++++++++++++++++++++++++++- src/Cache.cpp | 7 +++++ src/Cache_p.h | 1 + src/timeline/TimelineModel.cpp | 8 ++++++ src/timeline/TimelineModel.h | 3 ++ 7 files changed, 83 insertions(+), 3 deletions(-) (limited to 'src/Cache.cpp') diff --git a/resources/qml/ChatPage.qml b/resources/qml/ChatPage.qml index df2bf41f..cd323a97 100644 --- a/resources/qml/ChatPage.qml +++ b/resources/qml/ChatPage.qml @@ -71,7 +71,7 @@ Rectangle { AdaptiveLayoutElement { id: timlineViewC - minimumWidth: fontMetrics.averageCharacterWidth * 40 + Nheko.avatarSize + 2* Nheko.paddingMedium + minimumWidth: fontMetrics.averageCharacterWidth * 40 + Nheko.avatarSize + 2 * Nheko.paddingMedium TimelineView { id: timeline diff --git a/resources/qml/RoomList.qml b/resources/qml/RoomList.qml index 99e0ed41..d69f608b 100644 --- a/resources/qml/RoomList.qml +++ b/resources/qml/RoomList.qml @@ -254,9 +254,9 @@ Page { Label { id: timestamp + visible: !model.isInvite && !model.isSpace width: visible ? 0 : undefined - Layout.alignment: Qt.AlignRight | Qt.AlignBottom font.pixelSize: fontMetrics.font.pixelSize * 0.9 color: roomItem.unimportantText diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 90e28166..703f2fac 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -41,7 +41,8 @@ Item { ColumnLayout { id: timelineLayout - visible: room != null + visible: room != null && !room.isSpace + enabled: visible anchors.fill: parent spacing: 0 @@ -127,6 +128,66 @@ Item { } + ColumnLayout { + id: contentLayout1 + + visible: room != null && room.isSpace + enabled: visible + anchors.fill: parent + anchors.margins: Nheko.paddingLarge + spacing: Nheko.paddingLarge + + Avatar { + url: room.roomAvatarUrl.replace("mxc://", "image://MxcImage/") + displayName: room ? room.roomName : "" + height: 130 + width: 130 + Layout.alignment: Qt.AlignHCenter + enabled: false + } + + MatrixText { + text: room ? room.roomName : "" + font.pixelSize: 24 + Layout.alignment: Qt.AlignHCenter + } + + MatrixText { + text: qsTr("%1 member(s)").arg(room ? room.roomMemberCount : 0) + Layout.alignment: Qt.AlignHCenter + } + + ScrollView { + //Layout.maximumHeight: 75 + Layout.alignment: Qt.AlignHCenter + width: parent.width + + TextArea { + text: TimelineManager.escapeEmoji(room ? room.roomTopic : "") + wrapMode: TextEdit.WordWrap + textFormat: TextEdit.RichText + readOnly: true + background: null + selectByMouse: true + color: Nheko.colors.text + horizontalAlignment: TextEdit.AlignHCenter + onLinkActivated: Nheko.openLink(link) + + CursorShape { + anchors.fill: parent + cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + } + + } + + } + + Item { + Layout.fillHeight: true + } + + } + NhekoDropArea { anchors.fill: parent roomid: room ? room.roomId() : "" diff --git a/src/Cache.cpp b/src/Cache.cpp index 8b1798d6..144a2d9a 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -1772,6 +1772,13 @@ Cache::relatedEvents(const std::string &room_id, const std::string &event_id) return related_ids; } +size_t +Cache::memberCount(const std::string &room_id) +{ + auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY); + return getMembersDb(txn, room_id).size(txn); +} + QMap Cache::roomInfo(bool withInvites) { diff --git a/src/Cache_p.h b/src/Cache_p.h index e35e78ec..cfcf9c9e 100644 --- a/src/Cache_p.h +++ b/src/Cache_p.h @@ -101,6 +101,7 @@ public: std::vector getMembers(const std::string &room_id, std::size_t startIndex = 0, std::size_t len = 30); + size_t memberCount(const std::string &room_id); void saveState(const mtx::responses::Sync &res); bool isInitialized(); diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index 1ecb6cdf..13919e6d 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -774,6 +774,7 @@ TimelineModel::syncState(const mtx::responses::State &s) } else if (std::holds_alternative>(e)) { emit roomAvatarUrlChanged(); emit roomNameChanged(); + emit roomMemberCountChanged(); } } } @@ -830,6 +831,7 @@ TimelineModel::addEvents(const mtx::responses::Timeline &timeline) } else if (std::holds_alternative>(e)) { emit roomAvatarUrlChanged(); emit roomNameChanged(); + emit roomMemberCountChanged(); } } updateLastMessage(); @@ -1935,3 +1937,9 @@ TimelineModel::roomTopic() const return utils::replaceEmoji(utils::linkifyMessage( QString::fromStdString(info[room_id_].topic).toHtmlEscaped())); } + +int +TimelineModel::roomMemberCount() const +{ + return (int)cache::client()->memberCount(room_id_.toStdString()); +} diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index 42aa136f..3392d474 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -161,6 +161,7 @@ class TimelineModel : public QAbstractListModel Q_PROPERTY(QString roomName READ roomName NOTIFY roomNameChanged) Q_PROPERTY(QString roomAvatarUrl READ roomAvatarUrl NOTIFY roomAvatarUrlChanged) Q_PROPERTY(QString roomTopic READ roomTopic NOTIFY roomTopicChanged) + Q_PROPERTY(int roomMemberCount READ roomMemberCount NOTIFY roomMemberCountChanged) Q_PROPERTY(bool isSpace READ isSpace CONSTANT) Q_PROPERTY(InputBar *input READ input CONSTANT) Q_PROPERTY(Permissions *permissions READ permissions NOTIFY permissionsChanged) @@ -264,6 +265,7 @@ public: DescInfo lastMessage() const { return lastMessage_; } bool isSpace() const { return isSpace_; } + int roomMemberCount() const; public slots: void setCurrentIndex(int index); @@ -350,6 +352,7 @@ signals: void roomNameChanged(); void roomTopicChanged(); void roomAvatarUrlChanged(); + void roomMemberCountChanged(); void permissionsChanged(); void forwardToRoom(mtx::events::collections::TimelineEvents *e, QString roomId); -- cgit 1.5.1 From 5b016cbc6843029d62f79602a36203d4a4f9e230 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Thu, 1 Jul 2021 12:45:47 +0200 Subject: Remove dead code to calculate last message --- src/Cache.cpp | 92 ------------------------------------------ src/CacheStructs.h | 2 - src/Cache_p.h | 1 - src/timeline/RoomlistModel.cpp | 6 +-- 4 files changed, 3 insertions(+), 98 deletions(-) (limited to 'src/Cache.cpp') diff --git a/src/Cache.cpp b/src/Cache.cpp index 144a2d9a..aba76406 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -1794,8 +1794,6 @@ Cache::roomInfo(bool withInvites) while (roomsCursor.get(room_id, room_data, MDB_NEXT)) { RoomInfo tmp = json::parse(std::move(room_data)); tmp.member_count = getMembersDb(txn, std::string(room_id)).size(txn); - tmp.msgInfo = getLastMessageInfo(txn, std::string(room_id)); - result.insert(QString::fromStdString(std::string(room_id)), std::move(tmp)); } roomsCursor.close(); @@ -2022,96 +2020,6 @@ Cache::getTimelineEventId(const std::string &room_id, uint64_t index) return std::string(val); } -DescInfo -Cache::getLastMessageInfo(lmdb::txn &txn, const std::string &room_id) -{ - lmdb::dbi orderDb; - try { - orderDb = getOrderToMessageDb(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::dbi eventsDb; - try { - eventsDb = getEventsDb(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::dbi membersdb; - try { - membersdb = getMembersDb(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 {}; - } - - if (orderDb.size(txn) == 0) - return DescInfo{}; - - const auto local_user = utils::localUser(); - - DescInfo fallbackDesc{}; - - std::string_view indexVal, event_id; - - auto cursor = lmdb::cursor::open(txn, orderDb); - bool first = true; - while (cursor.get(indexVal, event_id, first ? MDB_LAST : MDB_PREV)) { - first = false; - - std::string_view event; - bool success = eventsDb.get(txn, event_id, event); - if (!success) - continue; - - auto obj = json::parse(event); - - if (fallbackDesc.event_id.isEmpty() && obj["type"] == "m.room.member" && - obj["state_key"] == local_user.toStdString() && - obj["content"]["membership"] == "join") { - uint64_t ts = obj["origin_server_ts"]; - auto time = QDateTime::fromMSecsSinceEpoch(ts); - fallbackDesc = DescInfo{QString::fromStdString(obj["event_id"]), - local_user, - tr("You joined this room."), - utils::descriptiveTime(time), - ts, - time}; - } - - if (!(obj["type"] == "m.room.message" || obj["type"] == "m.sticker" || - obj["type"] == "m.call.invite" || obj["type"] == "m.call.answer" || - obj["type"] == "m.call.hangup" || obj["type"] == "m.room.encrypted")) - continue; - - mtx::events::collections::TimelineEvent te; - mtx::events::collections::from_json(obj, te); - - std::string_view info; - MemberInfo m; - if (membersdb.get(txn, obj["sender"].get(), info)) { - m = json::parse(std::string_view(info.data(), info.size())); - } - - cursor.close(); - return utils::getMessageDescription( - te.data, local_user, QString::fromStdString(m.name)); - } - cursor.close(); - - return fallbackDesc; -} - QHash Cache::invites() { diff --git a/src/CacheStructs.h b/src/CacheStructs.h index 1d0f0d70..28c70055 100644 --- a/src/CacheStructs.h +++ b/src/CacheStructs.h @@ -83,8 +83,6 @@ struct RoomInfo //! Who can access to the room. mtx::events::state::JoinRule join_rule = mtx::events::state::JoinRule::Public; bool guest_access = false; - //! Metadata describing the last message in the timeline. - DescInfo msgInfo; //! The list of tags associated with this room std::vector tags; }; diff --git a/src/Cache_p.h b/src/Cache_p.h index cfcf9c9e..c76cc717 100644 --- a/src/Cache_p.h +++ b/src/Cache_p.h @@ -334,7 +334,6 @@ private: std::optional getMember(const std::string &room_id, const std::string &user_id); std::string getLastEventId(lmdb::txn &txn, const std::string &room_id); - DescInfo getLastMessageInfo(lmdb::txn &txn, const std::string &room_id); void saveTimelineMessages(lmdb::txn &txn, lmdb::dbi &eventsDb, const std::string &room_id, diff --git a/src/timeline/RoomlistModel.cpp b/src/timeline/RoomlistModel.cpp index 7f59b112..6a90ab6e 100644 --- a/src/timeline/RoomlistModel.cpp +++ b/src/timeline/RoomlistModel.cpp @@ -116,11 +116,11 @@ RoomlistModel::data(const QModelIndex &index, int role) const case Roles::RoomId: return roomid; case Roles::LastMessage: - return room.msgInfo.body; + return QString(); case Roles::Time: - return room.msgInfo.descriptiveTime; + return QString(); case Roles::Timestamp: - return QVariant(static_cast(room.msgInfo.timestamp)); + return QVariant(static_cast(0)); case Roles::HasUnreadMessages: case Roles::HasLoudNotification: return false; -- cgit 1.5.1 From f23fd5f8227fed68589584a0825f26717c51a52d Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Tue, 6 Jul 2021 11:39:29 +0200 Subject: Fix a few embarrassing bugs with device list updates --- src/Cache.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'src/Cache.cpp') diff --git a/src/Cache.cpp b/src/Cache.cpp index aba76406..8146e2cc 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -3588,25 +3588,31 @@ Cache::updateUserKeys(const std::string &sync_token, const mtx::responses::Query updateToWrite.self_signing_keys = update.self_signing_keys; updateToWrite.user_signing_keys = update.user_signing_keys; - // If we have keys for the device already, only update the signatures. + auto oldDeviceKeys = std::move(updateToWrite.device_keys); + updateToWrite.device_keys.clear(); + + // Don't insert keys, which we have seen once already for (const auto &[device_id, device_keys] : update.device_keys) { - if (updateToWrite.device_keys.count(device_id) && - updateToWrite.device_keys.at(device_id).keys == - device_keys.keys) { - updateToWrite.device_keys.at(device_id).signatures = - device_keys.signatures; + if (oldDeviceKeys.count(device_id) && + oldDeviceKeys.at(device_id).keys == device_keys.keys) { + // this is safe, since the keys are the same + updateToWrite.device_keys[device_id] = device_keys; } else { bool keyReused = false; for (const auto &[key_id, key] : device_keys.keys) { (void)key_id; if (updateToWrite.seen_device_keys.count(key)) { + nhlog::crypto()->warn( + "Key '{}' reused by ({}: {})", + key, + user, + device_id); keyReused = true; break; } } - if (!updateToWrite.device_keys.count(device_id) && - !keyReused) + if (!keyReused && !oldDeviceKeys.count(device_id)) updateToWrite.device_keys[device_id] = device_keys; } -- cgit 1.5.1