diff options
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/connection.h | 6 | ||||
-rw-r--r-- | lib/csapi/search.cpp | 28 | ||||
-rw-r--r-- | lib/csapi/search.h | 306 | ||||
-rw-r--r-- | lib/events/encryptionevent.cpp | 19 | ||||
-rw-r--r-- | lib/jobs/basejob.h | 8 | ||||
-rw-r--r-- | lib/room.cpp | 8 | ||||
-rw-r--r-- | lib/room.h | 4 | ||||
-rw-r--r-- | lib/uriresolver.h | 2 | ||||
-rw-r--r-- | lib/user.h | 4 |
10 files changed, 358 insertions, 28 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b77e262..2773c9da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -208,7 +208,6 @@ if (MATRIX_DOC_PATH AND GTAD_PATH) ${ABS_GTAD_PATH} --config ../gtad/gtad.yaml --out ${CSAPI_DIR} ${FULL_CSAPI_SRC_DIR} old_sync.yaml- room_initial_sync.yaml- # deprecated - search.yaml- # current GTAD is limited in handling move-only data key_backup.yaml- # immature and buggy in terms of API definition sync.yaml- # we have a better handcrafted implementation WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/lib diff --git a/lib/connection.h b/lib/connection.h index 6517b909..07ae9f29 100644 --- a/lib/connection.h +++ b/lib/connection.h @@ -497,7 +497,7 @@ public: setUserFactory(defaultUserFactory<T>()); } -public slots: +public Q_SLOTS: /** Set the homeserver base URL */ void setHomeserver(const QUrl& baseUrl); @@ -656,7 +656,7 @@ public slots: */ virtual PostReceiptJob* postReceipt(Room* room, RoomEvent* event); -signals: +Q_SIGNALS: /** * @deprecated * This was a signal resulting from a successful resolveServer(). @@ -853,7 +853,7 @@ protected: */ void onSyncSuccess(SyncData&& data, bool fromCache = false); -protected slots: +protected Q_SLOTS: void syncLoopIteration(); private: diff --git a/lib/csapi/search.cpp b/lib/csapi/search.cpp new file mode 100644 index 00000000..5649d52a --- /dev/null +++ b/lib/csapi/search.cpp @@ -0,0 +1,28 @@ +/****************************************************************************** + * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN + */ + +#include "search.h" + +#include <QtCore/QStringBuilder> + +using namespace Quotient; + +auto queryToSearch(const QString& nextBatch) +{ + BaseJob::Query _q; + addParam<IfNotEmpty>(_q, QStringLiteral("next_batch"), nextBatch); + return _q; +} + +SearchJob::SearchJob(const Categories& searchCategories, + const QString& nextBatch) + : BaseJob(HttpVerb::Post, QStringLiteral("SearchJob"), + QStringLiteral("/_matrix/client/r0") % "/search", + queryToSearch(nextBatch)) +{ + QJsonObject _data; + addParam<>(_data, QStringLiteral("search_categories"), searchCategories); + setRequestData(std::move(_data)); + addExpectedKey("search_categories"); +} diff --git a/lib/csapi/search.h b/lib/csapi/search.h new file mode 100644 index 00000000..c009ded6 --- /dev/null +++ b/lib/csapi/search.h @@ -0,0 +1,306 @@ +/****************************************************************************** + * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN + */ + +#pragma once + +#include "csapi/definitions/room_event_filter.h" + +#include "events/eventloader.h" +#include "jobs/basejob.h" + +namespace Quotient { + +/*! \brief Perform a server-side search. + * + * Performs a full text search across different categories. + */ +class SearchJob : public BaseJob { +public: + // Inner data structures + + /// Configures whether any context for the events + /// returned are included in the response. + struct IncludeEventContext { + /// How many events before the result are + /// returned. By default, this is ``5``. + Omittable<int> beforeLimit; + /// How many events after the result are + /// returned. By default, this is ``5``. + Omittable<int> afterLimit; + /// Requests that the server returns the + /// historic profile information for the users + /// that sent the events that were returned. + /// By default, this is ``false``. + Omittable<bool> includeProfile; + }; + + /// Configuration for group. + struct Group { + /// Key that defines the group. + QString key; + }; + + /// Requests that the server partitions the result set + /// based on the provided list of keys. + struct Groupings { + /// List of groups to request. + QVector<Group> groupBy; + }; + + /// Mapping of category name to search criteria. + struct RoomEventsCriteria { + /// The string to search events for + QString searchTerm; + /// The keys to search. Defaults to all. + QStringList keys; + /// This takes a `filter`_. + RoomEventFilter filter; + /// The order in which to search for results. + /// By default, this is ``"rank"``. + QString orderBy; + /// Configures whether any context for the events + /// returned are included in the response. + Omittable<IncludeEventContext> eventContext; + /// Requests the server return the current state for + /// each room returned. + Omittable<bool> includeState; + /// Requests that the server partitions the result set + /// based on the provided list of keys. + Omittable<Groupings> groupings; + }; + + /// Describes which categories to search in and their criteria. + struct Categories { + /// Mapping of category name to search criteria. + Omittable<RoomEventsCriteria> roomEvents; + }; + + /// Performs a full text search across different categories. + struct UserProfile { + /// Performs a full text search across different categories. + QString displayname; + /// Performs a full text search across different categories. + QString avatarUrl; + }; + + /// Context for result, if requested. + struct EventContext { + /// Pagination token for the start of the chunk + QString begin; + /// Pagination token for the end of the chunk + QString end; + /// The historic profile information of the + /// users that sent the events returned. + /// + /// The ``string`` key is the user ID for which + /// the profile belongs to. + QHash<QString, UserProfile> profileInfo; + /// Events just before the result. + RoomEvents eventsBefore; + /// Events just after the result. + RoomEvents eventsAfter; + }; + + /// The result object. + struct Result { + /// A number that describes how closely this result matches the search. + /// Higher is closer. + Omittable<double> rank; + /// The event that matched. + RoomEventPtr result; + /// Context for result, if requested. + Omittable<EventContext> context; + }; + + /// The results for a particular group value. + struct GroupValue { + /// Token that can be used to get the next batch + /// of results in the group, by passing as the + /// `next_batch` parameter to the next call. If + /// this field is absent, there are no more + /// results in this group. + QString nextBatch; + /// Key that can be used to order different + /// groups. + Omittable<int> order; + /// Which results are in this group. + QStringList results; + }; + + /// Mapping of category name to search criteria. + struct ResultRoomEvents { + /// An approximate count of the total number of results found. + Omittable<int> count; + /// List of words which should be highlighted, useful for stemming which + /// may change the query terms. + QStringList highlights; + /// List of results in the requested order. + std::vector<Result> results; + /// The current state for every room in the results. + /// This is included if the request had the + /// ``include_state`` key set with a value of ``true``. + /// + /// The ``string`` key is the room ID for which the ``State + /// Event`` array belongs to. + UnorderedMap<QString, StateEvents> state; + /// Any groups that were requested. + /// + /// The outer ``string`` key is the group key requested (eg: ``room_id`` + /// or ``sender``). The inner ``string`` key is the grouped value (eg: + /// a room's ID or a user's ID). + QHash<QString, QHash<QString, GroupValue>> groups; + /// Token that can be used to get the next batch of + /// results, by passing as the `next_batch` parameter to + /// the next call. If this field is absent, there are no + /// more results. + QString nextBatch; + }; + + /// Describes which categories to search in and their criteria. + struct ResultCategories { + /// Mapping of category name to search criteria. + Omittable<ResultRoomEvents> roomEvents; + }; + + // Construction/destruction + + /*! \brief Perform a server-side search. + * + * \param searchCategories + * Describes which categories to search in and their criteria. + * + * \param nextBatch + * The point to return events from. If given, this should be a + * ``next_batch`` result from a previous call to this endpoint. + */ + explicit SearchJob(const Categories& searchCategories, + const QString& nextBatch = {}); + + // Result properties + + /// Describes which categories to search in and their criteria. + ResultCategories searchCategories() const + { + return loadFromJson<ResultCategories>("search_categories"_ls); + } +}; + +template <> +struct JsonObjectConverter<SearchJob::IncludeEventContext> { + static void dumpTo(QJsonObject& jo, + const SearchJob::IncludeEventContext& pod) + { + addParam<IfNotEmpty>(jo, QStringLiteral("before_limit"), + pod.beforeLimit); + addParam<IfNotEmpty>(jo, QStringLiteral("after_limit"), pod.afterLimit); + addParam<IfNotEmpty>(jo, QStringLiteral("include_profile"), + pod.includeProfile); + } +}; + +template <> +struct JsonObjectConverter<SearchJob::Group> { + static void dumpTo(QJsonObject& jo, const SearchJob::Group& pod) + { + addParam<IfNotEmpty>(jo, QStringLiteral("key"), pod.key); + } +}; + +template <> +struct JsonObjectConverter<SearchJob::Groupings> { + static void dumpTo(QJsonObject& jo, const SearchJob::Groupings& pod) + { + addParam<IfNotEmpty>(jo, QStringLiteral("group_by"), pod.groupBy); + } +}; + +template <> +struct JsonObjectConverter<SearchJob::RoomEventsCriteria> { + static void dumpTo(QJsonObject& jo, const SearchJob::RoomEventsCriteria& pod) + { + addParam<>(jo, QStringLiteral("search_term"), pod.searchTerm); + addParam<IfNotEmpty>(jo, QStringLiteral("keys"), pod.keys); + addParam<IfNotEmpty>(jo, QStringLiteral("filter"), pod.filter); + addParam<IfNotEmpty>(jo, QStringLiteral("order_by"), pod.orderBy); + addParam<IfNotEmpty>(jo, QStringLiteral("event_context"), + pod.eventContext); + addParam<IfNotEmpty>(jo, QStringLiteral("include_state"), + pod.includeState); + addParam<IfNotEmpty>(jo, QStringLiteral("groupings"), pod.groupings); + } +}; + +template <> +struct JsonObjectConverter<SearchJob::Categories> { + static void dumpTo(QJsonObject& jo, const SearchJob::Categories& pod) + { + addParam<IfNotEmpty>(jo, QStringLiteral("room_events"), pod.roomEvents); + } +}; + +template <> +struct JsonObjectConverter<SearchJob::UserProfile> { + static void fillFrom(const QJsonObject& jo, SearchJob::UserProfile& result) + { + fromJson(jo.value("displayname"_ls), result.displayname); + fromJson(jo.value("avatar_url"_ls), result.avatarUrl); + } +}; + +template <> +struct JsonObjectConverter<SearchJob::EventContext> { + static void fillFrom(const QJsonObject& jo, SearchJob::EventContext& result) + { + fromJson(jo.value("start"_ls), result.begin); + fromJson(jo.value("end"_ls), result.end); + fromJson(jo.value("profile_info"_ls), result.profileInfo); + fromJson(jo.value("events_before"_ls), result.eventsBefore); + fromJson(jo.value("events_after"_ls), result.eventsAfter); + } +}; + +template <> +struct JsonObjectConverter<SearchJob::Result> { + static void fillFrom(const QJsonObject& jo, SearchJob::Result& result) + { + fromJson(jo.value("rank"_ls), result.rank); + fromJson(jo.value("result"_ls), result.result); + fromJson(jo.value("context"_ls), result.context); + } +}; + +template <> +struct JsonObjectConverter<SearchJob::GroupValue> { + static void fillFrom(const QJsonObject& jo, SearchJob::GroupValue& result) + { + fromJson(jo.value("next_batch"_ls), result.nextBatch); + fromJson(jo.value("order"_ls), result.order); + fromJson(jo.value("results"_ls), result.results); + } +}; + +template <> +struct JsonObjectConverter<SearchJob::ResultRoomEvents> { + static void fillFrom(const QJsonObject& jo, + SearchJob::ResultRoomEvents& result) + { + fromJson(jo.value("count"_ls), result.count); + fromJson(jo.value("highlights"_ls), result.highlights); + fromJson(jo.value("results"_ls), result.results); + fromJson(jo.value("state"_ls), result.state); + fromJson(jo.value("groups"_ls), result.groups); + fromJson(jo.value("next_batch"_ls), result.nextBatch); + } +}; + +template <> +struct JsonObjectConverter<SearchJob::ResultCategories> { + static void fillFrom(const QJsonObject& jo, + SearchJob::ResultCategories& result) + { + fromJson(jo.value("room_events"_ls), result.roomEvents); + } +}; + +} // namespace Quotient diff --git a/lib/events/encryptionevent.cpp b/lib/events/encryptionevent.cpp index 073303b0..f1bde621 100644 --- a/lib/events/encryptionevent.cpp +++ b/lib/events/encryptionevent.cpp @@ -1,21 +1,14 @@ -// -// Created by rusakov on 26/09/2017. -// Contributed by andreev on 27/06/2019. -// - #include "encryptionevent.h" -#include "converters.h" #include "e2ee.h" -#include "logging.h" #include <array> +namespace Quotient { static const std::array<QString, 1> encryptionStrings = { - { Quotient::MegolmV1AesSha2AlgoKey } + { MegolmV1AesSha2AlgoKey } }; -namespace Quotient { template <> struct JsonConverter<EncryptionType> { static EncryptionType load(const QJsonValue& jv) @@ -26,7 +19,8 @@ struct JsonConverter<EncryptionType> { if (encryptionString == *it) return EncryptionType(it - encryptionStrings.begin()); - qCWarning(EVENTS) << "Unknown EncryptionType: " << encryptionString; + if (!encryptionString.isEmpty()) + qCWarning(EVENTS) << "Unknown EncryptionType: " << encryptionString; return EncryptionType::Undefined; } }; @@ -35,7 +29,7 @@ struct JsonConverter<EncryptionType> { using namespace Quotient; EncryptionEventContent::EncryptionEventContent(const QJsonObject& json) - : encryption(fromJson<EncryptionType>(json["algorithm"_ls])) + : encryption(fromJson<EncryptionType>(json[AlgorithmKeyL])) , algorithm(sanitized(json[AlgorithmKeyL].toString())) , rotationPeriodMs(json[RotationPeriodMsKeyL].toInt(604800000)) , rotationPeriodMsgs(json[RotationPeriodMsgsKeyL].toInt(100)) @@ -44,9 +38,6 @@ EncryptionEventContent::EncryptionEventContent(const QJsonObject& json) void EncryptionEventContent::fillJson(QJsonObject* o) const { Q_ASSERT(o); - Q_ASSERT_X( - encryption != EncryptionType::Undefined, __FUNCTION__, - "The key 'algorithm' must be explicit in EncryptionEventContent"); if (encryption != EncryptionType::Undefined) o->insert(AlgorithmKey, algorithm); o->insert(RotationPeriodMsKey, rotationPeriodMs); diff --git a/lib/jobs/basejob.h b/lib/jobs/basejob.h index be2926be..5c054ed1 100644 --- a/lib/jobs/basejob.h +++ b/lib/jobs/basejob.h @@ -251,7 +251,7 @@ public: return dbg << j->objectName(); } -public slots: +public Q_SLOTS: void initiate(ConnectionData* connData, bool inBackground); /** @@ -263,7 +263,7 @@ public slots: */ void abandon(); -signals: +Q_SIGNALS: /** The job is about to send a network request */ void aboutToSendRequest(); @@ -433,7 +433,7 @@ protected: // Job objects should only be deleted via QObject::deleteLater ~BaseJob() override; -protected slots: +protected Q_SLOTS: void timeout(); /*! \brief Check the pending or received reply for upfront issues @@ -456,7 +456,7 @@ protected slots: */ virtual Status checkReply(const QNetworkReply *reply) const; -private slots: +private Q_SLOTS: void sendRequest(); void gotReply(); diff --git a/lib/room.cpp b/lib/room.cpp index 7ac3463e..1af294a7 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -2580,8 +2580,14 @@ Room::Changes Room::processStateEvent(const RoomEvent& e) // clang-format off } , [this, oldEncEvt = static_cast<const EncryptionEvent*>(oldStateEvent)]( - const EncryptionEvent&) { + const EncryptionEvent& ee) { // clang-format on + if (ee.algorithm().isEmpty()) { + qWarning(STATE) + << "The encryption event for room" << objectName() + << "doesn't have 'algorithm' specified - ignoring"; + return NoChange; + } if (oldEncEvt && oldEncEvt->encryption() != EncryptionEventContent::Undefined) { qCWarning(STATE) << "The room is already encrypted but a new" @@ -547,7 +547,7 @@ public: return setState(EvT(std::forward<ArgTs>(args)...)); } -public slots: +public Q_SLOTS: /** Check whether the room should be upgraded */ void checkVersion(); @@ -611,7 +611,7 @@ public slots: void answerCall(const QString& callId, const QString& sdp); void hangupCall(const QString& callId); -signals: +Q_SIGNALS: /// Initial set of state events has been loaded /** * The initial set is what comes from the initial sync for the room. diff --git a/lib/uriresolver.h b/lib/uriresolver.h index 9b2ced9d..428ce04c 100644 --- a/lib/uriresolver.h +++ b/lib/uriresolver.h @@ -141,7 +141,7 @@ public: return UriResolverBase::visitResource(account, uri); } -signals: +Q_SIGNALS: /// An action on a user has been requested void userAction(Quotient::User* user, QString action); @@ -122,7 +122,7 @@ public: QString avatarMediaId(const Room* room = nullptr) const; QUrl avatarUrl(const Room* room = nullptr) const; -public slots: +public Q_SLOTS: /// Set a new name in the global user profile void rename(const QString& newName); /// Set a new name for the user in one room @@ -143,7 +143,7 @@ public slots: /// Check whether the user is in ignore list bool isIgnored() const; -signals: +Q_SIGNALS: void defaultNameChanged(); void defaultAvatarChanged(); |