diff options
author | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2018-07-04 21:34:00 +0900 |
---|---|---|
committer | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2018-07-04 21:34:00 +0900 |
commit | 6a9de91752dfe75e185bf90ab856367b2c804582 (patch) | |
tree | 2a12ecc84bf0055e317ef2e4aeec3439d92b2035 /lib | |
parent | d5397fe5ae2ca34d5cfb11394dac17728a2b50ce (diff) | |
parent | 5d1dd53890611376873f6f959e206d5a56cfff70 (diff) | |
download | libquotient-6a9de91752dfe75e185bf90ab856367b2c804582.tar.gz libquotient-6a9de91752dfe75e185bf90ab856367b2c804582.zip |
Merge branch 'kitsune-events-rewritten'
Diffstat (limited to 'lib')
93 files changed, 1740 insertions, 1258 deletions
diff --git a/lib/connection.cpp b/lib/connection.cpp index 8fd960b6..339be5b9 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -355,9 +355,9 @@ void Connection::onSyncSuccess(SyncData &&data) { continue; } - d->accountData[accountEvent->jsonType()] = + d->accountData[accountEvent->matrixType()] = fromJson<AccountDataMap>(accountEvent->contentJson()); - emit accountDataChanged(accountEvent->jsonType()); + emit accountDataChanged(accountEvent->matrixType()); } } @@ -603,7 +603,7 @@ SendToDeviceJob* Connection::sendToDevices(const QString& eventType, std::for_each(devicesToEvents.begin(), devicesToEvents.end(), [&jsonUser] (const auto& deviceToEvents) { jsonUser.insert(deviceToEvents.first, - deviceToEvents.second.toJson()); + deviceToEvents.second.contentJson()); }); }); return callApi<SendToDeviceJob>(BackgroundRequest, @@ -1048,4 +1048,3 @@ void Connection::setCacheState(bool newValue) emit cacheStateChanged(); } } - diff --git a/lib/converters.h b/lib/converters.h index a59809e7..c01d7c8e 100644 --- a/lib/converters.h +++ b/lib/converters.h @@ -18,10 +18,14 @@ #pragma once +#include "util.h" + #include <QtCore/QJsonObject> #include <QtCore/QJsonArray> // Includes <QtCore/QJsonValue> #include <QtCore/QDate> #include <QtCore/QUrlQuery> +#include <QtCore/QSet> +#include <QtCore/QVector> #include <unordered_map> #include <vector> @@ -351,7 +355,7 @@ namespace QMatrixClient template <typename ValT> inline void addTo(QUrlQuery& q, const QString& k, ValT&& v) - { q.addQueryItem(k, QString("%1").arg(v)); } + { q.addQueryItem(k, QStringLiteral("%1").arg(v)); } // OpenAPI is entirely JSON-based, which means representing bools as // textual true/false, rather than 1/0. diff --git a/lib/csapi/account-data.cpp b/lib/csapi/account-data.cpp index ac45cb85..5021c73a 100644 --- a/lib/csapi/account-data.cpp +++ b/lib/csapi/account-data.cpp @@ -12,15 +12,19 @@ using namespace QMatrixClient; static const auto basePath = QStringLiteral("/_matrix/client/r0"); +static const auto SetAccountDataJobName = QStringLiteral("SetAccountDataJob"); + SetAccountDataJob::SetAccountDataJob(const QString& userId, const QString& type, const QJsonObject& content) - : BaseJob(HttpVerb::Put, "SetAccountDataJob", + : BaseJob(HttpVerb::Put, SetAccountDataJobName, basePath % "/user/" % userId % "/account_data/" % type) { setRequestData(Data(toJson(content))); } +static const auto SetAccountDataPerRoomJobName = QStringLiteral("SetAccountDataPerRoomJob"); + SetAccountDataPerRoomJob::SetAccountDataPerRoomJob(const QString& userId, const QString& roomId, const QString& type, const QJsonObject& content) - : BaseJob(HttpVerb::Put, "SetAccountDataPerRoomJob", + : BaseJob(HttpVerb::Put, SetAccountDataPerRoomJobName, basePath % "/user/" % userId % "/rooms/" % roomId % "/account_data/" % type) { setRequestData(Data(toJson(content))); diff --git a/lib/csapi/admin.cpp b/lib/csapi/admin.cpp index a0f7f67f..3effbbc3 100644 --- a/lib/csapi/admin.cpp +++ b/lib/csapi/admin.cpp @@ -23,11 +23,11 @@ namespace QMatrixClient const auto& _json = jv.toObject(); GetWhoIsJob::ConnectionInfo result; result.ip = - fromJson<QString>(_json.value("ip")); + fromJson<QString>(_json.value("ip"_ls)); result.lastSeen = - fromJson<qint64>(_json.value("last_seen")); + fromJson<qint64>(_json.value("last_seen"_ls)); result.userAgent = - fromJson<QString>(_json.value("user_agent")); + fromJson<QString>(_json.value("user_agent"_ls)); return result; } @@ -40,7 +40,7 @@ namespace QMatrixClient const auto& _json = jv.toObject(); GetWhoIsJob::SessionInfo result; result.connections = - fromJson<QVector<GetWhoIsJob::ConnectionInfo>>(_json.value("connections")); + fromJson<QVector<GetWhoIsJob::ConnectionInfo>>(_json.value("connections"_ls)); return result; } @@ -53,7 +53,7 @@ namespace QMatrixClient const auto& _json = jv.toObject(); GetWhoIsJob::DeviceInfo result; result.sessions = - fromJson<QVector<GetWhoIsJob::SessionInfo>>(_json.value("sessions")); + fromJson<QVector<GetWhoIsJob::SessionInfo>>(_json.value("sessions"_ls)); return result; } @@ -73,8 +73,10 @@ QUrl GetWhoIsJob::makeRequestUrl(QUrl baseUrl, const QString& userId) basePath % "/admin/whois/" % userId); } +static const auto GetWhoIsJobName = QStringLiteral("GetWhoIsJob"); + GetWhoIsJob::GetWhoIsJob(const QString& userId) - : BaseJob(HttpVerb::Get, "GetWhoIsJob", + : BaseJob(HttpVerb::Get, GetWhoIsJobName, basePath % "/admin/whois/" % userId) , d(new Private) { @@ -95,8 +97,8 @@ const QHash<QString, GetWhoIsJob::DeviceInfo>& GetWhoIsJob::devices() const BaseJob::Status GetWhoIsJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->userId = fromJson<QString>(json.value("user_id")); - d->devices = fromJson<QHash<QString, DeviceInfo>>(json.value("devices")); + d->userId = fromJson<QString>(json.value("user_id"_ls)); + d->devices = fromJson<QHash<QString, DeviceInfo>>(json.value("devices"_ls)); return Success; } diff --git a/lib/csapi/administrative_contact.cpp b/lib/csapi/administrative_contact.cpp index e3dee8ed..682a6f05 100644 --- a/lib/csapi/administrative_contact.cpp +++ b/lib/csapi/administrative_contact.cpp @@ -23,9 +23,9 @@ namespace QMatrixClient const auto& _json = jv.toObject(); GetAccount3PIDsJob::ThirdPartyIdentifier result; result.medium = - fromJson<QString>(_json.value("medium")); + fromJson<QString>(_json.value("medium"_ls)); result.address = - fromJson<QString>(_json.value("address")); + fromJson<QString>(_json.value("address"_ls)); return result; } @@ -44,8 +44,10 @@ QUrl GetAccount3PIDsJob::makeRequestUrl(QUrl baseUrl) basePath % "/account/3pid"); } +static const auto GetAccount3PIDsJobName = QStringLiteral("GetAccount3PIDsJob"); + GetAccount3PIDsJob::GetAccount3PIDsJob() - : BaseJob(HttpVerb::Get, "GetAccount3PIDsJob", + : BaseJob(HttpVerb::Get, GetAccount3PIDsJobName, basePath % "/account/3pid") , d(new Private) { @@ -61,7 +63,7 @@ const QVector<GetAccount3PIDsJob::ThirdPartyIdentifier>& GetAccount3PIDsJob::thr BaseJob::Status GetAccount3PIDsJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->threepids = fromJson<QVector<ThirdPartyIdentifier>>(json.value("threepids")); + d->threepids = fromJson<QVector<ThirdPartyIdentifier>>(json.value("threepids"_ls)); return Success; } @@ -72,20 +74,22 @@ namespace QMatrixClient QJsonObject toJson(const Post3PIDsJob::ThreePidCredentials& pod) { QJsonObject _json; - addParam<>(_json, "client_secret", pod.clientSecret); - addParam<>(_json, "id_server", pod.idServer); - addParam<>(_json, "sid", pod.sid); + addParam<>(_json, QStringLiteral("client_secret"), pod.clientSecret); + addParam<>(_json, QStringLiteral("id_server"), pod.idServer); + addParam<>(_json, QStringLiteral("sid"), pod.sid); return _json; } } // namespace QMatrixClient +static const auto Post3PIDsJobName = QStringLiteral("Post3PIDsJob"); + Post3PIDsJob::Post3PIDsJob(const ThreePidCredentials& threePidCreds, bool bind) - : BaseJob(HttpVerb::Post, "Post3PIDsJob", + : BaseJob(HttpVerb::Post, Post3PIDsJobName, basePath % "/account/3pid") { QJsonObject _data; - addParam<>(_data, "three_pid_creds", threePidCreds); - addParam<IfNotEmpty>(_data, "bind", bind); + addParam<>(_data, QStringLiteral("three_pid_creds"), threePidCreds); + addParam<IfNotEmpty>(_data, QStringLiteral("bind"), bind); setRequestData(_data); } @@ -95,8 +99,10 @@ QUrl RequestTokenTo3PIDJob::makeRequestUrl(QUrl baseUrl) basePath % "/account/3pid/email/requestToken"); } +static const auto RequestTokenTo3PIDJobName = QStringLiteral("RequestTokenTo3PIDJob"); + RequestTokenTo3PIDJob::RequestTokenTo3PIDJob() - : BaseJob(HttpVerb::Post, "RequestTokenTo3PIDJob", + : BaseJob(HttpVerb::Post, RequestTokenTo3PIDJobName, basePath % "/account/3pid/email/requestToken", false) { } diff --git a/lib/csapi/banning.cpp b/lib/csapi/banning.cpp index 4dbd8a7d..4065207b 100644 --- a/lib/csapi/banning.cpp +++ b/lib/csapi/banning.cpp @@ -12,22 +12,26 @@ using namespace QMatrixClient; static const auto basePath = QStringLiteral("/_matrix/client/r0"); +static const auto BanJobName = QStringLiteral("BanJob"); + BanJob::BanJob(const QString& roomId, const QString& userId, const QString& reason) - : BaseJob(HttpVerb::Post, "BanJob", + : BaseJob(HttpVerb::Post, BanJobName, basePath % "/rooms/" % roomId % "/ban") { QJsonObject _data; - addParam<>(_data, "user_id", userId); - addParam<IfNotEmpty>(_data, "reason", reason); + addParam<>(_data, QStringLiteral("user_id"), userId); + addParam<IfNotEmpty>(_data, QStringLiteral("reason"), reason); setRequestData(_data); } +static const auto UnbanJobName = QStringLiteral("UnbanJob"); + UnbanJob::UnbanJob(const QString& roomId, const QString& userId) - : BaseJob(HttpVerb::Post, "UnbanJob", + : BaseJob(HttpVerb::Post, UnbanJobName, basePath % "/rooms/" % roomId % "/unban") { QJsonObject _data; - addParam<>(_data, "user_id", userId); + addParam<>(_data, QStringLiteral("user_id"), userId); setRequestData(_data); } diff --git a/lib/csapi/content-repo.cpp b/lib/csapi/content-repo.cpp index 4ce80d08..9ac226ba 100644 --- a/lib/csapi/content-repo.cpp +++ b/lib/csapi/content-repo.cpp @@ -22,12 +22,14 @@ class UploadContentJob::Private BaseJob::Query queryToUploadContent(const QString& filename) { BaseJob::Query _q; - addParam<IfNotEmpty>(_q, "filename", filename); + addParam<IfNotEmpty>(_q, QStringLiteral("filename"), filename); return _q; } +static const auto UploadContentJobName = QStringLiteral("UploadContentJob"); + UploadContentJob::UploadContentJob(QIODevice* content, const QString& filename, const QString& contentType) - : BaseJob(HttpVerb::Post, "UploadContentJob", + : BaseJob(HttpVerb::Post, UploadContentJobName, basePath % "/upload", queryToUploadContent(filename)) , d(new Private) @@ -47,10 +49,10 @@ const QString& UploadContentJob::contentUri() const BaseJob::Status UploadContentJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("content_uri")) + if (!json.contains("content_uri"_ls)) return { JsonParseError, "The key 'content_uri' not found in the response" }; - d->contentUri = fromJson<QString>(json.value("content_uri")); + d->contentUri = fromJson<QString>(json.value("content_uri"_ls)); return Success; } @@ -65,7 +67,7 @@ class GetContentJob::Private BaseJob::Query queryToGetContent(bool allowRemote) { BaseJob::Query _q; - addParam<IfNotEmpty>(_q, "allow_remote", allowRemote); + addParam<IfNotEmpty>(_q, QStringLiteral("allow_remote"), allowRemote); return _q; } @@ -76,8 +78,10 @@ QUrl GetContentJob::makeRequestUrl(QUrl baseUrl, const QString& serverName, cons queryToGetContent(allowRemote)); } +static const auto GetContentJobName = QStringLiteral("GetContentJob"); + GetContentJob::GetContentJob(const QString& serverName, const QString& mediaId, bool allowRemote) - : BaseJob(HttpVerb::Get, "GetContentJob", + : BaseJob(HttpVerb::Get, GetContentJobName, basePath % "/download/" % serverName % "/" % mediaId, queryToGetContent(allowRemote), {}, false) @@ -122,7 +126,7 @@ class GetContentOverrideNameJob::Private BaseJob::Query queryToGetContentOverrideName(bool allowRemote) { BaseJob::Query _q; - addParam<IfNotEmpty>(_q, "allow_remote", allowRemote); + addParam<IfNotEmpty>(_q, QStringLiteral("allow_remote"), allowRemote); return _q; } @@ -133,8 +137,10 @@ QUrl GetContentOverrideNameJob::makeRequestUrl(QUrl baseUrl, const QString& serv queryToGetContentOverrideName(allowRemote)); } +static const auto GetContentOverrideNameJobName = QStringLiteral("GetContentOverrideNameJob"); + GetContentOverrideNameJob::GetContentOverrideNameJob(const QString& serverName, const QString& mediaId, const QString& fileName, bool allowRemote) - : BaseJob(HttpVerb::Get, "GetContentOverrideNameJob", + : BaseJob(HttpVerb::Get, GetContentOverrideNameJobName, basePath % "/download/" % serverName % "/" % mediaId % "/" % fileName, queryToGetContentOverrideName(allowRemote), {}, false) @@ -178,10 +184,10 @@ class GetContentThumbnailJob::Private BaseJob::Query queryToGetContentThumbnail(int width, int height, const QString& method, bool allowRemote) { BaseJob::Query _q; - addParam<>(_q, "width", width); - addParam<>(_q, "height", height); - addParam<IfNotEmpty>(_q, "method", method); - addParam<IfNotEmpty>(_q, "allow_remote", allowRemote); + addParam<>(_q, QStringLiteral("width"), width); + addParam<>(_q, QStringLiteral("height"), height); + addParam<IfNotEmpty>(_q, QStringLiteral("method"), method); + addParam<IfNotEmpty>(_q, QStringLiteral("allow_remote"), allowRemote); return _q; } @@ -192,8 +198,10 @@ QUrl GetContentThumbnailJob::makeRequestUrl(QUrl baseUrl, const QString& serverN queryToGetContentThumbnail(width, height, method, allowRemote)); } +static const auto GetContentThumbnailJobName = QStringLiteral("GetContentThumbnailJob"); + GetContentThumbnailJob::GetContentThumbnailJob(const QString& serverName, const QString& mediaId, int width, int height, const QString& method, bool allowRemote) - : BaseJob(HttpVerb::Get, "GetContentThumbnailJob", + : BaseJob(HttpVerb::Get, GetContentThumbnailJobName, basePath % "/thumbnail/" % serverName % "/" % mediaId, queryToGetContentThumbnail(width, height, method, allowRemote), {}, false) @@ -231,8 +239,8 @@ class GetUrlPreviewJob::Private BaseJob::Query queryToGetUrlPreview(const QString& url, Omittable<qint64> ts) { BaseJob::Query _q; - addParam<>(_q, "url", url); - addParam<IfNotEmpty>(_q, "ts", ts); + addParam<>(_q, QStringLiteral("url"), url); + addParam<IfNotEmpty>(_q, QStringLiteral("ts"), ts); return _q; } @@ -243,8 +251,10 @@ QUrl GetUrlPreviewJob::makeRequestUrl(QUrl baseUrl, const QString& url, Omittabl queryToGetUrlPreview(url, ts)); } +static const auto GetUrlPreviewJobName = QStringLiteral("GetUrlPreviewJob"); + GetUrlPreviewJob::GetUrlPreviewJob(const QString& url, Omittable<qint64> ts) - : BaseJob(HttpVerb::Get, "GetUrlPreviewJob", + : BaseJob(HttpVerb::Get, GetUrlPreviewJobName, basePath % "/preview_url", queryToGetUrlPreview(url, ts)) , d(new Private) @@ -266,8 +276,8 @@ const QString& GetUrlPreviewJob::ogImage() const BaseJob::Status GetUrlPreviewJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->matrixImageSize = fromJson<qint64>(json.value("matrix:image:size")); - d->ogImage = fromJson<QString>(json.value("og:image")); + d->matrixImageSize = fromJson<qint64>(json.value("matrix:image:size"_ls)); + d->ogImage = fromJson<QString>(json.value("og:image"_ls)); return Success; } diff --git a/lib/csapi/create_room.cpp b/lib/csapi/create_room.cpp index 910210bc..5600e18a 100644 --- a/lib/csapi/create_room.cpp +++ b/lib/csapi/create_room.cpp @@ -19,18 +19,18 @@ namespace QMatrixClient QJsonObject toJson(const CreateRoomJob::Invite3pid& pod) { QJsonObject _json; - addParam<>(_json, "id_server", pod.idServer); - addParam<>(_json, "medium", pod.medium); - addParam<>(_json, "address", pod.address); + addParam<>(_json, QStringLiteral("id_server"), pod.idServer); + addParam<>(_json, QStringLiteral("medium"), pod.medium); + addParam<>(_json, QStringLiteral("address"), pod.address); return _json; } QJsonObject toJson(const CreateRoomJob::StateEvent& pod) { QJsonObject _json; - addParam<IfNotEmpty>(_json, "type", pod.type); - addParam<IfNotEmpty>(_json, "state_key", pod.stateKey); - addParam<IfNotEmpty>(_json, "content", pod.content); + addParam<IfNotEmpty>(_json, QStringLiteral("type"), pod.type); + addParam<IfNotEmpty>(_json, QStringLiteral("state_key"), pod.stateKey); + addParam<IfNotEmpty>(_json, QStringLiteral("content"), pod.content); return _json; } } // namespace QMatrixClient @@ -41,23 +41,25 @@ class CreateRoomJob::Private QString roomId; }; +static const auto CreateRoomJobName = QStringLiteral("CreateRoomJob"); + CreateRoomJob::CreateRoomJob(const QString& visibility, const QString& roomAliasName, const QString& name, const QString& topic, const QStringList& invite, const QVector<Invite3pid>& invite3pid, const QJsonObject& creationContent, const QVector<StateEvent>& initialState, const QString& preset, bool isDirect, bool guestCanJoin) - : BaseJob(HttpVerb::Post, "CreateRoomJob", + : BaseJob(HttpVerb::Post, CreateRoomJobName, basePath % "/createRoom") , d(new Private) { QJsonObject _data; - addParam<IfNotEmpty>(_data, "visibility", visibility); - addParam<IfNotEmpty>(_data, "room_alias_name", roomAliasName); - addParam<IfNotEmpty>(_data, "name", name); - addParam<IfNotEmpty>(_data, "topic", topic); - addParam<IfNotEmpty>(_data, "invite", invite); - addParam<IfNotEmpty>(_data, "invite_3pid", invite3pid); - addParam<IfNotEmpty>(_data, "creation_content", creationContent); - addParam<IfNotEmpty>(_data, "initial_state", initialState); - addParam<IfNotEmpty>(_data, "preset", preset); - addParam<IfNotEmpty>(_data, "is_direct", isDirect); - addParam<IfNotEmpty>(_data, "guest_can_join", guestCanJoin); + addParam<IfNotEmpty>(_data, QStringLiteral("visibility"), visibility); + addParam<IfNotEmpty>(_data, QStringLiteral("room_alias_name"), roomAliasName); + addParam<IfNotEmpty>(_data, QStringLiteral("name"), name); + addParam<IfNotEmpty>(_data, QStringLiteral("topic"), topic); + addParam<IfNotEmpty>(_data, QStringLiteral("invite"), invite); + addParam<IfNotEmpty>(_data, QStringLiteral("invite_3pid"), invite3pid); + addParam<IfNotEmpty>(_data, QStringLiteral("creation_content"), creationContent); + addParam<IfNotEmpty>(_data, QStringLiteral("initial_state"), initialState); + addParam<IfNotEmpty>(_data, QStringLiteral("preset"), preset); + addParam<IfNotEmpty>(_data, QStringLiteral("is_direct"), isDirect); + addParam<IfNotEmpty>(_data, QStringLiteral("guest_can_join"), guestCanJoin); setRequestData(_data); } @@ -71,7 +73,7 @@ const QString& CreateRoomJob::roomId() const BaseJob::Status CreateRoomJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->roomId = fromJson<QString>(json.value("room_id")); + d->roomId = fromJson<QString>(json.value("room_id"_ls)); return Success; } diff --git a/lib/csapi/definitions/client_device.cpp b/lib/csapi/definitions/client_device.cpp index 7c3d7ea6..bd7acd02 100644 --- a/lib/csapi/definitions/client_device.cpp +++ b/lib/csapi/definitions/client_device.cpp @@ -9,10 +9,10 @@ using namespace QMatrixClient; QJsonObject QMatrixClient::toJson(const Device& pod) { QJsonObject _json; - addParam<>(_json, "device_id", pod.deviceId); - addParam<IfNotEmpty>(_json, "display_name", pod.displayName); - addParam<IfNotEmpty>(_json, "last_seen_ip", pod.lastSeenIp); - addParam<IfNotEmpty>(_json, "last_seen_ts", pod.lastSeenTs); + addParam<>(_json, QStringLiteral("device_id"), pod.deviceId); + addParam<IfNotEmpty>(_json, QStringLiteral("display_name"), pod.displayName); + addParam<IfNotEmpty>(_json, QStringLiteral("last_seen_ip"), pod.lastSeenIp); + addParam<IfNotEmpty>(_json, QStringLiteral("last_seen_ts"), pod.lastSeenTs); return _json; } @@ -21,13 +21,13 @@ Device FromJson<Device>::operator()(const QJsonValue& jv) const auto& _json = jv.toObject(); Device result; result.deviceId = - fromJson<QString>(_json.value("device_id")); + fromJson<QString>(_json.value("device_id"_ls)); result.displayName = - fromJson<QString>(_json.value("display_name")); + fromJson<QString>(_json.value("display_name"_ls)); result.lastSeenIp = - fromJson<QString>(_json.value("last_seen_ip")); + fromJson<QString>(_json.value("last_seen_ip"_ls)); result.lastSeenTs = - fromJson<qint64>(_json.value("last_seen_ts")); + fromJson<qint64>(_json.value("last_seen_ts"_ls)); return result; } diff --git a/lib/csapi/definitions/device_keys.cpp b/lib/csapi/definitions/device_keys.cpp index 43cd5d2e..d17f4c12 100644 --- a/lib/csapi/definitions/device_keys.cpp +++ b/lib/csapi/definitions/device_keys.cpp @@ -9,11 +9,11 @@ using namespace QMatrixClient; QJsonObject QMatrixClient::toJson(const DeviceKeys& pod) { QJsonObject _json; - addParam<>(_json, "user_id", pod.userId); - addParam<>(_json, "device_id", pod.deviceId); - addParam<>(_json, "algorithms", pod.algorithms); - addParam<>(_json, "keys", pod.keys); - addParam<>(_json, "signatures", pod.signatures); + addParam<>(_json, QStringLiteral("user_id"), pod.userId); + addParam<>(_json, QStringLiteral("device_id"), pod.deviceId); + addParam<>(_json, QStringLiteral("algorithms"), pod.algorithms); + addParam<>(_json, QStringLiteral("keys"), pod.keys); + addParam<>(_json, QStringLiteral("signatures"), pod.signatures); return _json; } @@ -22,15 +22,15 @@ DeviceKeys FromJson<DeviceKeys>::operator()(const QJsonValue& jv) const auto& _json = jv.toObject(); DeviceKeys result; result.userId = - fromJson<QString>(_json.value("user_id")); + fromJson<QString>(_json.value("user_id"_ls)); result.deviceId = - fromJson<QString>(_json.value("device_id")); + fromJson<QString>(_json.value("device_id"_ls)); result.algorithms = - fromJson<QStringList>(_json.value("algorithms")); + fromJson<QStringList>(_json.value("algorithms"_ls)); result.keys = - fromJson<QHash<QString, QString>>(_json.value("keys")); + fromJson<QHash<QString, QString>>(_json.value("keys"_ls)); result.signatures = - fromJson<QHash<QString, QHash<QString, QString>>>(_json.value("signatures")); + fromJson<QHash<QString, QHash<QString, QString>>>(_json.value("signatures"_ls)); return result; } diff --git a/lib/csapi/definitions/event_filter.cpp b/lib/csapi/definitions/event_filter.cpp index 21ee2b81..336de0dd 100644 --- a/lib/csapi/definitions/event_filter.cpp +++ b/lib/csapi/definitions/event_filter.cpp @@ -9,11 +9,11 @@ using namespace QMatrixClient; QJsonObject QMatrixClient::toJson(const Filter& pod) { QJsonObject _json; - addParam<IfNotEmpty>(_json, "limit", pod.limit); - addParam<IfNotEmpty>(_json, "not_senders", pod.notSenders); - addParam<IfNotEmpty>(_json, "not_types", pod.notTypes); - addParam<IfNotEmpty>(_json, "senders", pod.senders); - addParam<IfNotEmpty>(_json, "types", pod.types); + addParam<IfNotEmpty>(_json, QStringLiteral("limit"), pod.limit); + addParam<IfNotEmpty>(_json, QStringLiteral("not_senders"), pod.notSenders); + addParam<IfNotEmpty>(_json, QStringLiteral("not_types"), pod.notTypes); + addParam<IfNotEmpty>(_json, QStringLiteral("senders"), pod.senders); + addParam<IfNotEmpty>(_json, QStringLiteral("types"), pod.types); return _json; } @@ -22,15 +22,15 @@ Filter FromJson<Filter>::operator()(const QJsonValue& jv) const auto& _json = jv.toObject(); Filter result; result.limit = - fromJson<int>(_json.value("limit")); + fromJson<int>(_json.value("limit"_ls)); result.notSenders = - fromJson<QStringList>(_json.value("not_senders")); + fromJson<QStringList>(_json.value("not_senders"_ls)); result.notTypes = - fromJson<QStringList>(_json.value("not_types")); + fromJson<QStringList>(_json.value("not_types"_ls)); result.senders = - fromJson<QStringList>(_json.value("senders")); + fromJson<QStringList>(_json.value("senders"_ls)); result.types = - fromJson<QStringList>(_json.value("types")); + fromJson<QStringList>(_json.value("types"_ls)); return result; } diff --git a/lib/csapi/definitions/push_condition.cpp b/lib/csapi/definitions/push_condition.cpp index b8595ec6..19351ae1 100644 --- a/lib/csapi/definitions/push_condition.cpp +++ b/lib/csapi/definitions/push_condition.cpp @@ -9,10 +9,10 @@ using namespace QMatrixClient; QJsonObject QMatrixClient::toJson(const PushCondition& pod) { QJsonObject _json; - addParam<>(_json, "kind", pod.kind); - addParam<IfNotEmpty>(_json, "key", pod.key); - addParam<IfNotEmpty>(_json, "pattern", pod.pattern); - addParam<IfNotEmpty>(_json, "is", pod.is); + addParam<>(_json, QStringLiteral("kind"), pod.kind); + addParam<IfNotEmpty>(_json, QStringLiteral("key"), pod.key); + addParam<IfNotEmpty>(_json, QStringLiteral("pattern"), pod.pattern); + addParam<IfNotEmpty>(_json, QStringLiteral("is"), pod.is); return _json; } @@ -21,13 +21,13 @@ PushCondition FromJson<PushCondition>::operator()(const QJsonValue& jv) const auto& _json = jv.toObject(); PushCondition result; result.kind = - fromJson<QString>(_json.value("kind")); + fromJson<QString>(_json.value("kind"_ls)); result.key = - fromJson<QString>(_json.value("key")); + fromJson<QString>(_json.value("key"_ls)); result.pattern = - fromJson<QString>(_json.value("pattern")); + fromJson<QString>(_json.value("pattern"_ls)); result.is = - fromJson<QString>(_json.value("is")); + fromJson<QString>(_json.value("is"_ls)); return result; } diff --git a/lib/csapi/definitions/push_rule.cpp b/lib/csapi/definitions/push_rule.cpp index 98f5d788..833135ec 100644 --- a/lib/csapi/definitions/push_rule.cpp +++ b/lib/csapi/definitions/push_rule.cpp @@ -9,12 +9,12 @@ using namespace QMatrixClient; QJsonObject QMatrixClient::toJson(const PushRule& pod) { QJsonObject _json; - addParam<>(_json, "actions", pod.actions); - addParam<>(_json, "default", pod.isDefault); - addParam<>(_json, "enabled", pod.enabled); - addParam<>(_json, "rule_id", pod.ruleId); - addParam<IfNotEmpty>(_json, "conditions", pod.conditions); - addParam<IfNotEmpty>(_json, "pattern", pod.pattern); + addParam<>(_json, QStringLiteral("actions"), pod.actions); + addParam<>(_json, QStringLiteral("default"), pod.isDefault); + addParam<>(_json, QStringLiteral("enabled"), pod.enabled); + addParam<>(_json, QStringLiteral("rule_id"), pod.ruleId); + addParam<IfNotEmpty>(_json, QStringLiteral("conditions"), pod.conditions); + addParam<IfNotEmpty>(_json, QStringLiteral("pattern"), pod.pattern); return _json; } @@ -23,17 +23,17 @@ PushRule FromJson<PushRule>::operator()(const QJsonValue& jv) const auto& _json = jv.toObject(); PushRule result; result.actions = - fromJson<QVector<QVariant>>(_json.value("actions")); + fromJson<QVector<QVariant>>(_json.value("actions"_ls)); result.isDefault = - fromJson<bool>(_json.value("default")); + fromJson<bool>(_json.value("default"_ls)); result.enabled = - fromJson<bool>(_json.value("enabled")); + fromJson<bool>(_json.value("enabled"_ls)); result.ruleId = - fromJson<QString>(_json.value("rule_id")); + fromJson<QString>(_json.value("rule_id"_ls)); result.conditions = - fromJson<QVector<PushCondition>>(_json.value("conditions")); + fromJson<QVector<PushCondition>>(_json.value("conditions"_ls)); result.pattern = - fromJson<QString>(_json.value("pattern")); + fromJson<QString>(_json.value("pattern"_ls)); return result; } diff --git a/lib/csapi/definitions/push_ruleset.cpp b/lib/csapi/definitions/push_ruleset.cpp index ca2bbc0d..c424f686 100644 --- a/lib/csapi/definitions/push_ruleset.cpp +++ b/lib/csapi/definitions/push_ruleset.cpp @@ -9,11 +9,11 @@ using namespace QMatrixClient; QJsonObject QMatrixClient::toJson(const PushRuleset& pod) { QJsonObject _json; - addParam<IfNotEmpty>(_json, "content", pod.content); - addParam<IfNotEmpty>(_json, "override", pod.override); - addParam<IfNotEmpty>(_json, "room", pod.room); - addParam<IfNotEmpty>(_json, "sender", pod.sender); - addParam<IfNotEmpty>(_json, "underride", pod.underride); + addParam<IfNotEmpty>(_json, QStringLiteral("content"), pod.content); + addParam<IfNotEmpty>(_json, QStringLiteral("override"), pod.override); + addParam<IfNotEmpty>(_json, QStringLiteral("room"), pod.room); + addParam<IfNotEmpty>(_json, QStringLiteral("sender"), pod.sender); + addParam<IfNotEmpty>(_json, QStringLiteral("underride"), pod.underride); return _json; } @@ -22,15 +22,15 @@ PushRuleset FromJson<PushRuleset>::operator()(const QJsonValue& jv) const auto& _json = jv.toObject(); PushRuleset result; result.content = - fromJson<QVector<PushRule>>(_json.value("content")); + fromJson<QVector<PushRule>>(_json.value("content"_ls)); result.override = - fromJson<QVector<PushRule>>(_json.value("override")); + fromJson<QVector<PushRule>>(_json.value("override"_ls)); result.room = - fromJson<QVector<PushRule>>(_json.value("room")); + fromJson<QVector<PushRule>>(_json.value("room"_ls)); result.sender = - fromJson<QVector<PushRule>>(_json.value("sender")); + fromJson<QVector<PushRule>>(_json.value("sender"_ls)); result.underride = - fromJson<QVector<PushRule>>(_json.value("underride")); + fromJson<QVector<PushRule>>(_json.value("underride"_ls)); return result; } diff --git a/lib/csapi/definitions/room_event_filter.cpp b/lib/csapi/definitions/room_event_filter.cpp index 1702be22..18ce07ec 100644 --- a/lib/csapi/definitions/room_event_filter.cpp +++ b/lib/csapi/definitions/room_event_filter.cpp @@ -9,9 +9,9 @@ using namespace QMatrixClient; QJsonObject QMatrixClient::toJson(const RoomEventFilter& pod) { QJsonObject _json; - addParam<IfNotEmpty>(_json, "not_rooms", pod.notRooms); - addParam<IfNotEmpty>(_json, "rooms", pod.rooms); - addParam<IfNotEmpty>(_json, "contains_url", pod.containsUrl); + addParam<IfNotEmpty>(_json, QStringLiteral("not_rooms"), pod.notRooms); + addParam<IfNotEmpty>(_json, QStringLiteral("rooms"), pod.rooms); + addParam<IfNotEmpty>(_json, QStringLiteral("contains_url"), pod.containsUrl); return _json; } @@ -20,11 +20,11 @@ RoomEventFilter FromJson<RoomEventFilter>::operator()(const QJsonValue& jv) const auto& _json = jv.toObject(); RoomEventFilter result; result.notRooms = - fromJson<QStringList>(_json.value("not_rooms")); + fromJson<QStringList>(_json.value("not_rooms"_ls)); result.rooms = - fromJson<QStringList>(_json.value("rooms")); + fromJson<QStringList>(_json.value("rooms"_ls)); result.containsUrl = - fromJson<bool>(_json.value("contains_url")); + fromJson<bool>(_json.value("contains_url"_ls)); return result; } diff --git a/lib/csapi/definitions/sync_filter.cpp b/lib/csapi/definitions/sync_filter.cpp index 2b5cf8be..b42f15f5 100644 --- a/lib/csapi/definitions/sync_filter.cpp +++ b/lib/csapi/definitions/sync_filter.cpp @@ -9,13 +9,13 @@ using namespace QMatrixClient; QJsonObject QMatrixClient::toJson(const RoomFilter& pod) { QJsonObject _json; - addParam<IfNotEmpty>(_json, "not_rooms", pod.notRooms); - addParam<IfNotEmpty>(_json, "rooms", pod.rooms); - addParam<IfNotEmpty>(_json, "ephemeral", pod.ephemeral); - addParam<IfNotEmpty>(_json, "include_leave", pod.includeLeave); - addParam<IfNotEmpty>(_json, "state", pod.state); - addParam<IfNotEmpty>(_json, "timeline", pod.timeline); - addParam<IfNotEmpty>(_json, "account_data", pod.accountData); + addParam<IfNotEmpty>(_json, QStringLiteral("not_rooms"), pod.notRooms); + addParam<IfNotEmpty>(_json, QStringLiteral("rooms"), pod.rooms); + addParam<IfNotEmpty>(_json, QStringLiteral("ephemeral"), pod.ephemeral); + addParam<IfNotEmpty>(_json, QStringLiteral("include_leave"), pod.includeLeave); + addParam<IfNotEmpty>(_json, QStringLiteral("state"), pod.state); + addParam<IfNotEmpty>(_json, QStringLiteral("timeline"), pod.timeline); + addParam<IfNotEmpty>(_json, QStringLiteral("account_data"), pod.accountData); return _json; } @@ -24,19 +24,19 @@ RoomFilter FromJson<RoomFilter>::operator()(const QJsonValue& jv) const auto& _json = jv.toObject(); RoomFilter result; result.notRooms = - fromJson<QStringList>(_json.value("not_rooms")); + fromJson<QStringList>(_json.value("not_rooms"_ls)); result.rooms = - fromJson<QStringList>(_json.value("rooms")); + fromJson<QStringList>(_json.value("rooms"_ls)); result.ephemeral = - fromJson<RoomEventFilter>(_json.value("ephemeral")); + fromJson<RoomEventFilter>(_json.value("ephemeral"_ls)); result.includeLeave = - fromJson<bool>(_json.value("include_leave")); + fromJson<bool>(_json.value("include_leave"_ls)); result.state = - fromJson<RoomEventFilter>(_json.value("state")); + fromJson<RoomEventFilter>(_json.value("state"_ls)); result.timeline = - fromJson<RoomEventFilter>(_json.value("timeline")); + fromJson<RoomEventFilter>(_json.value("timeline"_ls)); result.accountData = - fromJson<RoomEventFilter>(_json.value("account_data")); + fromJson<RoomEventFilter>(_json.value("account_data"_ls)); return result; } @@ -44,11 +44,11 @@ RoomFilter FromJson<RoomFilter>::operator()(const QJsonValue& jv) QJsonObject QMatrixClient::toJson(const SyncFilter& pod) { QJsonObject _json; - addParam<IfNotEmpty>(_json, "event_fields", pod.eventFields); - addParam<IfNotEmpty>(_json, "event_format", pod.eventFormat); - addParam<IfNotEmpty>(_json, "presence", pod.presence); - addParam<IfNotEmpty>(_json, "account_data", pod.accountData); - addParam<IfNotEmpty>(_json, "room", pod.room); + addParam<IfNotEmpty>(_json, QStringLiteral("event_fields"), pod.eventFields); + addParam<IfNotEmpty>(_json, QStringLiteral("event_format"), pod.eventFormat); + addParam<IfNotEmpty>(_json, QStringLiteral("presence"), pod.presence); + addParam<IfNotEmpty>(_json, QStringLiteral("account_data"), pod.accountData); + addParam<IfNotEmpty>(_json, QStringLiteral("room"), pod.room); return _json; } @@ -57,15 +57,15 @@ SyncFilter FromJson<SyncFilter>::operator()(const QJsonValue& jv) const auto& _json = jv.toObject(); SyncFilter result; result.eventFields = - fromJson<QStringList>(_json.value("event_fields")); + fromJson<QStringList>(_json.value("event_fields"_ls)); result.eventFormat = - fromJson<QString>(_json.value("event_format")); + fromJson<QString>(_json.value("event_format"_ls)); result.presence = - fromJson<Filter>(_json.value("presence")); + fromJson<Filter>(_json.value("presence"_ls)); result.accountData = - fromJson<Filter>(_json.value("account_data")); + fromJson<Filter>(_json.value("account_data"_ls)); result.room = - fromJson<RoomFilter>(_json.value("room")); + fromJson<RoomFilter>(_json.value("room"_ls)); return result; } diff --git a/lib/csapi/device_management.cpp b/lib/csapi/device_management.cpp index a4b2daae..bbc7e674 100644 --- a/lib/csapi/device_management.cpp +++ b/lib/csapi/device_management.cpp @@ -24,8 +24,10 @@ QUrl GetDevicesJob::makeRequestUrl(QUrl baseUrl) basePath % "/devices"); } +static const auto GetDevicesJobName = QStringLiteral("GetDevicesJob"); + GetDevicesJob::GetDevicesJob() - : BaseJob(HttpVerb::Get, "GetDevicesJob", + : BaseJob(HttpVerb::Get, GetDevicesJobName, basePath % "/devices") , d(new Private) { @@ -41,7 +43,7 @@ const QVector<Device>& GetDevicesJob::devices() const BaseJob::Status GetDevicesJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->devices = fromJson<QVector<Device>>(json.value("devices")); + d->devices = fromJson<QVector<Device>>(json.value("devices"_ls)); return Success; } @@ -57,8 +59,10 @@ QUrl GetDeviceJob::makeRequestUrl(QUrl baseUrl, const QString& deviceId) basePath % "/devices/" % deviceId); } +static const auto GetDeviceJobName = QStringLiteral("GetDeviceJob"); + GetDeviceJob::GetDeviceJob(const QString& deviceId) - : BaseJob(HttpVerb::Get, "GetDeviceJob", + : BaseJob(HttpVerb::Get, GetDeviceJobName, basePath % "/devices/" % deviceId) , d(new Private) { @@ -74,38 +78,44 @@ const Device& GetDeviceJob::data() const BaseJob::Status GetDeviceJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("data")) + if (!json.contains("data"_ls)) return { JsonParseError, "The key 'data' not found in the response" }; - d->data = fromJson<Device>(json.value("data")); + d->data = fromJson<Device>(json.value("data"_ls)); return Success; } +static const auto UpdateDeviceJobName = QStringLiteral("UpdateDeviceJob"); + UpdateDeviceJob::UpdateDeviceJob(const QString& deviceId, const QString& displayName) - : BaseJob(HttpVerb::Put, "UpdateDeviceJob", + : BaseJob(HttpVerb::Put, UpdateDeviceJobName, basePath % "/devices/" % deviceId) { QJsonObject _data; - addParam<IfNotEmpty>(_data, "display_name", displayName); + addParam<IfNotEmpty>(_data, QStringLiteral("display_name"), displayName); setRequestData(_data); } +static const auto DeleteDeviceJobName = QStringLiteral("DeleteDeviceJob"); + DeleteDeviceJob::DeleteDeviceJob(const QString& deviceId, const QJsonObject& auth) - : BaseJob(HttpVerb::Delete, "DeleteDeviceJob", + : BaseJob(HttpVerb::Delete, DeleteDeviceJobName, basePath % "/devices/" % deviceId) { QJsonObject _data; - addParam<IfNotEmpty>(_data, "auth", auth); + addParam<IfNotEmpty>(_data, QStringLiteral("auth"), auth); setRequestData(_data); } +static const auto DeleteDevicesJobName = QStringLiteral("DeleteDevicesJob"); + DeleteDevicesJob::DeleteDevicesJob(const QStringList& devices, const QJsonObject& auth) - : BaseJob(HttpVerb::Post, "DeleteDevicesJob", + : BaseJob(HttpVerb::Post, DeleteDevicesJobName, basePath % "/delete_devices") { QJsonObject _data; - addParam<>(_data, "devices", devices); - addParam<IfNotEmpty>(_data, "auth", auth); + addParam<>(_data, QStringLiteral("devices"), devices); + addParam<IfNotEmpty>(_data, QStringLiteral("auth"), auth); setRequestData(_data); } diff --git a/lib/csapi/directory.cpp b/lib/csapi/directory.cpp index 7e8b87b8..fd3b8839 100644 --- a/lib/csapi/directory.cpp +++ b/lib/csapi/directory.cpp @@ -12,12 +12,14 @@ using namespace QMatrixClient; static const auto basePath = QStringLiteral("/_matrix/client/r0/directory"); +static const auto SetRoomAliasJobName = QStringLiteral("SetRoomAliasJob"); + SetRoomAliasJob::SetRoomAliasJob(const QString& roomAlias, const QString& roomId) - : BaseJob(HttpVerb::Put, "SetRoomAliasJob", + : BaseJob(HttpVerb::Put, SetRoomAliasJobName, basePath % "/room/" % roomAlias) { QJsonObject _data; - addParam<IfNotEmpty>(_data, "room_id", roomId); + addParam<IfNotEmpty>(_data, QStringLiteral("room_id"), roomId); setRequestData(_data); } @@ -34,8 +36,10 @@ QUrl GetRoomIdByAliasJob::makeRequestUrl(QUrl baseUrl, const QString& roomAlias) basePath % "/room/" % roomAlias); } +static const auto GetRoomIdByAliasJobName = QStringLiteral("GetRoomIdByAliasJob"); + GetRoomIdByAliasJob::GetRoomIdByAliasJob(const QString& roomAlias) - : BaseJob(HttpVerb::Get, "GetRoomIdByAliasJob", + : BaseJob(HttpVerb::Get, GetRoomIdByAliasJobName, basePath % "/room/" % roomAlias, false) , d(new Private) { @@ -56,8 +60,8 @@ const QStringList& GetRoomIdByAliasJob::servers() const BaseJob::Status GetRoomIdByAliasJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->roomId = fromJson<QString>(json.value("room_id")); - d->servers = fromJson<QStringList>(json.value("servers")); + d->roomId = fromJson<QString>(json.value("room_id"_ls)); + d->servers = fromJson<QStringList>(json.value("servers"_ls)); return Success; } @@ -67,8 +71,10 @@ QUrl DeleteRoomAliasJob::makeRequestUrl(QUrl baseUrl, const QString& roomAlias) basePath % "/room/" % roomAlias); } +static const auto DeleteRoomAliasJobName = QStringLiteral("DeleteRoomAliasJob"); + DeleteRoomAliasJob::DeleteRoomAliasJob(const QString& roomAlias) - : BaseJob(HttpVerb::Delete, "DeleteRoomAliasJob", + : BaseJob(HttpVerb::Delete, DeleteRoomAliasJobName, basePath % "/room/" % roomAlias) { } diff --git a/lib/csapi/event_context.cpp b/lib/csapi/event_context.cpp index 9e4c6963..806c1613 100644 --- a/lib/csapi/event_context.cpp +++ b/lib/csapi/event_context.cpp @@ -26,7 +26,7 @@ class GetEventContextJob::Private BaseJob::Query queryToGetEventContext(Omittable<int> limit) { BaseJob::Query _q; - addParam<IfNotEmpty>(_q, "limit", limit); + addParam<IfNotEmpty>(_q, QStringLiteral("limit"), limit); return _q; } @@ -37,8 +37,10 @@ QUrl GetEventContextJob::makeRequestUrl(QUrl baseUrl, const QString& roomId, con queryToGetEventContext(limit)); } +static const auto GetEventContextJobName = QStringLiteral("GetEventContextJob"); + GetEventContextJob::GetEventContextJob(const QString& roomId, const QString& eventId, Omittable<int> limit) - : BaseJob(HttpVerb::Get, "GetEventContextJob", + : BaseJob(HttpVerb::Get, GetEventContextJobName, basePath % "/rooms/" % roomId % "/context/" % eventId, queryToGetEventContext(limit)) , d(new Private) @@ -80,12 +82,12 @@ StateEvents&& GetEventContextJob::state() BaseJob::Status GetEventContextJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->begin = fromJson<QString>(json.value("start")); - d->end = fromJson<QString>(json.value("end")); - d->eventsBefore = fromJson<RoomEvents>(json.value("events_before")); - d->event = fromJson<RoomEventPtr>(json.value("event")); - d->eventsAfter = fromJson<RoomEvents>(json.value("events_after")); - d->state = fromJson<StateEvents>(json.value("state")); + d->begin = fromJson<QString>(json.value("start"_ls)); + d->end = fromJson<QString>(json.value("end"_ls)); + d->eventsBefore = fromJson<RoomEvents>(json.value("events_before"_ls)); + d->event = fromJson<RoomEventPtr>(json.value("event"_ls)); + d->eventsAfter = fromJson<RoomEvents>(json.value("events_after"_ls)); + d->state = fromJson<StateEvents>(json.value("state"_ls)); return Success; } diff --git a/lib/csapi/event_context.h b/lib/csapi/event_context.h index 0470ba36..22c9cbc3 100644 --- a/lib/csapi/event_context.h +++ b/lib/csapi/event_context.h @@ -6,7 +6,7 @@ #include "jobs/basejob.h" -#include "events/event.h" +#include "events/eventloader.h" #include "converters.h" namespace QMatrixClient diff --git a/lib/csapi/filter.cpp b/lib/csapi/filter.cpp index a1546923..51056cc3 100644 --- a/lib/csapi/filter.cpp +++ b/lib/csapi/filter.cpp @@ -18,8 +18,10 @@ class DefineFilterJob::Private QString filterId; }; +static const auto DefineFilterJobName = QStringLiteral("DefineFilterJob"); + DefineFilterJob::DefineFilterJob(const QString& userId, const SyncFilter& filter) - : BaseJob(HttpVerb::Post, "DefineFilterJob", + : BaseJob(HttpVerb::Post, DefineFilterJobName, basePath % "/user/" % userId % "/filter") , d(new Private) { @@ -36,7 +38,7 @@ const QString& DefineFilterJob::filterId() const BaseJob::Status DefineFilterJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->filterId = fromJson<QString>(json.value("filter_id")); + d->filterId = fromJson<QString>(json.value("filter_id"_ls)); return Success; } @@ -52,8 +54,10 @@ QUrl GetFilterJob::makeRequestUrl(QUrl baseUrl, const QString& userId, const QSt basePath % "/user/" % userId % "/filter/" % filterId); } +static const auto GetFilterJobName = QStringLiteral("GetFilterJob"); + GetFilterJob::GetFilterJob(const QString& userId, const QString& filterId) - : BaseJob(HttpVerb::Get, "GetFilterJob", + : BaseJob(HttpVerb::Get, GetFilterJobName, basePath % "/user/" % userId % "/filter/" % filterId) , d(new Private) { @@ -69,10 +73,10 @@ const SyncFilter& GetFilterJob::data() const BaseJob::Status GetFilterJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("data")) + if (!json.contains("data"_ls)) return { JsonParseError, "The key 'data' not found in the response" }; - d->data = fromJson<SyncFilter>(json.value("data")); + d->data = fromJson<SyncFilter>(json.value("data"_ls)); return Success; } diff --git a/lib/csapi/gtad.yaml b/lib/csapi/gtad.yaml index 3d1b7e88..09344be5 100644 --- a/lib/csapi/gtad.yaml +++ b/lib/csapi/gtad.yaml @@ -62,11 +62,11 @@ analyzer: - +set: { moveOnly: } +on: - /state_event.yaml$/: - { type: StateEventPtr, imports: '"events/event.h"' } + { type: StateEventPtr, imports: '"events/eventloader.h"' } - /room_event.yaml$/: - { type: RoomEventPtr, imports: '"events/event.h"' } + { type: RoomEventPtr, imports: '"events/eventloader.h"' } - /event.yaml$/: - { type: EventPtr, imports: '"events/event.h"' } + { type: EventPtr, imports: '"events/eventloader.h"' } - /auth_data.yaml$/: *QJsonObject # GTAD 0.6 cannot cope with this one - /m\.room\.member$/: pass # This $ref is only used in an array, see below - //: *UseOmittable # Also apply "avoidCopy" to all other ref'ed types @@ -79,7 +79,7 @@ analyzer: +on: - /^Notification|Result$/: type: "std::vector<{{1}}>" - imports: '"events/event.h"' + imports: '"events/eventloader.h"' - /m\.room\.member$/: type: "EventsArray<RoomMemberEvent>" imports: '"events/roommemberevent.h"' diff --git a/lib/csapi/inviting.cpp b/lib/csapi/inviting.cpp index 94e0910b..7dc33b18 100644 --- a/lib/csapi/inviting.cpp +++ b/lib/csapi/inviting.cpp @@ -12,12 +12,14 @@ using namespace QMatrixClient; static const auto basePath = QStringLiteral("/_matrix/client/r0"); +static const auto InviteUserJobName = QStringLiteral("InviteUserJob"); + InviteUserJob::InviteUserJob(const QString& roomId, const QString& userId) - : BaseJob(HttpVerb::Post, "InviteUserJob", + : BaseJob(HttpVerb::Post, InviteUserJobName, basePath % "/rooms/" % roomId % "/invite") { QJsonObject _data; - addParam<>(_data, "user_id", userId); + addParam<>(_data, QStringLiteral("user_id"), userId); setRequestData(_data); } diff --git a/lib/csapi/joining.cpp b/lib/csapi/joining.cpp index f2d6fbf7..0a4618af 100644 --- a/lib/csapi/joining.cpp +++ b/lib/csapi/joining.cpp @@ -19,10 +19,10 @@ namespace QMatrixClient QJsonObject toJson(const JoinRoomByIdJob::ThirdPartySigned& pod) { QJsonObject _json; - addParam<>(_json, "sender", pod.sender); - addParam<>(_json, "mxid", pod.mxid); - addParam<>(_json, "token", pod.token); - addParam<>(_json, "signatures", pod.signatures); + addParam<>(_json, QStringLiteral("sender"), pod.sender); + addParam<>(_json, QStringLiteral("mxid"), pod.mxid); + addParam<>(_json, QStringLiteral("token"), pod.token); + addParam<>(_json, QStringLiteral("signatures"), pod.signatures); return _json; } } // namespace QMatrixClient @@ -33,13 +33,15 @@ class JoinRoomByIdJob::Private QString roomId; }; +static const auto JoinRoomByIdJobName = QStringLiteral("JoinRoomByIdJob"); + JoinRoomByIdJob::JoinRoomByIdJob(const QString& roomId, const Omittable<ThirdPartySigned>& thirdPartySigned) - : BaseJob(HttpVerb::Post, "JoinRoomByIdJob", + : BaseJob(HttpVerb::Post, JoinRoomByIdJobName, basePath % "/rooms/" % roomId % "/join") , d(new Private) { QJsonObject _data; - addParam<IfNotEmpty>(_data, "third_party_signed", thirdPartySigned); + addParam<IfNotEmpty>(_data, QStringLiteral("third_party_signed"), thirdPartySigned); setRequestData(_data); } @@ -53,10 +55,10 @@ const QString& JoinRoomByIdJob::roomId() const BaseJob::Status JoinRoomByIdJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("room_id")) + if (!json.contains("room_id"_ls)) return { JsonParseError, "The key 'room_id' not found in the response" }; - d->roomId = fromJson<QString>(json.value("room_id")); + d->roomId = fromJson<QString>(json.value("room_id"_ls)); return Success; } @@ -67,17 +69,17 @@ namespace QMatrixClient QJsonObject toJson(const JoinRoomJob::Signed& pod) { QJsonObject _json; - addParam<>(_json, "sender", pod.sender); - addParam<>(_json, "mxid", pod.mxid); - addParam<>(_json, "token", pod.token); - addParam<>(_json, "signatures", pod.signatures); + addParam<>(_json, QStringLiteral("sender"), pod.sender); + addParam<>(_json, QStringLiteral("mxid"), pod.mxid); + addParam<>(_json, QStringLiteral("token"), pod.token); + addParam<>(_json, QStringLiteral("signatures"), pod.signatures); return _json; } QJsonObject toJson(const JoinRoomJob::ThirdPartySigned& pod) { QJsonObject _json; - addParam<>(_json, "signed", pod.signedData); + addParam<>(_json, QStringLiteral("signed"), pod.signedData); return _json; } } // namespace QMatrixClient @@ -88,13 +90,15 @@ class JoinRoomJob::Private QString roomId; }; +static const auto JoinRoomJobName = QStringLiteral("JoinRoomJob"); + JoinRoomJob::JoinRoomJob(const QString& roomIdOrAlias, const Omittable<ThirdPartySigned>& thirdPartySigned) - : BaseJob(HttpVerb::Post, "JoinRoomJob", + : BaseJob(HttpVerb::Post, JoinRoomJobName, basePath % "/join/" % roomIdOrAlias) , d(new Private) { QJsonObject _data; - addParam<IfNotEmpty>(_data, "third_party_signed", thirdPartySigned); + addParam<IfNotEmpty>(_data, QStringLiteral("third_party_signed"), thirdPartySigned); setRequestData(_data); } @@ -108,10 +112,10 @@ const QString& JoinRoomJob::roomId() const BaseJob::Status JoinRoomJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("room_id")) + if (!json.contains("room_id"_ls)) return { JsonParseError, "The key 'room_id' not found in the response" }; - d->roomId = fromJson<QString>(json.value("room_id")); + d->roomId = fromJson<QString>(json.value("room_id"_ls)); return Success; } diff --git a/lib/csapi/keys.cpp b/lib/csapi/keys.cpp index 4a76b7e2..fac811d0 100644 --- a/lib/csapi/keys.cpp +++ b/lib/csapi/keys.cpp @@ -18,14 +18,16 @@ class UploadKeysJob::Private QHash<QString, int> oneTimeKeyCounts; }; +static const auto UploadKeysJobName = QStringLiteral("UploadKeysJob"); + UploadKeysJob::UploadKeysJob(const Omittable<DeviceKeys>& deviceKeys, const QHash<QString, QVariant>& oneTimeKeys) - : BaseJob(HttpVerb::Post, "UploadKeysJob", + : BaseJob(HttpVerb::Post, UploadKeysJobName, basePath % "/keys/upload") , d(new Private) { QJsonObject _data; - addParam<IfNotEmpty>(_data, "device_keys", deviceKeys); - addParam<IfNotEmpty>(_data, "one_time_keys", oneTimeKeys); + addParam<IfNotEmpty>(_data, QStringLiteral("device_keys"), deviceKeys); + addParam<IfNotEmpty>(_data, QStringLiteral("one_time_keys"), oneTimeKeys); setRequestData(_data); } @@ -39,10 +41,10 @@ const QHash<QString, int>& UploadKeysJob::oneTimeKeyCounts() const BaseJob::Status UploadKeysJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("one_time_key_counts")) + if (!json.contains("one_time_key_counts"_ls)) return { JsonParseError, "The key 'one_time_key_counts' not found in the response" }; - d->oneTimeKeyCounts = fromJson<QHash<QString, int>>(json.value("one_time_key_counts")); + d->oneTimeKeyCounts = fromJson<QHash<QString, int>>(json.value("one_time_key_counts"_ls)); return Success; } @@ -57,7 +59,7 @@ namespace QMatrixClient const auto& _json = jv.toObject(); QueryKeysJob::UnsignedDeviceInfo result; result.deviceDisplayName = - fromJson<QString>(_json.value("device_display_name")); + fromJson<QString>(_json.value("device_display_name"_ls)); return result; } @@ -70,7 +72,7 @@ namespace QMatrixClient const auto& _json = jv.toObject(); QueryKeysJob::DeviceInformation result; result.unsignedData = - fromJson<QueryKeysJob::UnsignedDeviceInfo>(_json.value("unsigned")); + fromJson<QueryKeysJob::UnsignedDeviceInfo>(_json.value("unsigned"_ls)); return result; } @@ -84,15 +86,17 @@ class QueryKeysJob::Private QHash<QString, QHash<QString, DeviceInformation>> deviceKeys; }; +static const auto QueryKeysJobName = QStringLiteral("QueryKeysJob"); + QueryKeysJob::QueryKeysJob(const QHash<QString, QStringList>& deviceKeys, Omittable<int> timeout, const QString& token) - : BaseJob(HttpVerb::Post, "QueryKeysJob", + : BaseJob(HttpVerb::Post, QueryKeysJobName, basePath % "/keys/query") , d(new Private) { QJsonObject _data; - addParam<IfNotEmpty>(_data, "timeout", timeout); - addParam<>(_data, "device_keys", deviceKeys); - addParam<IfNotEmpty>(_data, "token", token); + addParam<IfNotEmpty>(_data, QStringLiteral("timeout"), timeout); + addParam<>(_data, QStringLiteral("device_keys"), deviceKeys); + addParam<IfNotEmpty>(_data, QStringLiteral("token"), token); setRequestData(_data); } @@ -111,8 +115,8 @@ const QHash<QString, QHash<QString, QueryKeysJob::DeviceInformation>>& QueryKeys BaseJob::Status QueryKeysJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->failures = fromJson<QHash<QString, QJsonObject>>(json.value("failures")); - d->deviceKeys = fromJson<QHash<QString, QHash<QString, DeviceInformation>>>(json.value("device_keys")); + d->failures = fromJson<QHash<QString, QJsonObject>>(json.value("failures"_ls)); + d->deviceKeys = fromJson<QHash<QString, QHash<QString, DeviceInformation>>>(json.value("device_keys"_ls)); return Success; } @@ -123,14 +127,16 @@ class ClaimKeysJob::Private QHash<QString, QHash<QString, QVariant>> oneTimeKeys; }; +static const auto ClaimKeysJobName = QStringLiteral("ClaimKeysJob"); + ClaimKeysJob::ClaimKeysJob(const QHash<QString, QHash<QString, QString>>& oneTimeKeys, Omittable<int> timeout) - : BaseJob(HttpVerb::Post, "ClaimKeysJob", + : BaseJob(HttpVerb::Post, ClaimKeysJobName, basePath % "/keys/claim") , d(new Private) { QJsonObject _data; - addParam<IfNotEmpty>(_data, "timeout", timeout); - addParam<>(_data, "one_time_keys", oneTimeKeys); + addParam<IfNotEmpty>(_data, QStringLiteral("timeout"), timeout); + addParam<>(_data, QStringLiteral("one_time_keys"), oneTimeKeys); setRequestData(_data); } @@ -149,8 +155,8 @@ const QHash<QString, QHash<QString, QVariant>>& ClaimKeysJob::oneTimeKeys() cons BaseJob::Status ClaimKeysJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->failures = fromJson<QHash<QString, QJsonObject>>(json.value("failures")); - d->oneTimeKeys = fromJson<QHash<QString, QHash<QString, QVariant>>>(json.value("one_time_keys")); + d->failures = fromJson<QHash<QString, QJsonObject>>(json.value("failures"_ls)); + d->oneTimeKeys = fromJson<QHash<QString, QHash<QString, QVariant>>>(json.value("one_time_keys"_ls)); return Success; } @@ -164,8 +170,8 @@ class GetKeysChangesJob::Private BaseJob::Query queryToGetKeysChanges(const QString& from, const QString& to) { BaseJob::Query _q; - addParam<>(_q, "from", from); - addParam<>(_q, "to", to); + addParam<>(_q, QStringLiteral("from"), from); + addParam<>(_q, QStringLiteral("to"), to); return _q; } @@ -176,8 +182,10 @@ QUrl GetKeysChangesJob::makeRequestUrl(QUrl baseUrl, const QString& from, const queryToGetKeysChanges(from, to)); } +static const auto GetKeysChangesJobName = QStringLiteral("GetKeysChangesJob"); + GetKeysChangesJob::GetKeysChangesJob(const QString& from, const QString& to) - : BaseJob(HttpVerb::Get, "GetKeysChangesJob", + : BaseJob(HttpVerb::Get, GetKeysChangesJobName, basePath % "/keys/changes", queryToGetKeysChanges(from, to)) , d(new Private) @@ -199,8 +207,8 @@ const QStringList& GetKeysChangesJob::left() const BaseJob::Status GetKeysChangesJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->changed = fromJson<QStringList>(json.value("changed")); - d->left = fromJson<QStringList>(json.value("left")); + d->changed = fromJson<QStringList>(json.value("changed"_ls)); + d->left = fromJson<QStringList>(json.value("left"_ls)); return Success; } diff --git a/lib/csapi/kicking.cpp b/lib/csapi/kicking.cpp index 73ef70ae..1d6d5543 100644 --- a/lib/csapi/kicking.cpp +++ b/lib/csapi/kicking.cpp @@ -12,13 +12,15 @@ using namespace QMatrixClient; static const auto basePath = QStringLiteral("/_matrix/client/r0"); +static const auto KickJobName = QStringLiteral("KickJob"); + KickJob::KickJob(const QString& roomId, const QString& userId, const QString& reason) - : BaseJob(HttpVerb::Post, "KickJob", + : BaseJob(HttpVerb::Post, KickJobName, basePath % "/rooms/" % roomId % "/kick") { QJsonObject _data; - addParam<>(_data, "user_id", userId); - addParam<IfNotEmpty>(_data, "reason", reason); + addParam<>(_data, QStringLiteral("user_id"), userId); + addParam<IfNotEmpty>(_data, QStringLiteral("reason"), reason); setRequestData(_data); } diff --git a/lib/csapi/leaving.cpp b/lib/csapi/leaving.cpp index afc4adbd..09e5f83b 100644 --- a/lib/csapi/leaving.cpp +++ b/lib/csapi/leaving.cpp @@ -18,8 +18,10 @@ QUrl LeaveRoomJob::makeRequestUrl(QUrl baseUrl, const QString& roomId) basePath % "/rooms/" % roomId % "/leave"); } +static const auto LeaveRoomJobName = QStringLiteral("LeaveRoomJob"); + LeaveRoomJob::LeaveRoomJob(const QString& roomId) - : BaseJob(HttpVerb::Post, "LeaveRoomJob", + : BaseJob(HttpVerb::Post, LeaveRoomJobName, basePath % "/rooms/" % roomId % "/leave") { } @@ -30,8 +32,10 @@ QUrl ForgetRoomJob::makeRequestUrl(QUrl baseUrl, const QString& roomId) basePath % "/rooms/" % roomId % "/forget"); } +static const auto ForgetRoomJobName = QStringLiteral("ForgetRoomJob"); + ForgetRoomJob::ForgetRoomJob(const QString& roomId) - : BaseJob(HttpVerb::Post, "ForgetRoomJob", + : BaseJob(HttpVerb::Post, ForgetRoomJobName, basePath % "/rooms/" % roomId % "/forget") { } diff --git a/lib/csapi/list_joined_rooms.cpp b/lib/csapi/list_joined_rooms.cpp index 82ec8849..a745dba1 100644 --- a/lib/csapi/list_joined_rooms.cpp +++ b/lib/csapi/list_joined_rooms.cpp @@ -24,8 +24,10 @@ QUrl GetJoinedRoomsJob::makeRequestUrl(QUrl baseUrl) basePath % "/joined_rooms"); } +static const auto GetJoinedRoomsJobName = QStringLiteral("GetJoinedRoomsJob"); + GetJoinedRoomsJob::GetJoinedRoomsJob() - : BaseJob(HttpVerb::Get, "GetJoinedRoomsJob", + : BaseJob(HttpVerb::Get, GetJoinedRoomsJobName, basePath % "/joined_rooms") , d(new Private) { @@ -41,10 +43,10 @@ const QStringList& GetJoinedRoomsJob::joinedRooms() const BaseJob::Status GetJoinedRoomsJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("joined_rooms")) + if (!json.contains("joined_rooms"_ls)) return { JsonParseError, "The key 'joined_rooms' not found in the response" }; - d->joinedRooms = fromJson<QStringList>(json.value("joined_rooms")); + d->joinedRooms = fromJson<QStringList>(json.value("joined_rooms"_ls)); return Success; } diff --git a/lib/csapi/list_public_rooms.cpp b/lib/csapi/list_public_rooms.cpp index 5d605bbb..c34af34c 100644 --- a/lib/csapi/list_public_rooms.cpp +++ b/lib/csapi/list_public_rooms.cpp @@ -24,8 +24,10 @@ QUrl GetRoomVisibilityOnDirectoryJob::makeRequestUrl(QUrl baseUrl, const QString basePath % "/directory/list/room/" % roomId); } +static const auto GetRoomVisibilityOnDirectoryJobName = QStringLiteral("GetRoomVisibilityOnDirectoryJob"); + GetRoomVisibilityOnDirectoryJob::GetRoomVisibilityOnDirectoryJob(const QString& roomId) - : BaseJob(HttpVerb::Get, "GetRoomVisibilityOnDirectoryJob", + : BaseJob(HttpVerb::Get, GetRoomVisibilityOnDirectoryJobName, basePath % "/directory/list/room/" % roomId, false) , d(new Private) { @@ -41,16 +43,18 @@ const QString& GetRoomVisibilityOnDirectoryJob::visibility() const BaseJob::Status GetRoomVisibilityOnDirectoryJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->visibility = fromJson<QString>(json.value("visibility")); + d->visibility = fromJson<QString>(json.value("visibility"_ls)); return Success; } +static const auto SetRoomVisibilityOnDirectoryJobName = QStringLiteral("SetRoomVisibilityOnDirectoryJob"); + SetRoomVisibilityOnDirectoryJob::SetRoomVisibilityOnDirectoryJob(const QString& roomId, const QString& visibility) - : BaseJob(HttpVerb::Put, "SetRoomVisibilityOnDirectoryJob", + : BaseJob(HttpVerb::Put, SetRoomVisibilityOnDirectoryJobName, basePath % "/directory/list/room/" % roomId) { QJsonObject _data; - addParam<IfNotEmpty>(_data, "visibility", visibility); + addParam<IfNotEmpty>(_data, QStringLiteral("visibility"), visibility); setRequestData(_data); } @@ -65,23 +69,23 @@ namespace QMatrixClient const auto& _json = jv.toObject(); GetPublicRoomsJob::PublicRoomsChunk result; result.aliases = - fromJson<QStringList>(_json.value("aliases")); + fromJson<QStringList>(_json.value("aliases"_ls)); result.canonicalAlias = - fromJson<QString>(_json.value("canonical_alias")); + fromJson<QString>(_json.value("canonical_alias"_ls)); result.name = - fromJson<QString>(_json.value("name")); + fromJson<QString>(_json.value("name"_ls)); result.numJoinedMembers = - fromJson<qint64>(_json.value("num_joined_members")); + fromJson<qint64>(_json.value("num_joined_members"_ls)); result.roomId = - fromJson<QString>(_json.value("room_id")); + fromJson<QString>(_json.value("room_id"_ls)); result.topic = - fromJson<QString>(_json.value("topic")); + fromJson<QString>(_json.value("topic"_ls)); result.worldReadable = - fromJson<bool>(_json.value("world_readable")); + fromJson<bool>(_json.value("world_readable"_ls)); result.guestCanJoin = - fromJson<bool>(_json.value("guest_can_join")); + fromJson<bool>(_json.value("guest_can_join"_ls)); result.avatarUrl = - fromJson<QString>(_json.value("avatar_url")); + fromJson<QString>(_json.value("avatar_url"_ls)); return result; } @@ -100,9 +104,9 @@ class GetPublicRoomsJob::Private BaseJob::Query queryToGetPublicRooms(Omittable<int> limit, const QString& since, const QString& server) { BaseJob::Query _q; - addParam<IfNotEmpty>(_q, "limit", limit); - addParam<IfNotEmpty>(_q, "since", since); - addParam<IfNotEmpty>(_q, "server", server); + addParam<IfNotEmpty>(_q, QStringLiteral("limit"), limit); + addParam<IfNotEmpty>(_q, QStringLiteral("since"), since); + addParam<IfNotEmpty>(_q, QStringLiteral("server"), server); return _q; } @@ -113,8 +117,10 @@ QUrl GetPublicRoomsJob::makeRequestUrl(QUrl baseUrl, Omittable<int> limit, const queryToGetPublicRooms(limit, since, server)); } +static const auto GetPublicRoomsJobName = QStringLiteral("GetPublicRoomsJob"); + GetPublicRoomsJob::GetPublicRoomsJob(Omittable<int> limit, const QString& since, const QString& server) - : BaseJob(HttpVerb::Get, "GetPublicRoomsJob", + : BaseJob(HttpVerb::Get, GetPublicRoomsJobName, basePath % "/publicRooms", queryToGetPublicRooms(limit, since, server), {}, false) @@ -147,13 +153,13 @@ Omittable<qint64> GetPublicRoomsJob::totalRoomCountEstimate() const BaseJob::Status GetPublicRoomsJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("chunk")) + if (!json.contains("chunk"_ls)) return { JsonParseError, "The key 'chunk' not found in the response" }; - d->chunk = fromJson<QVector<PublicRoomsChunk>>(json.value("chunk")); - d->nextBatch = fromJson<QString>(json.value("next_batch")); - d->prevBatch = fromJson<QString>(json.value("prev_batch")); - d->totalRoomCountEstimate = fromJson<qint64>(json.value("total_room_count_estimate")); + d->chunk = fromJson<QVector<PublicRoomsChunk>>(json.value("chunk"_ls)); + d->nextBatch = fromJson<QString>(json.value("next_batch"_ls)); + d->prevBatch = fromJson<QString>(json.value("prev_batch"_ls)); + d->totalRoomCountEstimate = fromJson<qint64>(json.value("total_room_count_estimate"_ls)); return Success; } @@ -164,7 +170,7 @@ namespace QMatrixClient QJsonObject toJson(const QueryPublicRoomsJob::Filter& pod) { QJsonObject _json; - addParam<IfNotEmpty>(_json, "generic_search_term", pod.genericSearchTerm); + addParam<IfNotEmpty>(_json, QStringLiteral("generic_search_term"), pod.genericSearchTerm); return _json; } @@ -175,23 +181,23 @@ namespace QMatrixClient const auto& _json = jv.toObject(); QueryPublicRoomsJob::PublicRoomsChunk result; result.aliases = - fromJson<QStringList>(_json.value("aliases")); + fromJson<QStringList>(_json.value("aliases"_ls)); result.canonicalAlias = - fromJson<QString>(_json.value("canonical_alias")); + fromJson<QString>(_json.value("canonical_alias"_ls)); result.name = - fromJson<QString>(_json.value("name")); + fromJson<QString>(_json.value("name"_ls)); result.numJoinedMembers = - fromJson<qint64>(_json.value("num_joined_members")); + fromJson<qint64>(_json.value("num_joined_members"_ls)); result.roomId = - fromJson<QString>(_json.value("room_id")); + fromJson<QString>(_json.value("room_id"_ls)); result.topic = - fromJson<QString>(_json.value("topic")); + fromJson<QString>(_json.value("topic"_ls)); result.worldReadable = - fromJson<bool>(_json.value("world_readable")); + fromJson<bool>(_json.value("world_readable"_ls)); result.guestCanJoin = - fromJson<bool>(_json.value("guest_can_join")); + fromJson<bool>(_json.value("guest_can_join"_ls)); result.avatarUrl = - fromJson<QString>(_json.value("avatar_url")); + fromJson<QString>(_json.value("avatar_url"_ls)); return result; } @@ -210,20 +216,22 @@ class QueryPublicRoomsJob::Private BaseJob::Query queryToQueryPublicRooms(const QString& server) { BaseJob::Query _q; - addParam<IfNotEmpty>(_q, "server", server); + addParam<IfNotEmpty>(_q, QStringLiteral("server"), server); return _q; } +static const auto QueryPublicRoomsJobName = QStringLiteral("QueryPublicRoomsJob"); + QueryPublicRoomsJob::QueryPublicRoomsJob(const QString& server, Omittable<int> limit, const QString& since, const Omittable<Filter>& filter) - : BaseJob(HttpVerb::Post, "QueryPublicRoomsJob", + : BaseJob(HttpVerb::Post, QueryPublicRoomsJobName, basePath % "/publicRooms", queryToQueryPublicRooms(server)) , d(new Private) { QJsonObject _data; - addParam<IfNotEmpty>(_data, "limit", limit); - addParam<IfNotEmpty>(_data, "since", since); - addParam<IfNotEmpty>(_data, "filter", filter); + addParam<IfNotEmpty>(_data, QStringLiteral("limit"), limit); + addParam<IfNotEmpty>(_data, QStringLiteral("since"), since); + addParam<IfNotEmpty>(_data, QStringLiteral("filter"), filter); setRequestData(_data); } @@ -252,13 +260,13 @@ Omittable<qint64> QueryPublicRoomsJob::totalRoomCountEstimate() const BaseJob::Status QueryPublicRoomsJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("chunk")) + if (!json.contains("chunk"_ls)) return { JsonParseError, "The key 'chunk' not found in the response" }; - d->chunk = fromJson<QVector<PublicRoomsChunk>>(json.value("chunk")); - d->nextBatch = fromJson<QString>(json.value("next_batch")); - d->prevBatch = fromJson<QString>(json.value("prev_batch")); - d->totalRoomCountEstimate = fromJson<qint64>(json.value("total_room_count_estimate")); + d->chunk = fromJson<QVector<PublicRoomsChunk>>(json.value("chunk"_ls)); + d->nextBatch = fromJson<QString>(json.value("next_batch"_ls)); + d->prevBatch = fromJson<QString>(json.value("prev_batch"_ls)); + d->totalRoomCountEstimate = fromJson<qint64>(json.value("total_room_count_estimate"_ls)); return Success; } diff --git a/lib/csapi/login.cpp b/lib/csapi/login.cpp index e0795f8a..b8734d05 100644 --- a/lib/csapi/login.cpp +++ b/lib/csapi/login.cpp @@ -21,20 +21,22 @@ class LoginJob::Private QString deviceId; }; +static const auto LoginJobName = QStringLiteral("LoginJob"); + LoginJob::LoginJob(const QString& type, const QString& user, const QString& medium, const QString& address, const QString& password, const QString& token, const QString& deviceId, const QString& initialDeviceDisplayName) - : BaseJob(HttpVerb::Post, "LoginJob", + : BaseJob(HttpVerb::Post, LoginJobName, basePath % "/login", false) , d(new Private) { QJsonObject _data; - addParam<>(_data, "type", type); - addParam<IfNotEmpty>(_data, "user", user); - addParam<IfNotEmpty>(_data, "medium", medium); - addParam<IfNotEmpty>(_data, "address", address); - addParam<IfNotEmpty>(_data, "password", password); - addParam<IfNotEmpty>(_data, "token", token); - addParam<IfNotEmpty>(_data, "device_id", deviceId); - addParam<IfNotEmpty>(_data, "initial_device_display_name", initialDeviceDisplayName); + addParam<>(_data, QStringLiteral("type"), type); + addParam<IfNotEmpty>(_data, QStringLiteral("user"), user); + addParam<IfNotEmpty>(_data, QStringLiteral("medium"), medium); + addParam<IfNotEmpty>(_data, QStringLiteral("address"), address); + addParam<IfNotEmpty>(_data, QStringLiteral("password"), password); + addParam<IfNotEmpty>(_data, QStringLiteral("token"), token); + addParam<IfNotEmpty>(_data, QStringLiteral("device_id"), deviceId); + addParam<IfNotEmpty>(_data, QStringLiteral("initial_device_display_name"), initialDeviceDisplayName); setRequestData(_data); } @@ -63,10 +65,10 @@ const QString& LoginJob::deviceId() const BaseJob::Status LoginJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->userId = fromJson<QString>(json.value("user_id")); - d->accessToken = fromJson<QString>(json.value("access_token")); - d->homeServer = fromJson<QString>(json.value("home_server")); - d->deviceId = fromJson<QString>(json.value("device_id")); + d->userId = fromJson<QString>(json.value("user_id"_ls)); + d->accessToken = fromJson<QString>(json.value("access_token"_ls)); + d->homeServer = fromJson<QString>(json.value("home_server"_ls)); + d->deviceId = fromJson<QString>(json.value("device_id"_ls)); return Success; } diff --git a/lib/csapi/logout.cpp b/lib/csapi/logout.cpp index 42f99bbc..6e209e07 100644 --- a/lib/csapi/logout.cpp +++ b/lib/csapi/logout.cpp @@ -18,8 +18,10 @@ QUrl LogoutJob::makeRequestUrl(QUrl baseUrl) basePath % "/logout"); } +static const auto LogoutJobName = QStringLiteral("LogoutJob"); + LogoutJob::LogoutJob() - : BaseJob(HttpVerb::Post, "LogoutJob", + : BaseJob(HttpVerb::Post, LogoutJobName, basePath % "/logout") { } @@ -30,8 +32,10 @@ QUrl LogoutAllJob::makeRequestUrl(QUrl baseUrl) basePath % "/logout/all"); } +static const auto LogoutAllJobName = QStringLiteral("LogoutAllJob"); + LogoutAllJob::LogoutAllJob() - : BaseJob(HttpVerb::Post, "LogoutAllJob", + : BaseJob(HttpVerb::Post, LogoutAllJobName, basePath % "/logout/all") { } diff --git a/lib/csapi/message_pagination.cpp b/lib/csapi/message_pagination.cpp index 1eb2aa07..c59a51ab 100644 --- a/lib/csapi/message_pagination.cpp +++ b/lib/csapi/message_pagination.cpp @@ -23,11 +23,11 @@ class GetRoomEventsJob::Private BaseJob::Query queryToGetRoomEvents(const QString& from, const QString& to, const QString& dir, Omittable<int> limit, const QString& filter) { BaseJob::Query _q; - addParam<>(_q, "from", from); - addParam<IfNotEmpty>(_q, "to", to); - addParam<>(_q, "dir", dir); - addParam<IfNotEmpty>(_q, "limit", limit); - addParam<IfNotEmpty>(_q, "filter", filter); + addParam<>(_q, QStringLiteral("from"), from); + addParam<IfNotEmpty>(_q, QStringLiteral("to"), to); + addParam<>(_q, QStringLiteral("dir"), dir); + addParam<IfNotEmpty>(_q, QStringLiteral("limit"), limit); + addParam<IfNotEmpty>(_q, QStringLiteral("filter"), filter); return _q; } @@ -38,8 +38,10 @@ QUrl GetRoomEventsJob::makeRequestUrl(QUrl baseUrl, const QString& roomId, const queryToGetRoomEvents(from, to, dir, limit, filter)); } +static const auto GetRoomEventsJobName = QStringLiteral("GetRoomEventsJob"); + GetRoomEventsJob::GetRoomEventsJob(const QString& roomId, const QString& from, const QString& dir, const QString& to, Omittable<int> limit, const QString& filter) - : BaseJob(HttpVerb::Get, "GetRoomEventsJob", + : BaseJob(HttpVerb::Get, GetRoomEventsJobName, basePath % "/rooms/" % roomId % "/messages", queryToGetRoomEvents(from, to, dir, limit, filter)) , d(new Private) @@ -66,9 +68,9 @@ RoomEvents&& GetRoomEventsJob::chunk() BaseJob::Status GetRoomEventsJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->begin = fromJson<QString>(json.value("start")); - d->end = fromJson<QString>(json.value("end")); - d->chunk = fromJson<RoomEvents>(json.value("chunk")); + d->begin = fromJson<QString>(json.value("start"_ls)); + d->end = fromJson<QString>(json.value("end"_ls)); + d->chunk = fromJson<RoomEvents>(json.value("chunk"_ls)); return Success; } diff --git a/lib/csapi/message_pagination.h b/lib/csapi/message_pagination.h index 92b258ea..58900940 100644 --- a/lib/csapi/message_pagination.h +++ b/lib/csapi/message_pagination.h @@ -6,7 +6,7 @@ #include "jobs/basejob.h" -#include "events/event.h" +#include "events/eventloader.h" #include "converters.h" namespace QMatrixClient diff --git a/lib/csapi/notifications.cpp b/lib/csapi/notifications.cpp index 39570991..f98cddd2 100644 --- a/lib/csapi/notifications.cpp +++ b/lib/csapi/notifications.cpp @@ -23,17 +23,17 @@ namespace QMatrixClient const auto& _json = jv.toObject(); GetNotificationsJob::Notification result; result.actions = - fromJson<QVector<QVariant>>(_json.value("actions")); + fromJson<QVector<QVariant>>(_json.value("actions"_ls)); result.event = - fromJson<EventPtr>(_json.value("event")); + fromJson<EventPtr>(_json.value("event"_ls)); result.profileTag = - fromJson<QString>(_json.value("profile_tag")); + fromJson<QString>(_json.value("profile_tag"_ls)); result.read = - fromJson<bool>(_json.value("read")); + fromJson<bool>(_json.value("read"_ls)); result.roomId = - fromJson<QString>(_json.value("room_id")); + fromJson<QString>(_json.value("room_id"_ls)); result.ts = - fromJson<qint64>(_json.value("ts")); + fromJson<qint64>(_json.value("ts"_ls)); return result; } @@ -50,9 +50,9 @@ class GetNotificationsJob::Private BaseJob::Query queryToGetNotifications(const QString& from, Omittable<int> limit, const QString& only) { BaseJob::Query _q; - addParam<IfNotEmpty>(_q, "from", from); - addParam<IfNotEmpty>(_q, "limit", limit); - addParam<IfNotEmpty>(_q, "only", only); + addParam<IfNotEmpty>(_q, QStringLiteral("from"), from); + addParam<IfNotEmpty>(_q, QStringLiteral("limit"), limit); + addParam<IfNotEmpty>(_q, QStringLiteral("only"), only); return _q; } @@ -63,8 +63,10 @@ QUrl GetNotificationsJob::makeRequestUrl(QUrl baseUrl, const QString& from, Omit queryToGetNotifications(from, limit, only)); } +static const auto GetNotificationsJobName = QStringLiteral("GetNotificationsJob"); + GetNotificationsJob::GetNotificationsJob(const QString& from, Omittable<int> limit, const QString& only) - : BaseJob(HttpVerb::Get, "GetNotificationsJob", + : BaseJob(HttpVerb::Get, GetNotificationsJobName, basePath % "/notifications", queryToGetNotifications(from, limit, only)) , d(new Private) @@ -86,11 +88,11 @@ std::vector<GetNotificationsJob::Notification>&& GetNotificationsJob::notificati BaseJob::Status GetNotificationsJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->nextToken = fromJson<QString>(json.value("next_token")); - if (!json.contains("notifications")) + d->nextToken = fromJson<QString>(json.value("next_token"_ls)); + if (!json.contains("notifications"_ls)) return { JsonParseError, "The key 'notifications' not found in the response" }; - d->notifications = fromJson<std::vector<Notification>>(json.value("notifications")); + d->notifications = fromJson<std::vector<Notification>>(json.value("notifications"_ls)); return Success; } diff --git a/lib/csapi/notifications.h b/lib/csapi/notifications.h index 094fa3af..3698431d 100644 --- a/lib/csapi/notifications.h +++ b/lib/csapi/notifications.h @@ -6,7 +6,7 @@ #include "jobs/basejob.h" -#include "events/event.h" +#include "events/eventloader.h" #include "converters.h" #include <QtCore/QVector> #include <QtCore/QVariant> diff --git a/lib/csapi/peeking_events.cpp b/lib/csapi/peeking_events.cpp index b3be7631..e046a62e 100644 --- a/lib/csapi/peeking_events.cpp +++ b/lib/csapi/peeking_events.cpp @@ -23,9 +23,9 @@ class PeekEventsJob::Private BaseJob::Query queryToPeekEvents(const QString& from, Omittable<int> timeout, const QString& roomId) { BaseJob::Query _q; - addParam<IfNotEmpty>(_q, "from", from); - addParam<IfNotEmpty>(_q, "timeout", timeout); - addParam<IfNotEmpty>(_q, "room_id", roomId); + addParam<IfNotEmpty>(_q, QStringLiteral("from"), from); + addParam<IfNotEmpty>(_q, QStringLiteral("timeout"), timeout); + addParam<IfNotEmpty>(_q, QStringLiteral("room_id"), roomId); return _q; } @@ -36,8 +36,10 @@ QUrl PeekEventsJob::makeRequestUrl(QUrl baseUrl, const QString& from, Omittable< queryToPeekEvents(from, timeout, roomId)); } +static const auto PeekEventsJobName = QStringLiteral("PeekEventsJob"); + PeekEventsJob::PeekEventsJob(const QString& from, Omittable<int> timeout, const QString& roomId) - : BaseJob(HttpVerb::Get, "PeekEventsJob", + : BaseJob(HttpVerb::Get, PeekEventsJobName, basePath % "/events", queryToPeekEvents(from, timeout, roomId)) , d(new Private) @@ -64,9 +66,9 @@ RoomEvents&& PeekEventsJob::chunk() BaseJob::Status PeekEventsJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->begin = fromJson<QString>(json.value("start")); - d->end = fromJson<QString>(json.value("end")); - d->chunk = fromJson<RoomEvents>(json.value("chunk")); + d->begin = fromJson<QString>(json.value("start"_ls)); + d->end = fromJson<QString>(json.value("end"_ls)); + d->chunk = fromJson<RoomEvents>(json.value("chunk"_ls)); return Success; } diff --git a/lib/csapi/peeking_events.h b/lib/csapi/peeking_events.h index f8876bf1..5f2c4233 100644 --- a/lib/csapi/peeking_events.h +++ b/lib/csapi/peeking_events.h @@ -6,7 +6,7 @@ #include "jobs/basejob.h" -#include "events/event.h" +#include "events/eventloader.h" #include "converters.h" namespace QMatrixClient diff --git a/lib/csapi/presence.cpp b/lib/csapi/presence.cpp index 35b2c960..66827163 100644 --- a/lib/csapi/presence.cpp +++ b/lib/csapi/presence.cpp @@ -12,13 +12,15 @@ using namespace QMatrixClient; static const auto basePath = QStringLiteral("/_matrix/client/r0"); +static const auto SetPresenceJobName = QStringLiteral("SetPresenceJob"); + SetPresenceJob::SetPresenceJob(const QString& userId, const QString& presence, const QString& statusMsg) - : BaseJob(HttpVerb::Put, "SetPresenceJob", + : BaseJob(HttpVerb::Put, SetPresenceJobName, basePath % "/presence/" % userId % "/status") { QJsonObject _data; - addParam<>(_data, "presence", presence); - addParam<IfNotEmpty>(_data, "status_msg", statusMsg); + addParam<>(_data, QStringLiteral("presence"), presence); + addParam<IfNotEmpty>(_data, QStringLiteral("status_msg"), statusMsg); setRequestData(_data); } @@ -37,8 +39,10 @@ QUrl GetPresenceJob::makeRequestUrl(QUrl baseUrl, const QString& userId) basePath % "/presence/" % userId % "/status"); } +static const auto GetPresenceJobName = QStringLiteral("GetPresenceJob"); + GetPresenceJob::GetPresenceJob(const QString& userId) - : BaseJob(HttpVerb::Get, "GetPresenceJob", + : BaseJob(HttpVerb::Get, GetPresenceJobName, basePath % "/presence/" % userId % "/status", false) , d(new Private) { @@ -69,23 +73,25 @@ bool GetPresenceJob::currentlyActive() const BaseJob::Status GetPresenceJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("presence")) + if (!json.contains("presence"_ls)) return { JsonParseError, "The key 'presence' not found in the response" }; - d->presence = fromJson<QString>(json.value("presence")); - d->lastActiveAgo = fromJson<int>(json.value("last_active_ago")); - d->statusMsg = fromJson<QString>(json.value("status_msg")); - d->currentlyActive = fromJson<bool>(json.value("currently_active")); + d->presence = fromJson<QString>(json.value("presence"_ls)); + d->lastActiveAgo = fromJson<int>(json.value("last_active_ago"_ls)); + d->statusMsg = fromJson<QString>(json.value("status_msg"_ls)); + d->currentlyActive = fromJson<bool>(json.value("currently_active"_ls)); return Success; } +static const auto ModifyPresenceListJobName = QStringLiteral("ModifyPresenceListJob"); + ModifyPresenceListJob::ModifyPresenceListJob(const QString& userId, const QStringList& invite, const QStringList& drop) - : BaseJob(HttpVerb::Post, "ModifyPresenceListJob", + : BaseJob(HttpVerb::Post, ModifyPresenceListJobName, basePath % "/presence/list/" % userId) { QJsonObject _data; - addParam<IfNotEmpty>(_data, "invite", invite); - addParam<IfNotEmpty>(_data, "drop", drop); + addParam<IfNotEmpty>(_data, QStringLiteral("invite"), invite); + addParam<IfNotEmpty>(_data, QStringLiteral("drop"), drop); setRequestData(_data); } @@ -101,8 +107,10 @@ QUrl GetPresenceForListJob::makeRequestUrl(QUrl baseUrl, const QString& userId) basePath % "/presence/list/" % userId); } +static const auto GetPresenceForListJobName = QStringLiteral("GetPresenceForListJob"); + GetPresenceForListJob::GetPresenceForListJob(const QString& userId) - : BaseJob(HttpVerb::Get, "GetPresenceForListJob", + : BaseJob(HttpVerb::Get, GetPresenceForListJobName, basePath % "/presence/list/" % userId, false) , d(new Private) { @@ -118,10 +126,10 @@ Events&& GetPresenceForListJob::data() BaseJob::Status GetPresenceForListJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("data")) + if (!json.contains("data"_ls)) return { JsonParseError, "The key 'data' not found in the response" }; - d->data = fromJson<Events>(json.value("data")); + d->data = fromJson<Events>(json.value("data"_ls)); return Success; } diff --git a/lib/csapi/presence.h b/lib/csapi/presence.h index 2def94ba..7d6665f3 100644 --- a/lib/csapi/presence.h +++ b/lib/csapi/presence.h @@ -6,7 +6,7 @@ #include "jobs/basejob.h" -#include "events/event.h" +#include "events/eventloader.h" #include "converters.h" namespace QMatrixClient diff --git a/lib/csapi/profile.cpp b/lib/csapi/profile.cpp index b08eb970..bb053062 100644 --- a/lib/csapi/profile.cpp +++ b/lib/csapi/profile.cpp @@ -12,12 +12,14 @@ using namespace QMatrixClient; static const auto basePath = QStringLiteral("/_matrix/client/r0"); +static const auto SetDisplayNameJobName = QStringLiteral("SetDisplayNameJob"); + SetDisplayNameJob::SetDisplayNameJob(const QString& userId, const QString& displayname) - : BaseJob(HttpVerb::Put, "SetDisplayNameJob", + : BaseJob(HttpVerb::Put, SetDisplayNameJobName, basePath % "/profile/" % userId % "/displayname") { QJsonObject _data; - addParam<IfNotEmpty>(_data, "displayname", displayname); + addParam<IfNotEmpty>(_data, QStringLiteral("displayname"), displayname); setRequestData(_data); } @@ -33,8 +35,10 @@ QUrl GetDisplayNameJob::makeRequestUrl(QUrl baseUrl, const QString& userId) basePath % "/profile/" % userId % "/displayname"); } +static const auto GetDisplayNameJobName = QStringLiteral("GetDisplayNameJob"); + GetDisplayNameJob::GetDisplayNameJob(const QString& userId) - : BaseJob(HttpVerb::Get, "GetDisplayNameJob", + : BaseJob(HttpVerb::Get, GetDisplayNameJobName, basePath % "/profile/" % userId % "/displayname", false) , d(new Private) { @@ -50,16 +54,18 @@ const QString& GetDisplayNameJob::displayname() const BaseJob::Status GetDisplayNameJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->displayname = fromJson<QString>(json.value("displayname")); + d->displayname = fromJson<QString>(json.value("displayname"_ls)); return Success; } +static const auto SetAvatarUrlJobName = QStringLiteral("SetAvatarUrlJob"); + SetAvatarUrlJob::SetAvatarUrlJob(const QString& userId, const QString& avatarUrl) - : BaseJob(HttpVerb::Put, "SetAvatarUrlJob", + : BaseJob(HttpVerb::Put, SetAvatarUrlJobName, basePath % "/profile/" % userId % "/avatar_url") { QJsonObject _data; - addParam<IfNotEmpty>(_data, "avatar_url", avatarUrl); + addParam<IfNotEmpty>(_data, QStringLiteral("avatar_url"), avatarUrl); setRequestData(_data); } @@ -75,8 +81,10 @@ QUrl GetAvatarUrlJob::makeRequestUrl(QUrl baseUrl, const QString& userId) basePath % "/profile/" % userId % "/avatar_url"); } +static const auto GetAvatarUrlJobName = QStringLiteral("GetAvatarUrlJob"); + GetAvatarUrlJob::GetAvatarUrlJob(const QString& userId) - : BaseJob(HttpVerb::Get, "GetAvatarUrlJob", + : BaseJob(HttpVerb::Get, GetAvatarUrlJobName, basePath % "/profile/" % userId % "/avatar_url", false) , d(new Private) { @@ -92,7 +100,7 @@ const QString& GetAvatarUrlJob::avatarUrl() const BaseJob::Status GetAvatarUrlJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->avatarUrl = fromJson<QString>(json.value("avatar_url")); + d->avatarUrl = fromJson<QString>(json.value("avatar_url"_ls)); return Success; } @@ -109,8 +117,10 @@ QUrl GetUserProfileJob::makeRequestUrl(QUrl baseUrl, const QString& userId) basePath % "/profile/" % userId); } +static const auto GetUserProfileJobName = QStringLiteral("GetUserProfileJob"); + GetUserProfileJob::GetUserProfileJob(const QString& userId) - : BaseJob(HttpVerb::Get, "GetUserProfileJob", + : BaseJob(HttpVerb::Get, GetUserProfileJobName, basePath % "/profile/" % userId, false) , d(new Private) { @@ -131,8 +141,8 @@ const QString& GetUserProfileJob::displayname() const BaseJob::Status GetUserProfileJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->avatarUrl = fromJson<QString>(json.value("avatar_url")); - d->displayname = fromJson<QString>(json.value("displayname")); + d->avatarUrl = fromJson<QString>(json.value("avatar_url"_ls)); + d->displayname = fromJson<QString>(json.value("displayname"_ls)); return Success; } diff --git a/lib/csapi/pusher.cpp b/lib/csapi/pusher.cpp index 1a43900b..feecdbc7 100644 --- a/lib/csapi/pusher.cpp +++ b/lib/csapi/pusher.cpp @@ -23,7 +23,7 @@ namespace QMatrixClient const auto& _json = jv.toObject(); GetPushersJob::PusherData result; result.url = - fromJson<QString>(_json.value("url")); + fromJson<QString>(_json.value("url"_ls)); return result; } @@ -36,21 +36,21 @@ namespace QMatrixClient const auto& _json = jv.toObject(); GetPushersJob::Pusher result; result.pushkey = - fromJson<QString>(_json.value("pushkey")); + fromJson<QString>(_json.value("pushkey"_ls)); result.kind = - fromJson<QString>(_json.value("kind")); + fromJson<QString>(_json.value("kind"_ls)); result.appId = - fromJson<QString>(_json.value("app_id")); + fromJson<QString>(_json.value("app_id"_ls)); result.appDisplayName = - fromJson<QString>(_json.value("app_display_name")); + fromJson<QString>(_json.value("app_display_name"_ls)); result.deviceDisplayName = - fromJson<QString>(_json.value("device_display_name")); + fromJson<QString>(_json.value("device_display_name"_ls)); result.profileTag = - fromJson<QString>(_json.value("profile_tag")); + fromJson<QString>(_json.value("profile_tag"_ls)); result.lang = - fromJson<QString>(_json.value("lang")); + fromJson<QString>(_json.value("lang"_ls)); result.data = - fromJson<GetPushersJob::PusherData>(_json.value("data")); + fromJson<GetPushersJob::PusherData>(_json.value("data"_ls)); return result; } @@ -69,8 +69,10 @@ QUrl GetPushersJob::makeRequestUrl(QUrl baseUrl) basePath % "/pushers"); } +static const auto GetPushersJobName = QStringLiteral("GetPushersJob"); + GetPushersJob::GetPushersJob() - : BaseJob(HttpVerb::Get, "GetPushersJob", + : BaseJob(HttpVerb::Get, GetPushersJobName, basePath % "/pushers") , d(new Private) { @@ -86,7 +88,7 @@ const QVector<GetPushersJob::Pusher>& GetPushersJob::pushers() const BaseJob::Status GetPushersJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->pushers = fromJson<QVector<Pusher>>(json.value("pushers")); + d->pushers = fromJson<QVector<Pusher>>(json.value("pushers"_ls)); return Success; } @@ -97,25 +99,27 @@ namespace QMatrixClient QJsonObject toJson(const PostPusherJob::PusherData& pod) { QJsonObject _json; - addParam<IfNotEmpty>(_json, "url", pod.url); + addParam<IfNotEmpty>(_json, QStringLiteral("url"), pod.url); return _json; } } // namespace QMatrixClient +static const auto PostPusherJobName = QStringLiteral("PostPusherJob"); + PostPusherJob::PostPusherJob(const QString& pushkey, const QString& kind, const QString& appId, const QString& appDisplayName, const QString& deviceDisplayName, const QString& lang, const PusherData& data, const QString& profileTag, bool append) - : BaseJob(HttpVerb::Post, "PostPusherJob", + : BaseJob(HttpVerb::Post, PostPusherJobName, basePath % "/pushers/set") { QJsonObject _data; - addParam<>(_data, "pushkey", pushkey); - addParam<>(_data, "kind", kind); - addParam<>(_data, "app_id", appId); - addParam<>(_data, "app_display_name", appDisplayName); - addParam<>(_data, "device_display_name", deviceDisplayName); - addParam<IfNotEmpty>(_data, "profile_tag", profileTag); - addParam<>(_data, "lang", lang); - addParam<>(_data, "data", data); - addParam<IfNotEmpty>(_data, "append", append); + addParam<>(_data, QStringLiteral("pushkey"), pushkey); + addParam<>(_data, QStringLiteral("kind"), kind); + addParam<>(_data, QStringLiteral("app_id"), appId); + addParam<>(_data, QStringLiteral("app_display_name"), appDisplayName); + addParam<>(_data, QStringLiteral("device_display_name"), deviceDisplayName); + addParam<IfNotEmpty>(_data, QStringLiteral("profile_tag"), profileTag); + addParam<>(_data, QStringLiteral("lang"), lang); + addParam<>(_data, QStringLiteral("data"), data); + addParam<IfNotEmpty>(_data, QStringLiteral("append"), append); setRequestData(_data); } diff --git a/lib/csapi/pushrules.cpp b/lib/csapi/pushrules.cpp index d7e416dc..22976641 100644 --- a/lib/csapi/pushrules.cpp +++ b/lib/csapi/pushrules.cpp @@ -24,8 +24,10 @@ QUrl GetPushRulesJob::makeRequestUrl(QUrl baseUrl) basePath % "/pushrules"); } +static const auto GetPushRulesJobName = QStringLiteral("GetPushRulesJob"); + GetPushRulesJob::GetPushRulesJob() - : BaseJob(HttpVerb::Get, "GetPushRulesJob", + : BaseJob(HttpVerb::Get, GetPushRulesJobName, basePath % "/pushrules") , d(new Private) { @@ -41,10 +43,10 @@ const PushRuleset& GetPushRulesJob::global() const BaseJob::Status GetPushRulesJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("global")) + if (!json.contains("global"_ls)) return { JsonParseError, "The key 'global' not found in the response" }; - d->global = fromJson<PushRuleset>(json.value("global")); + d->global = fromJson<PushRuleset>(json.value("global"_ls)); return Success; } @@ -60,8 +62,10 @@ QUrl GetPushRuleJob::makeRequestUrl(QUrl baseUrl, const QString& scope, const QS basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId); } +static const auto GetPushRuleJobName = QStringLiteral("GetPushRuleJob"); + GetPushRuleJob::GetPushRuleJob(const QString& scope, const QString& kind, const QString& ruleId) - : BaseJob(HttpVerb::Get, "GetPushRuleJob", + : BaseJob(HttpVerb::Get, GetPushRuleJobName, basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId) , d(new Private) { @@ -77,10 +81,10 @@ const PushRule& GetPushRuleJob::data() const BaseJob::Status GetPushRuleJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("data")) + if (!json.contains("data"_ls)) return { JsonParseError, "The key 'data' not found in the response" }; - d->data = fromJson<PushRule>(json.value("data")); + d->data = fromJson<PushRule>(json.value("data"_ls)); return Success; } @@ -90,8 +94,10 @@ QUrl DeletePushRuleJob::makeRequestUrl(QUrl baseUrl, const QString& scope, const basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId); } +static const auto DeletePushRuleJobName = QStringLiteral("DeletePushRuleJob"); + DeletePushRuleJob::DeletePushRuleJob(const QString& scope, const QString& kind, const QString& ruleId) - : BaseJob(HttpVerb::Delete, "DeletePushRuleJob", + : BaseJob(HttpVerb::Delete, DeletePushRuleJobName, basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId) { } @@ -99,20 +105,22 @@ DeletePushRuleJob::DeletePushRuleJob(const QString& scope, const QString& kind, BaseJob::Query queryToSetPushRule(const QString& before, const QString& after) { BaseJob::Query _q; - addParam<IfNotEmpty>(_q, "before", before); - addParam<IfNotEmpty>(_q, "after", after); + addParam<IfNotEmpty>(_q, QStringLiteral("before"), before); + addParam<IfNotEmpty>(_q, QStringLiteral("after"), after); return _q; } +static const auto SetPushRuleJobName = QStringLiteral("SetPushRuleJob"); + SetPushRuleJob::SetPushRuleJob(const QString& scope, const QString& kind, const QString& ruleId, const QStringList& actions, const QString& before, const QString& after, const QVector<PushCondition>& conditions, const QString& pattern) - : BaseJob(HttpVerb::Put, "SetPushRuleJob", + : BaseJob(HttpVerb::Put, SetPushRuleJobName, basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId, queryToSetPushRule(before, after)) { QJsonObject _data; - addParam<>(_data, "actions", actions); - addParam<IfNotEmpty>(_data, "conditions", conditions); - addParam<IfNotEmpty>(_data, "pattern", pattern); + addParam<>(_data, QStringLiteral("actions"), actions); + addParam<IfNotEmpty>(_data, QStringLiteral("conditions"), conditions); + addParam<IfNotEmpty>(_data, QStringLiteral("pattern"), pattern); setRequestData(_data); } @@ -128,8 +136,10 @@ QUrl IsPushRuleEnabledJob::makeRequestUrl(QUrl baseUrl, const QString& scope, co basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId % "/enabled"); } +static const auto IsPushRuleEnabledJobName = QStringLiteral("IsPushRuleEnabledJob"); + IsPushRuleEnabledJob::IsPushRuleEnabledJob(const QString& scope, const QString& kind, const QString& ruleId) - : BaseJob(HttpVerb::Get, "IsPushRuleEnabledJob", + : BaseJob(HttpVerb::Get, IsPushRuleEnabledJobName, basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId % "/enabled") , d(new Private) { @@ -145,19 +155,21 @@ bool IsPushRuleEnabledJob::enabled() const BaseJob::Status IsPushRuleEnabledJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("enabled")) + if (!json.contains("enabled"_ls)) return { JsonParseError, "The key 'enabled' not found in the response" }; - d->enabled = fromJson<bool>(json.value("enabled")); + d->enabled = fromJson<bool>(json.value("enabled"_ls)); return Success; } +static const auto SetPushRuleEnabledJobName = QStringLiteral("SetPushRuleEnabledJob"); + SetPushRuleEnabledJob::SetPushRuleEnabledJob(const QString& scope, const QString& kind, const QString& ruleId, bool enabled) - : BaseJob(HttpVerb::Put, "SetPushRuleEnabledJob", + : BaseJob(HttpVerb::Put, SetPushRuleEnabledJobName, basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId % "/enabled") { QJsonObject _data; - addParam<>(_data, "enabled", enabled); + addParam<>(_data, QStringLiteral("enabled"), enabled); setRequestData(_data); } @@ -173,8 +185,10 @@ QUrl GetPushRuleActionsJob::makeRequestUrl(QUrl baseUrl, const QString& scope, c basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId % "/actions"); } +static const auto GetPushRuleActionsJobName = QStringLiteral("GetPushRuleActionsJob"); + GetPushRuleActionsJob::GetPushRuleActionsJob(const QString& scope, const QString& kind, const QString& ruleId) - : BaseJob(HttpVerb::Get, "GetPushRuleActionsJob", + : BaseJob(HttpVerb::Get, GetPushRuleActionsJobName, basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId % "/actions") , d(new Private) { @@ -190,19 +204,21 @@ const QStringList& GetPushRuleActionsJob::actions() const BaseJob::Status GetPushRuleActionsJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("actions")) + if (!json.contains("actions"_ls)) return { JsonParseError, "The key 'actions' not found in the response" }; - d->actions = fromJson<QStringList>(json.value("actions")); + d->actions = fromJson<QStringList>(json.value("actions"_ls)); return Success; } +static const auto SetPushRuleActionsJobName = QStringLiteral("SetPushRuleActionsJob"); + SetPushRuleActionsJob::SetPushRuleActionsJob(const QString& scope, const QString& kind, const QString& ruleId, const QStringList& actions) - : BaseJob(HttpVerb::Put, "SetPushRuleActionsJob", + : BaseJob(HttpVerb::Put, SetPushRuleActionsJobName, basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId % "/actions") { QJsonObject _data; - addParam<>(_data, "actions", actions); + addParam<>(_data, QStringLiteral("actions"), actions); setRequestData(_data); } diff --git a/lib/csapi/receipts.cpp b/lib/csapi/receipts.cpp index 945e8673..b78ba533 100644 --- a/lib/csapi/receipts.cpp +++ b/lib/csapi/receipts.cpp @@ -12,8 +12,10 @@ using namespace QMatrixClient; static const auto basePath = QStringLiteral("/_matrix/client/r0"); +static const auto PostReceiptJobName = QStringLiteral("PostReceiptJob"); + PostReceiptJob::PostReceiptJob(const QString& roomId, const QString& receiptType, const QString& eventId, const QJsonObject& receipt) - : BaseJob(HttpVerb::Post, "PostReceiptJob", + : BaseJob(HttpVerb::Post, PostReceiptJobName, basePath % "/rooms/" % roomId % "/receipt/" % receiptType % "/" % eventId) { setRequestData(Data(toJson(receipt))); diff --git a/lib/csapi/redaction.cpp b/lib/csapi/redaction.cpp index 2c73800c..64098670 100644 --- a/lib/csapi/redaction.cpp +++ b/lib/csapi/redaction.cpp @@ -18,13 +18,15 @@ class RedactEventJob::Private QString eventId; }; +static const auto RedactEventJobName = QStringLiteral("RedactEventJob"); + RedactEventJob::RedactEventJob(const QString& roomId, const QString& eventId, const QString& txnId, const QString& reason) - : BaseJob(HttpVerb::Put, "RedactEventJob", + : BaseJob(HttpVerb::Put, RedactEventJobName, basePath % "/rooms/" % roomId % "/redact/" % eventId % "/" % txnId) , d(new Private) { QJsonObject _data; - addParam<IfNotEmpty>(_data, "reason", reason); + addParam<IfNotEmpty>(_data, QStringLiteral("reason"), reason); setRequestData(_data); } @@ -38,7 +40,7 @@ const QString& RedactEventJob::eventId() const BaseJob::Status RedactEventJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->eventId = fromJson<QString>(json.value("event_id")); + d->eventId = fromJson<QString>(json.value("event_id"_ls)); return Success; } diff --git a/lib/csapi/registration.cpp b/lib/csapi/registration.cpp index 4345635a..4991829c 100644 --- a/lib/csapi/registration.cpp +++ b/lib/csapi/registration.cpp @@ -24,24 +24,26 @@ class RegisterJob::Private BaseJob::Query queryToRegister(const QString& kind) { BaseJob::Query _q; - addParam<IfNotEmpty>(_q, "kind", kind); + addParam<IfNotEmpty>(_q, QStringLiteral("kind"), kind); return _q; } +static const auto RegisterJobName = QStringLiteral("RegisterJob"); + RegisterJob::RegisterJob(const QString& kind, const QJsonObject& auth, bool bindEmail, const QString& username, const QString& password, const QString& deviceId, const QString& initialDeviceDisplayName) - : BaseJob(HttpVerb::Post, "RegisterJob", + : BaseJob(HttpVerb::Post, RegisterJobName, basePath % "/register", queryToRegister(kind), {}, false) , d(new Private) { QJsonObject _data; - addParam<IfNotEmpty>(_data, "auth", auth); - addParam<IfNotEmpty>(_data, "bind_email", bindEmail); - addParam<IfNotEmpty>(_data, "username", username); - addParam<IfNotEmpty>(_data, "password", password); - addParam<IfNotEmpty>(_data, "device_id", deviceId); - addParam<IfNotEmpty>(_data, "initial_device_display_name", initialDeviceDisplayName); + addParam<IfNotEmpty>(_data, QStringLiteral("auth"), auth); + addParam<IfNotEmpty>(_data, QStringLiteral("bind_email"), bindEmail); + addParam<IfNotEmpty>(_data, QStringLiteral("username"), username); + addParam<IfNotEmpty>(_data, QStringLiteral("password"), password); + addParam<IfNotEmpty>(_data, QStringLiteral("device_id"), deviceId); + addParam<IfNotEmpty>(_data, QStringLiteral("initial_device_display_name"), initialDeviceDisplayName); setRequestData(_data); } @@ -70,32 +72,36 @@ const QString& RegisterJob::deviceId() const BaseJob::Status RegisterJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->userId = fromJson<QString>(json.value("user_id")); - d->accessToken = fromJson<QString>(json.value("access_token")); - d->homeServer = fromJson<QString>(json.value("home_server")); - d->deviceId = fromJson<QString>(json.value("device_id")); + d->userId = fromJson<QString>(json.value("user_id"_ls)); + d->accessToken = fromJson<QString>(json.value("access_token"_ls)); + d->homeServer = fromJson<QString>(json.value("home_server"_ls)); + d->deviceId = fromJson<QString>(json.value("device_id"_ls)); return Success; } +static const auto RequestTokenToRegisterJobName = QStringLiteral("RequestTokenToRegisterJob"); + RequestTokenToRegisterJob::RequestTokenToRegisterJob(const QString& clientSecret, const QString& email, int sendAttempt, const QString& idServer) - : BaseJob(HttpVerb::Post, "RequestTokenToRegisterJob", + : BaseJob(HttpVerb::Post, RequestTokenToRegisterJobName, basePath % "/register/email/requestToken", false) { QJsonObject _data; - addParam<IfNotEmpty>(_data, "id_server", idServer); - addParam<>(_data, "client_secret", clientSecret); - addParam<>(_data, "email", email); - addParam<>(_data, "send_attempt", sendAttempt); + addParam<IfNotEmpty>(_data, QStringLiteral("id_server"), idServer); + addParam<>(_data, QStringLiteral("client_secret"), clientSecret); + addParam<>(_data, QStringLiteral("email"), email); + addParam<>(_data, QStringLiteral("send_attempt"), sendAttempt); setRequestData(_data); } +static const auto ChangePasswordJobName = QStringLiteral("ChangePasswordJob"); + ChangePasswordJob::ChangePasswordJob(const QString& newPassword, const QJsonObject& auth) - : BaseJob(HttpVerb::Post, "ChangePasswordJob", + : BaseJob(HttpVerb::Post, ChangePasswordJobName, basePath % "/account/password") { QJsonObject _data; - addParam<>(_data, "new_password", newPassword); - addParam<IfNotEmpty>(_data, "auth", auth); + addParam<>(_data, QStringLiteral("new_password"), newPassword); + addParam<IfNotEmpty>(_data, QStringLiteral("auth"), auth); setRequestData(_data); } @@ -105,18 +111,22 @@ QUrl RequestTokenToResetPasswordJob::makeRequestUrl(QUrl baseUrl) basePath % "/account/password/email/requestToken"); } +static const auto RequestTokenToResetPasswordJobName = QStringLiteral("RequestTokenToResetPasswordJob"); + RequestTokenToResetPasswordJob::RequestTokenToResetPasswordJob() - : BaseJob(HttpVerb::Post, "RequestTokenToResetPasswordJob", + : BaseJob(HttpVerb::Post, RequestTokenToResetPasswordJobName, basePath % "/account/password/email/requestToken", false) { } +static const auto DeactivateAccountJobName = QStringLiteral("DeactivateAccountJob"); + DeactivateAccountJob::DeactivateAccountJob(const QJsonObject& auth) - : BaseJob(HttpVerb::Post, "DeactivateAccountJob", + : BaseJob(HttpVerb::Post, DeactivateAccountJobName, basePath % "/account/deactivate") { QJsonObject _data; - addParam<IfNotEmpty>(_data, "auth", auth); + addParam<IfNotEmpty>(_data, QStringLiteral("auth"), auth); setRequestData(_data); } @@ -129,7 +139,7 @@ class CheckUsernameAvailabilityJob::Private BaseJob::Query queryToCheckUsernameAvailability(const QString& username) { BaseJob::Query _q; - addParam<>(_q, "username", username); + addParam<>(_q, QStringLiteral("username"), username); return _q; } @@ -140,8 +150,10 @@ QUrl CheckUsernameAvailabilityJob::makeRequestUrl(QUrl baseUrl, const QString& u queryToCheckUsernameAvailability(username)); } +static const auto CheckUsernameAvailabilityJobName = QStringLiteral("CheckUsernameAvailabilityJob"); + CheckUsernameAvailabilityJob::CheckUsernameAvailabilityJob(const QString& username) - : BaseJob(HttpVerb::Get, "CheckUsernameAvailabilityJob", + : BaseJob(HttpVerb::Get, CheckUsernameAvailabilityJobName, basePath % "/register/available", queryToCheckUsernameAvailability(username), {}, false) @@ -159,7 +171,7 @@ bool CheckUsernameAvailabilityJob::available() const BaseJob::Status CheckUsernameAvailabilityJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->available = fromJson<bool>(json.value("available")); + d->available = fromJson<bool>(json.value("available"_ls)); return Success; } diff --git a/lib/csapi/report_content.cpp b/lib/csapi/report_content.cpp index f1a1d6f2..a79d4dad 100644 --- a/lib/csapi/report_content.cpp +++ b/lib/csapi/report_content.cpp @@ -12,13 +12,15 @@ using namespace QMatrixClient; static const auto basePath = QStringLiteral("/_matrix/client/r0"); +static const auto ReportContentJobName = QStringLiteral("ReportContentJob"); + ReportContentJob::ReportContentJob(const QString& roomId, const QString& eventId, int score, const QString& reason) - : BaseJob(HttpVerb::Post, "ReportContentJob", + : BaseJob(HttpVerb::Post, ReportContentJobName, basePath % "/rooms/" % roomId % "/report/" % eventId) { QJsonObject _data; - addParam<>(_data, "score", score); - addParam<>(_data, "reason", reason); + addParam<>(_data, QStringLiteral("score"), score); + addParam<>(_data, QStringLiteral("reason"), reason); setRequestData(_data); } diff --git a/lib/csapi/room_send.cpp b/lib/csapi/room_send.cpp index 9637a205..2b39ede2 100644 --- a/lib/csapi/room_send.cpp +++ b/lib/csapi/room_send.cpp @@ -18,8 +18,10 @@ class SendMessageJob::Private QString eventId; }; +static const auto SendMessageJobName = QStringLiteral("SendMessageJob"); + SendMessageJob::SendMessageJob(const QString& roomId, const QString& eventType, const QString& txnId, const QJsonObject& body) - : BaseJob(HttpVerb::Put, "SendMessageJob", + : BaseJob(HttpVerb::Put, SendMessageJobName, basePath % "/rooms/" % roomId % "/send/" % eventType % "/" % txnId) , d(new Private) { @@ -36,7 +38,7 @@ const QString& SendMessageJob::eventId() const BaseJob::Status SendMessageJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->eventId = fromJson<QString>(json.value("event_id")); + d->eventId = fromJson<QString>(json.value("event_id"_ls)); return Success; } diff --git a/lib/csapi/room_state.cpp b/lib/csapi/room_state.cpp index 39f36afb..8f87979d 100644 --- a/lib/csapi/room_state.cpp +++ b/lib/csapi/room_state.cpp @@ -18,8 +18,10 @@ class SetRoomStateWithKeyJob::Private QString eventId; }; +static const auto SetRoomStateWithKeyJobName = QStringLiteral("SetRoomStateWithKeyJob"); + SetRoomStateWithKeyJob::SetRoomStateWithKeyJob(const QString& roomId, const QString& eventType, const QString& stateKey, const QJsonObject& body) - : BaseJob(HttpVerb::Put, "SetRoomStateWithKeyJob", + : BaseJob(HttpVerb::Put, SetRoomStateWithKeyJobName, basePath % "/rooms/" % roomId % "/state/" % eventType % "/" % stateKey) , d(new Private) { @@ -36,7 +38,7 @@ const QString& SetRoomStateWithKeyJob::eventId() const BaseJob::Status SetRoomStateWithKeyJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->eventId = fromJson<QString>(json.value("event_id")); + d->eventId = fromJson<QString>(json.value("event_id"_ls)); return Success; } @@ -46,8 +48,10 @@ class SetRoomStateJob::Private QString eventId; }; +static const auto SetRoomStateJobName = QStringLiteral("SetRoomStateJob"); + SetRoomStateJob::SetRoomStateJob(const QString& roomId, const QString& eventType, const QJsonObject& body) - : BaseJob(HttpVerb::Put, "SetRoomStateJob", + : BaseJob(HttpVerb::Put, SetRoomStateJobName, basePath % "/rooms/" % roomId % "/state/" % eventType) , d(new Private) { @@ -64,7 +68,7 @@ const QString& SetRoomStateJob::eventId() const BaseJob::Status SetRoomStateJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->eventId = fromJson<QString>(json.value("event_id")); + d->eventId = fromJson<QString>(json.value("event_id"_ls)); return Success; } diff --git a/lib/csapi/rooms.cpp b/lib/csapi/rooms.cpp index 4b66b447..a70d9543 100644 --- a/lib/csapi/rooms.cpp +++ b/lib/csapi/rooms.cpp @@ -24,8 +24,10 @@ QUrl GetOneRoomEventJob::makeRequestUrl(QUrl baseUrl, const QString& roomId, con basePath % "/rooms/" % roomId % "/event/" % eventId); } +static const auto GetOneRoomEventJobName = QStringLiteral("GetOneRoomEventJob"); + GetOneRoomEventJob::GetOneRoomEventJob(const QString& roomId, const QString& eventId) - : BaseJob(HttpVerb::Get, "GetOneRoomEventJob", + : BaseJob(HttpVerb::Get, GetOneRoomEventJobName, basePath % "/rooms/" % roomId % "/event/" % eventId) , d(new Private) { @@ -41,10 +43,10 @@ EventPtr&& GetOneRoomEventJob::data() BaseJob::Status GetOneRoomEventJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("data")) + if (!json.contains("data"_ls)) return { JsonParseError, "The key 'data' not found in the response" }; - d->data = fromJson<EventPtr>(json.value("data")); + d->data = fromJson<EventPtr>(json.value("data"_ls)); return Success; } @@ -60,8 +62,10 @@ QUrl GetRoomStateWithKeyJob::makeRequestUrl(QUrl baseUrl, const QString& roomId, basePath % "/rooms/" % roomId % "/state/" % eventType % "/" % stateKey); } +static const auto GetRoomStateWithKeyJobName = QStringLiteral("GetRoomStateWithKeyJob"); + GetRoomStateWithKeyJob::GetRoomStateWithKeyJob(const QString& roomId, const QString& eventType, const QString& stateKey) - : BaseJob(HttpVerb::Get, "GetRoomStateWithKeyJob", + : BaseJob(HttpVerb::Get, GetRoomStateWithKeyJobName, basePath % "/rooms/" % roomId % "/state/" % eventType % "/" % stateKey) , d(new Private) { @@ -77,10 +81,10 @@ StateEventPtr&& GetRoomStateWithKeyJob::data() BaseJob::Status GetRoomStateWithKeyJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("data")) + if (!json.contains("data"_ls)) return { JsonParseError, "The key 'data' not found in the response" }; - d->data = fromJson<StateEventPtr>(json.value("data")); + d->data = fromJson<StateEventPtr>(json.value("data"_ls)); return Success; } @@ -96,8 +100,10 @@ QUrl GetRoomStateByTypeJob::makeRequestUrl(QUrl baseUrl, const QString& roomId, basePath % "/rooms/" % roomId % "/state/" % eventType); } +static const auto GetRoomStateByTypeJobName = QStringLiteral("GetRoomStateByTypeJob"); + GetRoomStateByTypeJob::GetRoomStateByTypeJob(const QString& roomId, const QString& eventType) - : BaseJob(HttpVerb::Get, "GetRoomStateByTypeJob", + : BaseJob(HttpVerb::Get, GetRoomStateByTypeJobName, basePath % "/rooms/" % roomId % "/state/" % eventType) , d(new Private) { @@ -113,10 +119,10 @@ StateEventPtr&& GetRoomStateByTypeJob::data() BaseJob::Status GetRoomStateByTypeJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("data")) + if (!json.contains("data"_ls)) return { JsonParseError, "The key 'data' not found in the response" }; - d->data = fromJson<StateEventPtr>(json.value("data")); + d->data = fromJson<StateEventPtr>(json.value("data"_ls)); return Success; } @@ -132,8 +138,10 @@ QUrl GetRoomStateJob::makeRequestUrl(QUrl baseUrl, const QString& roomId) basePath % "/rooms/" % roomId % "/state"); } +static const auto GetRoomStateJobName = QStringLiteral("GetRoomStateJob"); + GetRoomStateJob::GetRoomStateJob(const QString& roomId) - : BaseJob(HttpVerb::Get, "GetRoomStateJob", + : BaseJob(HttpVerb::Get, GetRoomStateJobName, basePath % "/rooms/" % roomId % "/state") , d(new Private) { @@ -149,10 +157,10 @@ StateEvents&& GetRoomStateJob::data() BaseJob::Status GetRoomStateJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("data")) + if (!json.contains("data"_ls)) return { JsonParseError, "The key 'data' not found in the response" }; - d->data = fromJson<StateEvents>(json.value("data")); + d->data = fromJson<StateEvents>(json.value("data"_ls)); return Success; } @@ -168,8 +176,10 @@ QUrl GetMembersByRoomJob::makeRequestUrl(QUrl baseUrl, const QString& roomId) basePath % "/rooms/" % roomId % "/members"); } +static const auto GetMembersByRoomJobName = QStringLiteral("GetMembersByRoomJob"); + GetMembersByRoomJob::GetMembersByRoomJob(const QString& roomId) - : BaseJob(HttpVerb::Get, "GetMembersByRoomJob", + : BaseJob(HttpVerb::Get, GetMembersByRoomJobName, basePath % "/rooms/" % roomId % "/members") , d(new Private) { @@ -185,7 +195,7 @@ EventsArray<RoomMemberEvent>&& GetMembersByRoomJob::chunk() BaseJob::Status GetMembersByRoomJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->chunk = fromJson<EventsArray<RoomMemberEvent>>(json.value("chunk")); + d->chunk = fromJson<EventsArray<RoomMemberEvent>>(json.value("chunk"_ls)); return Success; } @@ -200,9 +210,9 @@ namespace QMatrixClient const auto& _json = jv.toObject(); GetJoinedMembersByRoomJob::RoomMember result; result.displayName = - fromJson<QString>(_json.value("display_name")); + fromJson<QString>(_json.value("display_name"_ls)); result.avatarUrl = - fromJson<QString>(_json.value("avatar_url")); + fromJson<QString>(_json.value("avatar_url"_ls)); return result; } @@ -221,8 +231,10 @@ QUrl GetJoinedMembersByRoomJob::makeRequestUrl(QUrl baseUrl, const QString& room basePath % "/rooms/" % roomId % "/joined_members"); } +static const auto GetJoinedMembersByRoomJobName = QStringLiteral("GetJoinedMembersByRoomJob"); + GetJoinedMembersByRoomJob::GetJoinedMembersByRoomJob(const QString& roomId) - : BaseJob(HttpVerb::Get, "GetJoinedMembersByRoomJob", + : BaseJob(HttpVerb::Get, GetJoinedMembersByRoomJobName, basePath % "/rooms/" % roomId % "/joined_members") , d(new Private) { @@ -238,7 +250,7 @@ const QHash<QString, GetJoinedMembersByRoomJob::RoomMember>& GetJoinedMembersByR BaseJob::Status GetJoinedMembersByRoomJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->joined = fromJson<QHash<QString, RoomMember>>(json.value("joined")); + d->joined = fromJson<QHash<QString, RoomMember>>(json.value("joined"_ls)); return Success; } diff --git a/lib/csapi/rooms.h b/lib/csapi/rooms.h index 459c6ad5..7d690ec8 100644 --- a/lib/csapi/rooms.h +++ b/lib/csapi/rooms.h @@ -6,8 +6,8 @@ #include "jobs/basejob.h" -#include "events/event.h" #include "events/roommemberevent.h" +#include "events/eventloader.h" #include <QtCore/QHash> #include "converters.h" diff --git a/lib/csapi/search.cpp b/lib/csapi/search.cpp index 75748b38..f3adb315 100644 --- a/lib/csapi/search.cpp +++ b/lib/csapi/search.cpp @@ -19,43 +19,43 @@ namespace QMatrixClient QJsonObject toJson(const SearchJob::IncludeEventContext& pod) { QJsonObject _json; - addParam<IfNotEmpty>(_json, "before_limit", pod.beforeLimit); - addParam<IfNotEmpty>(_json, "after_limit", pod.afterLimit); - addParam<IfNotEmpty>(_json, "include_profile", pod.includeProfile); + addParam<IfNotEmpty>(_json, QStringLiteral("before_limit"), pod.beforeLimit); + addParam<IfNotEmpty>(_json, QStringLiteral("after_limit"), pod.afterLimit); + addParam<IfNotEmpty>(_json, QStringLiteral("include_profile"), pod.includeProfile); return _json; } QJsonObject toJson(const SearchJob::Group& pod) { QJsonObject _json; - addParam<IfNotEmpty>(_json, "key", pod.key); + addParam<IfNotEmpty>(_json, QStringLiteral("key"), pod.key); return _json; } QJsonObject toJson(const SearchJob::Groupings& pod) { QJsonObject _json; - addParam<IfNotEmpty>(_json, "group_by", pod.groupBy); + addParam<IfNotEmpty>(_json, QStringLiteral("group_by"), pod.groupBy); return _json; } QJsonObject toJson(const SearchJob::RoomEventsCriteria& pod) { QJsonObject _json; - addParam<>(_json, "search_term", pod.searchTerm); - addParam<IfNotEmpty>(_json, "keys", pod.keys); - addParam<IfNotEmpty>(_json, "filter", pod.filter); - addParam<IfNotEmpty>(_json, "order_by", pod.orderBy); - addParam<IfNotEmpty>(_json, "event_context", pod.eventContext); - addParam<IfNotEmpty>(_json, "include_state", pod.includeState); - addParam<IfNotEmpty>(_json, "groupings", pod.groupings); + addParam<>(_json, QStringLiteral("search_term"), pod.searchTerm); + addParam<IfNotEmpty>(_json, QStringLiteral("keys"), pod.keys); + addParam<IfNotEmpty>(_json, QStringLiteral("filter"), pod.filter); + addParam<IfNotEmpty>(_json, QStringLiteral("order_by"), pod.orderBy); + addParam<IfNotEmpty>(_json, QStringLiteral("event_context"), pod.eventContext); + addParam<IfNotEmpty>(_json, QStringLiteral("include_state"), pod.includeState); + addParam<IfNotEmpty>(_json, QStringLiteral("groupings"), pod.groupings); return _json; } QJsonObject toJson(const SearchJob::Categories& pod) { QJsonObject _json; - addParam<IfNotEmpty>(_json, "room_events", pod.roomEvents); + addParam<IfNotEmpty>(_json, QStringLiteral("room_events"), pod.roomEvents); return _json; } @@ -66,9 +66,9 @@ namespace QMatrixClient const auto& _json = jv.toObject(); SearchJob::UserProfile result; result.displayname = - fromJson<QString>(_json.value("displayname")); + fromJson<QString>(_json.value("displayname"_ls)); result.avatarUrl = - fromJson<QString>(_json.value("avatar_url")); + fromJson<QString>(_json.value("avatar_url"_ls)); return result; } @@ -81,15 +81,15 @@ namespace QMatrixClient const auto& _json = jv.toObject(); SearchJob::EventContext result; result.begin = - fromJson<QString>(_json.value("start")); + fromJson<QString>(_json.value("start"_ls)); result.end = - fromJson<QString>(_json.value("end")); + fromJson<QString>(_json.value("end"_ls)); result.profileInfo = - fromJson<QHash<QString, SearchJob::UserProfile>>(_json.value("profile_info")); + fromJson<QHash<QString, SearchJob::UserProfile>>(_json.value("profile_info"_ls)); result.eventsBefore = - fromJson<RoomEvents>(_json.value("events_before")); + fromJson<RoomEvents>(_json.value("events_before"_ls)); result.eventsAfter = - fromJson<RoomEvents>(_json.value("events_after")); + fromJson<RoomEvents>(_json.value("events_after"_ls)); return result; } @@ -102,11 +102,11 @@ namespace QMatrixClient const auto& _json = jv.toObject(); SearchJob::Result result; result.rank = - fromJson<double>(_json.value("rank")); + fromJson<double>(_json.value("rank"_ls)); result.result = - fromJson<RoomEventPtr>(_json.value("result")); + fromJson<RoomEventPtr>(_json.value("result"_ls)); result.context = - fromJson<SearchJob::EventContext>(_json.value("context")); + fromJson<SearchJob::EventContext>(_json.value("context"_ls)); return result; } @@ -119,11 +119,11 @@ namespace QMatrixClient const auto& _json = jv.toObject(); SearchJob::GroupValue result; result.nextBatch = - fromJson<QString>(_json.value("next_batch")); + fromJson<QString>(_json.value("next_batch"_ls)); result.order = - fromJson<int>(_json.value("order")); + fromJson<int>(_json.value("order"_ls)); result.results = - fromJson<QStringList>(_json.value("results")); + fromJson<QStringList>(_json.value("results"_ls)); return result; } @@ -136,15 +136,15 @@ namespace QMatrixClient const auto& _json = jv.toObject(); SearchJob::ResultRoomEvents result; result.count = - fromJson<qint64>(_json.value("count")); + fromJson<qint64>(_json.value("count"_ls)); result.results = - fromJson<std::vector<SearchJob::Result>>(_json.value("results")); + fromJson<std::vector<SearchJob::Result>>(_json.value("results"_ls)); result.state = - fromJson<std::unordered_map<QString, StateEvents>>(_json.value("state")); + fromJson<std::unordered_map<QString, StateEvents>>(_json.value("state"_ls)); result.groups = - fromJson<QHash<QString, QHash<QString, SearchJob::GroupValue>>>(_json.value("groups")); + fromJson<QHash<QString, QHash<QString, SearchJob::GroupValue>>>(_json.value("groups"_ls)); result.nextBatch = - fromJson<QString>(_json.value("next_batch")); + fromJson<QString>(_json.value("next_batch"_ls)); return result; } @@ -157,7 +157,7 @@ namespace QMatrixClient const auto& _json = jv.toObject(); SearchJob::ResultCategories result; result.roomEvents = - fromJson<SearchJob::ResultRoomEvents>(_json.value("room_events")); + fromJson<SearchJob::ResultRoomEvents>(_json.value("room_events"_ls)); return result; } @@ -173,18 +173,20 @@ class SearchJob::Private BaseJob::Query queryToSearch(const QString& nextBatch) { BaseJob::Query _q; - addParam<IfNotEmpty>(_q, "next_batch", nextBatch); + addParam<IfNotEmpty>(_q, QStringLiteral("next_batch"), nextBatch); return _q; } +static const auto SearchJobName = QStringLiteral("SearchJob"); + SearchJob::SearchJob(const Categories& searchCategories, const QString& nextBatch) - : BaseJob(HttpVerb::Post, "SearchJob", + : BaseJob(HttpVerb::Post, SearchJobName, basePath % "/search", queryToSearch(nextBatch)) , d(new Private) { QJsonObject _data; - addParam<>(_data, "search_categories", searchCategories); + addParam<>(_data, QStringLiteral("search_categories"), searchCategories); setRequestData(_data); } @@ -198,10 +200,10 @@ const SearchJob::ResultCategories& SearchJob::searchCategories() const BaseJob::Status SearchJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("search_categories")) + if (!json.contains("search_categories"_ls)) return { JsonParseError, "The key 'search_categories' not found in the response" }; - d->searchCategories = fromJson<ResultCategories>(json.value("search_categories")); + d->searchCategories = fromJson<ResultCategories>(json.value("search_categories"_ls)); return Success; } diff --git a/lib/csapi/search.h b/lib/csapi/search.h index 206bacca..572ea6af 100644 --- a/lib/csapi/search.h +++ b/lib/csapi/search.h @@ -6,12 +6,12 @@ #include "jobs/basejob.h" -#include <unordered_map> -#include <QtCore/QHash> #include <QtCore/QJsonObject> -#include "events/event.h" #include "converters.h" #include <QtCore/QVector> +#include <unordered_map> +#include <QtCore/QHash> +#include "events/eventloader.h" namespace QMatrixClient { diff --git a/lib/csapi/tags.cpp b/lib/csapi/tags.cpp index 9cd78aec..1afc3bfc 100644 --- a/lib/csapi/tags.cpp +++ b/lib/csapi/tags.cpp @@ -24,8 +24,10 @@ QUrl GetRoomTagsJob::makeRequestUrl(QUrl baseUrl, const QString& userId, const Q basePath % "/user/" % userId % "/rooms/" % roomId % "/tags"); } +static const auto GetRoomTagsJobName = QStringLiteral("GetRoomTagsJob"); + GetRoomTagsJob::GetRoomTagsJob(const QString& userId, const QString& roomId) - : BaseJob(HttpVerb::Get, "GetRoomTagsJob", + : BaseJob(HttpVerb::Get, GetRoomTagsJobName, basePath % "/user/" % userId % "/rooms/" % roomId % "/tags") , d(new Private) { @@ -41,12 +43,14 @@ const QJsonObject& GetRoomTagsJob::tags() const BaseJob::Status GetRoomTagsJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->tags = fromJson<QJsonObject>(json.value("tags")); + d->tags = fromJson<QJsonObject>(json.value("tags"_ls)); return Success; } +static const auto SetRoomTagJobName = QStringLiteral("SetRoomTagJob"); + SetRoomTagJob::SetRoomTagJob(const QString& userId, const QString& roomId, const QString& tag, const QJsonObject& body) - : BaseJob(HttpVerb::Put, "SetRoomTagJob", + : BaseJob(HttpVerb::Put, SetRoomTagJobName, basePath % "/user/" % userId % "/rooms/" % roomId % "/tags/" % tag) { setRequestData(Data(toJson(body))); @@ -58,8 +62,10 @@ QUrl DeleteRoomTagJob::makeRequestUrl(QUrl baseUrl, const QString& userId, const basePath % "/user/" % userId % "/rooms/" % roomId % "/tags/" % tag); } +static const auto DeleteRoomTagJobName = QStringLiteral("DeleteRoomTagJob"); + DeleteRoomTagJob::DeleteRoomTagJob(const QString& userId, const QString& roomId, const QString& tag) - : BaseJob(HttpVerb::Delete, "DeleteRoomTagJob", + : BaseJob(HttpVerb::Delete, DeleteRoomTagJobName, basePath % "/user/" % userId % "/rooms/" % roomId % "/tags/" % tag) { } diff --git a/lib/csapi/third_party_membership.cpp b/lib/csapi/third_party_membership.cpp index 2372f9d7..c1683338 100644 --- a/lib/csapi/third_party_membership.cpp +++ b/lib/csapi/third_party_membership.cpp @@ -12,14 +12,16 @@ using namespace QMatrixClient; static const auto basePath = QStringLiteral("/_matrix/client/r0"); +static const auto InviteBy3PIDJobName = QStringLiteral("InviteBy3PIDJob"); + InviteBy3PIDJob::InviteBy3PIDJob(const QString& roomId, const QString& idServer, const QString& medium, const QString& address) - : BaseJob(HttpVerb::Post, "InviteBy3PIDJob", + : BaseJob(HttpVerb::Post, InviteBy3PIDJobName, basePath % "/rooms/" % roomId % "/invite") { QJsonObject _data; - addParam<>(_data, "id_server", idServer); - addParam<>(_data, "medium", medium); - addParam<>(_data, "address", address); + addParam<>(_data, QStringLiteral("id_server"), idServer); + addParam<>(_data, QStringLiteral("medium"), medium); + addParam<>(_data, QStringLiteral("address"), address); setRequestData(_data); } diff --git a/lib/csapi/to_device.cpp b/lib/csapi/to_device.cpp index 1478a679..7c7f495a 100644 --- a/lib/csapi/to_device.cpp +++ b/lib/csapi/to_device.cpp @@ -12,12 +12,14 @@ using namespace QMatrixClient; static const auto basePath = QStringLiteral("/_matrix/client/r0"); +static const auto SendToDeviceJobName = QStringLiteral("SendToDeviceJob"); + SendToDeviceJob::SendToDeviceJob(const QString& eventType, const QString& txnId, const QHash<QString, QHash<QString, QJsonObject>>& messages) - : BaseJob(HttpVerb::Put, "SendToDeviceJob", + : BaseJob(HttpVerb::Put, SendToDeviceJobName, basePath % "/sendToDevice/" % eventType % "/" % txnId) { QJsonObject _data; - addParam<IfNotEmpty>(_data, "messages", messages); + addParam<IfNotEmpty>(_data, QStringLiteral("messages"), messages); setRequestData(_data); } diff --git a/lib/csapi/typing.cpp b/lib/csapi/typing.cpp index 6db522c4..bf10912b 100644 --- a/lib/csapi/typing.cpp +++ b/lib/csapi/typing.cpp @@ -12,13 +12,15 @@ using namespace QMatrixClient; static const auto basePath = QStringLiteral("/_matrix/client/r0"); +static const auto SetTypingJobName = QStringLiteral("SetTypingJob"); + SetTypingJob::SetTypingJob(const QString& userId, const QString& roomId, bool typing, Omittable<int> timeout) - : BaseJob(HttpVerb::Put, "SetTypingJob", + : BaseJob(HttpVerb::Put, SetTypingJobName, basePath % "/rooms/" % roomId % "/typing/" % userId) { QJsonObject _data; - addParam<>(_data, "typing", typing); - addParam<IfNotEmpty>(_data, "timeout", timeout); + addParam<>(_data, QStringLiteral("typing"), typing); + addParam<IfNotEmpty>(_data, QStringLiteral("timeout"), timeout); setRequestData(_data); } diff --git a/lib/csapi/users.cpp b/lib/csapi/users.cpp index e7f68bda..408a8cad 100644 --- a/lib/csapi/users.cpp +++ b/lib/csapi/users.cpp @@ -23,11 +23,11 @@ namespace QMatrixClient const auto& _json = jv.toObject(); SearchUserDirectoryJob::User result; result.userId = - fromJson<QString>(_json.value("user_id")); + fromJson<QString>(_json.value("user_id"_ls)); result.displayName = - fromJson<QString>(_json.value("display_name")); + fromJson<QString>(_json.value("display_name"_ls)); result.avatarUrl = - fromJson<QString>(_json.value("avatar_url")); + fromJson<QString>(_json.value("avatar_url"_ls)); return result; } @@ -41,14 +41,16 @@ class SearchUserDirectoryJob::Private bool limited; }; +static const auto SearchUserDirectoryJobName = QStringLiteral("SearchUserDirectoryJob"); + SearchUserDirectoryJob::SearchUserDirectoryJob(const QString& searchTerm, Omittable<int> limit) - : BaseJob(HttpVerb::Post, "SearchUserDirectoryJob", + : BaseJob(HttpVerb::Post, SearchUserDirectoryJobName, basePath % "/user_directory/search") , d(new Private) { QJsonObject _data; - addParam<>(_data, "search_term", searchTerm); - addParam<IfNotEmpty>(_data, "limit", limit); + addParam<>(_data, QStringLiteral("search_term"), searchTerm); + addParam<IfNotEmpty>(_data, QStringLiteral("limit"), limit); setRequestData(_data); } @@ -67,14 +69,14 @@ bool SearchUserDirectoryJob::limited() const BaseJob::Status SearchUserDirectoryJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("results")) + if (!json.contains("results"_ls)) return { JsonParseError, "The key 'results' not found in the response" }; - d->results = fromJson<QVector<User>>(json.value("results")); - if (!json.contains("limited")) + d->results = fromJson<QVector<User>>(json.value("results"_ls)); + if (!json.contains("limited"_ls)) return { JsonParseError, "The key 'limited' not found in the response" }; - d->limited = fromJson<bool>(json.value("limited")); + d->limited = fromJson<bool>(json.value("limited"_ls)); return Success; } diff --git a/lib/csapi/versions.cpp b/lib/csapi/versions.cpp index 7b55b94f..128902e2 100644 --- a/lib/csapi/versions.cpp +++ b/lib/csapi/versions.cpp @@ -24,8 +24,10 @@ QUrl GetVersionsJob::makeRequestUrl(QUrl baseUrl) basePath % "/versions"); } +static const auto GetVersionsJobName = QStringLiteral("GetVersionsJob"); + GetVersionsJob::GetVersionsJob() - : BaseJob(HttpVerb::Get, "GetVersionsJob", + : BaseJob(HttpVerb::Get, GetVersionsJobName, basePath % "/versions", false) , d(new Private) { @@ -41,7 +43,7 @@ const QStringList& GetVersionsJob::versions() const BaseJob::Status GetVersionsJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - d->versions = fromJson<QStringList>(json.value("versions")); + d->versions = fromJson<QStringList>(json.value("versions"_ls)); return Success; } diff --git a/lib/csapi/voip.cpp b/lib/csapi/voip.cpp index f84c140d..8ecf92c6 100644 --- a/lib/csapi/voip.cpp +++ b/lib/csapi/voip.cpp @@ -24,8 +24,10 @@ QUrl GetTurnServerJob::makeRequestUrl(QUrl baseUrl) basePath % "/voip/turnServer"); } +static const auto GetTurnServerJobName = QStringLiteral("GetTurnServerJob"); + GetTurnServerJob::GetTurnServerJob() - : BaseJob(HttpVerb::Get, "GetTurnServerJob", + : BaseJob(HttpVerb::Get, GetTurnServerJobName, basePath % "/voip/turnServer") , d(new Private) { @@ -41,10 +43,10 @@ const QJsonObject& GetTurnServerJob::data() const BaseJob::Status GetTurnServerJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("data")) + if (!json.contains("data"_ls)) return { JsonParseError, "The key 'data' not found in the response" }; - d->data = fromJson<QJsonObject>(json.value("data")); + d->data = fromJson<QJsonObject>(json.value("data"_ls)); return Success; } diff --git a/lib/csapi/whoami.cpp b/lib/csapi/whoami.cpp index 4c231b5f..cb6439ef 100644 --- a/lib/csapi/whoami.cpp +++ b/lib/csapi/whoami.cpp @@ -24,8 +24,10 @@ QUrl GetTokenOwnerJob::makeRequestUrl(QUrl baseUrl) basePath % "/account/whoami"); } +static const auto GetTokenOwnerJobName = QStringLiteral("GetTokenOwnerJob"); + GetTokenOwnerJob::GetTokenOwnerJob() - : BaseJob(HttpVerb::Get, "GetTokenOwnerJob", + : BaseJob(HttpVerb::Get, GetTokenOwnerJobName, basePath % "/account/whoami") , d(new Private) { @@ -41,10 +43,10 @@ const QString& GetTokenOwnerJob::userId() const BaseJob::Status GetTokenOwnerJob::parseJson(const QJsonDocument& data) { auto json = data.object(); - if (!json.contains("user_id")) + if (!json.contains("user_id"_ls)) return { JsonParseError, "The key 'user_id' not found in the response" }; - d->userId = fromJson<QString>(json.value("user_id")); + d->userId = fromJson<QString>(json.value("user_id"_ls)); return Success; } diff --git a/lib/csapi/{{base}}.cpp.mustache b/lib/csapi/{{base}}.cpp.mustache index 8b5acd65..d25997ed 100644 --- a/lib/csapi/{{base}}.cpp.mustache +++ b/lib/csapi/{{base}}.cpp.mustache @@ -11,7 +11,7 @@ using namespace QMatrixClient; QJsonObject QMatrixClient::toJson(const {{qualifiedName}}& pod) { QJsonObject _json;{{#vars}} - addParam<{{^required?}}IfNotEmpty{{/required?}}>(_json, "{{baseName}}", pod.{{nameCamelCase}});{{/vars}} + addParam<{{^required?}}IfNotEmpty{{/required?}}>(_json, QStringLiteral("{{baseName}}"), pod.{{nameCamelCase}});{{/vars}} return _json; } {{/in?}}{{#out?}} @@ -20,7 +20,7 @@ QJsonObject QMatrixClient::toJson(const {{qualifiedName}}& pod) const auto& _json = jv.toObject(); {{qualifiedName}} result; {{#vars}}result.{{nameCamelCase}} = - fromJson<{{dataType.name}}>(_json.value("{{baseName}}")); + fromJson<{{dataType.name}}>(_json.value("{{baseName}}"_ls)); {{/vars}} return result; } @@ -34,7 +34,7 @@ namespace QMatrixClient QJsonObject toJson(const {{qualifiedName}}& pod) { QJsonObject _json;{{#vars}} - addParam<{{^required?}}IfNotEmpty{{/required?}}>(_json, "{{baseName}}", pod.{{nameCamelCase}});{{/vars}} + addParam<{{^required?}}IfNotEmpty{{/required?}}>(_json, QStringLiteral("{{baseName}}"), pod.{{nameCamelCase}});{{/vars}} return _json; } {{/in?}}{{#out?}} @@ -45,7 +45,7 @@ namespace QMatrixClient const auto& _json = jv.toObject(); {{qualifiedName}} result; {{#vars}} result.{{nameCamelCase}} = - fromJson<{{dataType.qualifiedName}}>(_json.value("{{baseName}}")); + fromJson<{{dataType.qualifiedName}}>(_json.value("{{baseName}}"_ls)); {{/vars}} return result; } @@ -61,7 +61,7 @@ class {{camelCaseOperationId}}Job::Private BaseJob::Query queryTo{{camelCaseOperationId}}({{#queryParams}}{{>joinedParamDef}}{{/queryParams}}) { BaseJob::Query _q;{{#queryParams}} - addParam<{{^required?}}IfNotEmpty{{/required?}}>(_q, "{{baseName}}", {{paramName}});{{/queryParams}} + addParam<{{^required?}}IfNotEmpty{{/required?}}>(_q, QStringLiteral("{{baseName}}"), {{paramName}});{{/queryParams}} return _q; } {{/queryParams?}}{{^bodyParams}} @@ -72,8 +72,10 @@ QUrl {{camelCaseOperationId}}Job::makeRequestUrl(QUrl baseUrl{{#allParams?}}, {{ queryTo{{camelCaseOperationId}}({{>passQueryParams}}){{/queryParams?}}); } {{/ bodyParams}} +static const auto {{camelCaseOperationId}}JobName = QStringLiteral("{{camelCaseOperationId}}Job"); + {{camelCaseOperationId}}Job::{{camelCaseOperationId}}Job({{#allParams}}{{>joinedParamDef}}{{/allParams}}) - : BaseJob(HttpVerb::{{#@cap}}{{#@tolower}}{{httpMethod}}{{/@tolower}}{{/@cap}}, "{{camelCaseOperationId}}Job", + : BaseJob(HttpVerb::{{#@cap}}{{#@tolower}}{{httpMethod}}{{/@tolower}}{{/@cap}}, {{camelCaseOperationId}}JobName, basePath{{#pathParts}} % {{_}}{{/pathParts}}{{#queryParams?}}, queryTo{{camelCaseOperationId}}({{>passQueryParams}}){{/queryParams?}}{{#skipAuth}}{{#queryParams?}}, {}{{/queryParams?}}, false{{/skipAuth}}){{#responses}}{{#normalResponse?}}{{#allProperties?}} @@ -87,7 +89,7 @@ QUrl {{camelCaseOperationId}}Job::makeRequestUrl(QUrl baseUrl{{#allParams?}}, {{ }}{{#consumesNonJson?}}{{nameCamelCase}}{{/consumesNonJson? }}{{^consumesNonJson?}}toJson({{nameCamelCase}}){{/consumesNonJson?}}));{{/inlineBody }}{{^inlineBody}} QJsonObject _data;{{#bodyParams}} - addParam<{{^required?}}IfNotEmpty{{/required?}}>(_data, "{{baseName}}", {{paramName}});{{/bodyParams}} + addParam<{{^required?}}IfNotEmpty{{/required?}}>(_data, QStringLiteral("{{baseName}}"), {{paramName}});{{/bodyParams}} setRequestData(_data);{{/inlineBody}} {{/bodyParams?}}{{#producesNonJson?}} setExpectedContentTypes({ {{#produces}}"{{_}}"{{>cjoin}}{{/produces}} }); {{/producesNonJson?}}}{{!<- mind the actual brace}} @@ -108,10 +110,10 @@ BaseJob::Status {{camelCaseOperationId}}Job::parseReply(QNetworkReply* reply) BaseJob::Status {{camelCaseOperationId}}Job::parseJson(const QJsonDocument& data) { auto json = data.object(); - {{# properties}}{{#required?}}if (!json.contains("{{baseName}}")) + {{# properties}}{{#required?}}if (!json.contains("{{baseName}}"_ls)) return { JsonParseError, "The key '{{baseName}}' not found in the response" }; - {{/required?}}d->{{paramName}} = fromJson<{{dataType.name}}>(json.value("{{baseName}}")); + {{/required?}}d->{{paramName}} = fromJson<{{dataType.name}}>(json.value("{{baseName}}"_ls)); {{/ properties}}return Success; }{{/ producesNonJson?}} {{/allProperties?}}{{/normalResponse?}}{{/responses}}{{/operation}}{{/operations}} diff --git a/lib/events/accountdataevents.h b/lib/events/accountdataevents.h index 11667172..671ed776 100644 --- a/lib/events/accountdataevents.h +++ b/lib/events/accountdataevents.h @@ -22,6 +22,7 @@ #include "event.h" #include "eventcontent.h" +#include "converters.h" namespace QMatrixClient { @@ -32,7 +33,7 @@ namespace QMatrixClient { TagRecord (QString order = {}) : order(std::move(order)) { } explicit TagRecord(const QJsonValue& jv) - : order(jv.toObject().value("order").toString()) + : order(jv.toObject().value("order"_ls).toString()) { } QString order; @@ -50,28 +51,31 @@ namespace QMatrixClient using TagsMap = QHash<QString, TagRecord>; -#define DEFINE_SIMPLE_EVENT(_Name, _TypeId, _EnumType, _ContentType, _ContentKey) \ +#define DEFINE_SIMPLE_EVENT(_Name, _TypeId, _ContentType, _ContentKey) \ class _Name : public Event \ { \ public: \ - static constexpr const char* typeId() { return _TypeId; } \ - explicit _Name(const QJsonObject& obj) \ - : Event((_EnumType), obj) \ - , _content(contentJson(), QStringLiteral(#_ContentKey)) \ + using content_type = _ContentType; \ + DEFINE_EVENT_TYPEID(_TypeId, _Name) \ + explicit _Name(QJsonObject obj) \ + : Event(typeId(), std::move(obj)) \ { } \ - template <typename... Ts> \ - explicit _Name(Ts&&... contentArgs) \ - : Event(_EnumType) \ - , _content(QStringLiteral(#_ContentKey), \ - std::forward<Ts>(contentArgs)...) \ + explicit _Name(_ContentType content) \ + : Event(typeId(), matrixTypeId(), \ + QJsonObject { { QStringLiteral(#_ContentKey), \ + toJson(std::move(content)) } }) \ { } \ - const _ContentType& _ContentKey() const { return _content.value; } \ - QJsonObject toJson() const { return _content.toJson(); } \ - protected: \ - EventContent::SimpleContent<_ContentType> _content; \ - }; + auto _ContentKey() const \ + { return fromJson<content_type>(contentJson()[#_ContentKey##_ls]); } \ + }; \ + REGISTER_EVENT_TYPE(_Name) \ + // End of macro + + DEFINE_SIMPLE_EVENT(TagEvent, "m.tag", TagsMap, tags) + DEFINE_SIMPLE_EVENT(ReadMarkerEvent, "m.fully_read", QString, event_id) + DEFINE_SIMPLE_EVENT(IgnoredUsersEvent, "m.ignored_user_list", + QSet<QString>, ignored_users) - DEFINE_SIMPLE_EVENT(TagEvent, "m.tag", EventType::Tag, TagsMap, tags) - DEFINE_SIMPLE_EVENT(ReadMarkerEvent, "m.fully_read", EventType::ReadMarker, - QString, event_id) + DEFINE_EVENTTYPE_ALIAS(Tag, TagEvent) + DEFINE_EVENTTYPE_ALIAS(ReadMarker, ReadMarkerEvent) } diff --git a/lib/events/directchatevent.cpp b/lib/events/directchatevent.cpp index 63d638a3..266d60d8 100644 --- a/lib/events/directchatevent.cpp +++ b/lib/events/directchatevent.cpp @@ -18,18 +18,14 @@ #include "directchatevent.h" -#include "converters.h" +#include <QtCore/QJsonArray> using namespace QMatrixClient; -DirectChatEvent::DirectChatEvent(const QJsonObject& obj) - : Event(Type::DirectChat, obj) -{ } - QMultiHash<QString, QString> DirectChatEvent::usersToDirectChats() const { QMultiHash<QString, QString> result; - const auto json = contentJson(); + const auto& json = contentJson(); for (auto it = json.begin(); it != json.end(); ++it) { // Beware of range-for's over temporary returned from temporary diff --git a/lib/events/directchatevent.h b/lib/events/directchatevent.h index bd8f2d35..7559796b 100644 --- a/lib/events/directchatevent.h +++ b/lib/events/directchatevent.h @@ -25,10 +25,14 @@ namespace QMatrixClient class DirectChatEvent : public Event { public: - explicit DirectChatEvent(const QJsonObject& obj); + DEFINE_EVENT_TYPEID("m.direct", DirectChatEvent) - QMultiHash<QString, QString> usersToDirectChats() const; + explicit DirectChatEvent(const QJsonObject& obj) + : Event(typeId(), obj) + { } - static constexpr const char* typeId() { return "m.direct"; } + QMultiHash<QString, QString> usersToDirectChats() const; }; + REGISTER_EVENT_TYPE(DirectChatEvent) + DEFINE_EVENTTYPE_ALIAS(DirectChat, DirectChatEvent) } diff --git a/lib/events/event.cpp b/lib/events/event.cpp index 576e9426..44bf79a1 100644 --- a/lib/events/event.cpp +++ b/lib/events/event.cpp @@ -18,170 +18,51 @@ #include "event.h" -#include "roommessageevent.h" -#include "simplestateevents.h" -#include "roommemberevent.h" -#include "roomavatarevent.h" -#include "typingevent.h" -#include "receiptevent.h" -#include "accountdataevents.h" -#include "directchatevent.h" -#include "redactionevent.h" #include "logging.h" #include <QtCore/QJsonDocument> using namespace QMatrixClient; -Event::Event(Type type, const QJsonObject& rep) - : _type(type), _originalJson(rep) +event_type_t QMatrixClient::nextTypeId() { - if (!rep.contains("content") && - !rep.value("unsigned").toObject().contains("redacted_because")) - { - qCWarning(EVENTS) << "Event without 'content' node"; - qCWarning(EVENTS) << formatJson << rep; - } + static event_type_t _id = EventTypeTraits<void>::id; + return ++_id; } -Event::~Event() = default; - -QString Event::jsonType() const +Event::Event(Type type, const QJsonObject& json) + : _type(type), _json(json) { - return originalJsonObject().value("type").toString(); -} - -QByteArray Event::originalJson() const -{ - return QJsonDocument(_originalJson).toJson(); -} - -QJsonObject Event::originalJsonObject() const -{ - return _originalJson; -} - -const QJsonObject Event::contentJson() const -{ - return _originalJson["content"].toObject(); -} - -template <typename BaseEventT> -inline event_ptr_tt<BaseEventT> makeIfMatches(const QJsonObject&, const QString&) -{ - return nullptr; -} - -template <typename BaseEventT, typename EventT, typename... EventTs> -inline event_ptr_tt<BaseEventT> makeIfMatches(const QJsonObject& o, - const QString& selector) -{ - if (selector == EventT::typeId()) - return _impl::create<EventT>(o); - - return makeIfMatches<BaseEventT, EventTs...>(o, selector); -} - -template <> -EventPtr _impl::doMakeEvent<Event>(const QJsonObject& obj) -{ - // Check more specific event types first - if (auto e = doMakeEvent<RoomEvent>(obj)) - return ptrCast<Event>(move(e)); - - return makeIfMatches<Event, - TypingEvent, ReceiptEvent, TagEvent, ReadMarkerEvent, DirectChatEvent>( - obj, obj["type"].toString()); -} - -RoomEvent::RoomEvent(Event::Type type) : Event(type) { } - -RoomEvent::RoomEvent(Type type, const QJsonObject& rep) - : Event(type, rep) - , _id(rep["event_id"].toString()) -{ -// if (_id.isEmpty()) -// { -// qCWarning(EVENTS) << "Can't find event_id in a room event"; -// qCWarning(EVENTS) << formatJson << rep; -// } -// if (!rep.contains("origin_server_ts")) -// { -// qCWarning(EVENTS) << "Can't find server timestamp in a room event"; -// qCWarning(EVENTS) << formatJson << rep; -// } -// if (_senderId.isEmpty()) -// { -// qCWarning(EVENTS) << "Can't find sender in a room event"; -// qCWarning(EVENTS) << formatJson << rep; -// } - auto unsignedData = rep["unsigned"].toObject(); - auto redaction = unsignedData.value("redacted_because"); - if (redaction.isObject()) + if (!json.contains(ContentKeyL) && + !json.value(UnsignedKeyL).toObject().contains(RedactedCauseKeyL)) { - _redactedBecause = _impl::create<RedactionEvent>(redaction.toObject()); - return; + qCWarning(EVENTS) << "Event without 'content' node"; + qCWarning(EVENTS) << formatJson << json; } - - _txnId = unsignedData.value("transactionId").toString(); - if (!_txnId.isEmpty()) - qCDebug(EVENTS) << "Event transactionId:" << _txnId; -} - -RoomEvent::~RoomEvent() = default; // Let the smart pointer do its job - -QDateTime RoomEvent::timestamp() const -{ - return QMatrixClient::fromJson<QDateTime>( - originalJsonObject().value("origin_server_ts")); } -QString RoomEvent::roomId() const -{ - return originalJsonObject().value("room_id").toString(); -} - -QString RoomEvent::senderId() const -{ - return originalJsonObject().value("sender").toString(); -} +Event::Event(Type type, event_mtype_t matrixType, const QJsonObject& contentJson) + : Event(type, basicEventJson(matrixType, contentJson)) +{ } -QString RoomEvent::redactionReason() const -{ - return isRedacted() ? _redactedBecause->reason() : QString{}; -} +Event::~Event() = default; -void RoomEvent::addId(const QString& id) +QString Event::matrixType() const { - Q_ASSERT(_id.isEmpty()); Q_ASSERT(!id.isEmpty()); - _id = id; + return fullJson()[TypeKeyL].toString(); } -template <> -RoomEventPtr _impl::doMakeEvent(const QJsonObject& obj) +QByteArray Event::originalJson() const { - // Check more specific event types first - if (auto e = doMakeEvent<StateEventBase>(obj)) - return ptrCast<RoomEvent>(move(e)); - - return makeIfMatches<RoomEvent, - RoomMessageEvent, RedactionEvent>(obj, obj["type"].toString()); + return QJsonDocument(_json).toJson(); } -bool StateEventBase::repeatsState() const +const QJsonObject Event::contentJson() const { - auto contentJson = originalJsonObject().value("content"); - auto prevContentJson = originalJsonObject().value("unsigned") - .toObject().value("prev_content"); - return contentJson == prevContentJson; + return fullJson()[ContentKeyL].toObject(); } -template<> -StateEventPtr _impl::doMakeEvent<StateEventBase>(const QJsonObject& obj) +const QJsonObject Event::unsignedJson() const { - return makeIfMatches<StateEventBase, - RoomNameEvent, RoomAliasesEvent, - RoomCanonicalAliasEvent, RoomMemberEvent, RoomTopicEvent, - RoomAvatarEvent, EncryptionEvent>(obj, obj["type"].toString()); - + return fullJson()[UnsignedKeyL].toObject(); } diff --git a/lib/events/event.h b/lib/events/event.h index cbfa06ac..04384aa7 100644 --- a/lib/events/event.h +++ b/lib/events/event.h @@ -18,11 +18,14 @@ #pragma once -#include "converters.h" #include "util.h" +#include <QtCore/QJsonObject> + namespace QMatrixClient { + // === event_ptr_tt<> and type casting facilities === + template <typename EventT> using event_ptr_tt = std::unique_ptr<EventT>; @@ -44,252 +47,238 @@ namespace QMatrixClient return unique_ptr_cast<TargetT>(ptr); } - namespace _impl + // === Standard Matrix key names and basicEventJson() === + + static const auto TypeKey = QStringLiteral("type"); + static const auto ContentKey = QStringLiteral("content"); + static const auto EventIdKey = QStringLiteral("event_id"); + static const auto TypeKeyL = "type"_ls; + static const auto ContentKeyL = "content"_ls; + static const auto EventIdKeyL = "event_id"_ls; + static const auto UnsignedKeyL = "unsigned"_ls; + static const auto RedactedCauseKeyL = "redacted_because"_ls; + static const auto PrevContentKeyL = "prev_content"_ls; + + // Minimal correct Matrix event JSON + template <typename StrT> + inline QJsonObject basicEventJson(StrT matrixType, + const QJsonObject& content) + { + return { { TypeKey, std::forward<StrT>(matrixType) }, + { ContentKey, content } }; + } + + // === Event factory === + + using event_type_t = size_t; + using event_mtype_t = const char*; + + template <typename EventT> + struct EventTypeTraits + { + static const event_type_t id; + }; + + template <> + struct EventTypeTraits<void> + { + static constexpr event_type_t id = 0; + }; + + event_type_t nextTypeId(); + + template <typename EventT> + const event_type_t EventTypeTraits<EventT>::id = nextTypeId(); + + template <typename EventT> + inline event_type_t typeId() { return EventTypeTraits<std::decay_t<EventT>>::id; } + + inline event_type_t unknownEventTypeId() { return typeId<void>(); } + + template <typename EventT, typename... ArgTs> + inline event_ptr_tt<EventT> makeEvent(ArgTs&&... args) + { + return std::make_unique<EventT>(std::forward<ArgTs>(args)...); + } + + template <typename BaseEventT> + class EventFactory { - template <typename EventT, typename... ArgTs> - inline event_ptr_tt<EventT> create(ArgTs&&... args) - { - return std::make_unique<EventT>(std::forward<ArgTs>(args)...); - } - - template <typename EventT> - inline event_ptr_tt<EventT> doMakeEvent(const QJsonObject& obj) - { - return create<EventT>(obj); - } + public: + template <typename FnT> + static void addMethod(FnT&& method) + { + factories().emplace_back(std::forward<FnT>(method)); + } + + /** Chain two type factories + * Adds the factory class of EventT2 (EventT2::factory_t) to + * the list in factory class of EventT1 (EventT1::factory_t) so + * that when EventT1::factory_t::make() is invoked, types of + * EventT2 factory are looked through as well. This is used + * to include RoomEvent types into the more general Event factory, + * and state event types into the RoomEvent factory. + */ + template <typename EventT> + static auto chainFactory() + { + addMethod(&EventT::factory_t::make); + return 0; + } + + static event_ptr_tt<BaseEventT> make(const QJsonObject& json, + const QString& matrixType) + { + for (const auto& f: factories()) + if (auto e = f(json, matrixType)) + return e; + return makeEvent<BaseEventT>(unknownEventTypeId(), json); + } + + private: + static auto& factories() + { + using inner_factory_tt = + std::function<event_ptr_tt<BaseEventT>(const QJsonObject&, + const QString&)>; + static std::vector<inner_factory_tt> _factories {}; + return _factories; + } + }; + + /** Add a type to its default factory + * Adds a standard factory method (via makeEvent<>) for a given + * type to EventT::factory_t factory class so that it can be + * created dynamically from loadEvent<>(). + * + * \tparam EventT the type to enable dynamic creation of + * \return the registered type id + * \sa loadEvent, Event::type + */ + template <typename EventT> + inline void setupFactory() + { + EventT::factory_t::addMethod( + [] (const QJsonObject& json, const QString& jsonMatrixType) + { + return EventT::matrixTypeId() == jsonMatrixType + ? makeEvent<EventT>(json) : nullptr; + }); } + // === Event === + class Event { Q_GADGET + Q_PROPERTY(Type type READ type CONSTANT) + Q_PROPERTY(QJsonObject contentJson READ contentJson CONSTANT) public: - enum class Type : quint16 - { - Unknown = 0, - Typing, Receipt, Tag, DirectChat, ReadMarker, - RoomEventBase = 0x1000, - RoomMessage = RoomEventBase + 1, - RoomEncryptedMessage, Redaction, - RoomStateEventBase = 0x1800, - RoomName = RoomStateEventBase + 1, - RoomAliases, RoomCanonicalAlias, RoomMember, RoomTopic, - RoomAvatar, RoomEncryption, RoomCreate, RoomJoinRules, - RoomPowerLevels, - Reserved = 0x2000 - }; - - explicit Event(Type type) : _type(type) { } - Event(Type type, const QJsonObject& rep); + using Type = event_type_t; + using factory_t = EventFactory<Event>; + + explicit Event(Type type, const QJsonObject& json); + explicit Event(Type type, event_mtype_t matrixType, + const QJsonObject& contentJson = {}); Event(const Event&) = delete; + Event(Event&&) = default; + Event& operator=(const Event&) = delete; + Event& operator=(Event&&) = delete; virtual ~Event(); Type type() const { return _type; } - QString jsonType() const; - bool isStateEvent() const - { - return (quint16(_type) & 0x1800) == 0x1800; - } + QString matrixType() const; QByteArray originalJson() const; - QJsonObject originalJsonObject() const; + QJsonObject originalJsonObject() const { return fullJson(); } + + const QJsonObject& fullJson() const { return _json; } // According to the CS API spec, every event also has // a "content" object; but since its structure is different for - // different types, we're implementing it per-event type - // (and in most cases it will be a combination of other fields - // instead of "content" field). + // different types, we're implementing it per-event type. const QJsonObject contentJson() const; + const QJsonObject unsignedJson() const; + + virtual bool isStateEvent() const { return false; } - virtual QJsonObject toJson() const { Q_ASSERT(false); return {}; } + protected: + QJsonObject& editJson() { return _json; } private: Type _type; - QJsonObject _originalJson; - - REGISTER_ENUM(Type) - Q_PROPERTY(Type type READ type CONSTANT) - Q_PROPERTY(QJsonObject contentJson READ contentJson CONSTANT) + QJsonObject _json; }; - using EventType = Event::Type; using EventPtr = event_ptr_tt<Event>; - /** Create an event with proper type from a JSON object - * Use this factory template to detect the type from the JSON object - * contents (the detected event type should derive from the template - * parameter type) and create an event object of that type. - */ - template <typename EventT> - inline event_ptr_tt<EventT> makeEvent(const QJsonObject& obj) - { - auto e = _impl::doMakeEvent<EventT>(obj); - if (!e) - e = _impl::create<EventT>(EventType::Unknown, obj); - return e; - } - - namespace _impl - { - template <> - EventPtr doMakeEvent<Event>(const QJsonObject& obj); - } - - template <typename EventT> struct FromJson<event_ptr_tt<EventT>> - { - auto operator()(const QJsonValue& jv) const - { - return makeEvent<EventT>(jv.toObject()); - } - }; - template <typename EventT> using EventsArray = std::vector<event_ptr_tt<EventT>>; using Events = EventsArray<Event>; - class RedactionEvent; + // === Macros used with event class definitions === + + // This macro should be used in a public section of an event class to + // provide matrixTypeId() and typeId(). +#define DEFINE_EVENT_TYPEID(_Id, _Type) \ + static constexpr event_mtype_t matrixTypeId() { return _Id; } \ + static auto typeId() { return QMatrixClient::typeId<_Type>(); } \ + // End of macro + + // This macro should be put after an event class definition (in .h or .cpp) + // to enable its deserialisation from a /sync and other + // polymorphic event arrays +#define REGISTER_EVENT_TYPE(_Type) \ + namespace { \ + [[gnu::unused]] \ + static const auto _factoryAdded##_Type = ( setupFactory<_Type>(), 0); \ + } \ + // End of macro + + // This macro provides constants in EventType:: namespace for + // back-compatibility with libQMatrixClient 0.3 event type system. +#define DEFINE_EVENTTYPE_ALIAS(_Id, _Type) \ + namespace EventType \ + { \ + [[deprecated("Use typeId<>(), is<>() or visit<>()")]] \ + static const auto _Id = typeId<_Type>(); \ + } \ + // End of macro + + // === is<>() and visit<>() === - /** This class corresponds to m.room.* events */ - class RoomEvent : public Event - { - Q_GADGET - Q_PROPERTY(QString id READ id) - Q_PROPERTY(QDateTime timestamp READ timestamp CONSTANT) - Q_PROPERTY(QString roomId READ roomId CONSTANT) - Q_PROPERTY(QString senderId READ senderId CONSTANT) - Q_PROPERTY(QString redactionReason READ redactionReason) - Q_PROPERTY(bool isRedacted READ isRedacted) - Q_PROPERTY(QString transactionId READ transactionId) - public: - // RedactionEvent is an incomplete type here so we cannot inline - // constructors and destructors - explicit RoomEvent(Type type); - RoomEvent(Type type, const QJsonObject& rep); - ~RoomEvent() override; - - QString id() const { return _id; } - QDateTime timestamp() const; - QString roomId() const; - QString senderId() const; - bool isRedacted() const { return bool(_redactedBecause); } - const event_ptr_tt<RedactionEvent>& redactedBecause() const - { - return _redactedBecause; - } - QString redactionReason() const; - const QString& transactionId() const { return _txnId; } - - /** - * Sets the transaction id for locally created events. This should be - * done before the event is exposed to any code using the respective - * Q_PROPERTY. - * - * \param txnId - transaction id, normally obtained from - * Connection::generateTxnId() - */ - void setTransactionId(const QString& txnId) { _txnId = txnId; } - - /** - * Sets event id for locally created events - * - * When a new event is created locally, it has no server id yet. - * This function allows to add the id once the confirmation from - * the server is received. There should be no id set previously - * in the event. It's the responsibility of the code calling addId() - * to notify clients that use Q_PROPERTY(id) about its change - */ - void addId(const QString& id); + template <typename EventT> + inline bool is(const Event& e) { return e.type() == typeId<EventT>(); } - private: - QString _id; - event_ptr_tt<RedactionEvent> _redactedBecause; - QString _txnId; - }; - using RoomEventPtr = event_ptr_tt<RoomEvent>; - using RoomEvents = EventsArray<RoomEvent>; - using RoomEventsRange = Range<RoomEvents>; + inline bool isUnknown(const Event& e) { return e.type() == unknownEventTypeId(); } - namespace _impl + template <typename FnT> + inline fn_return_t<FnT> visit(const Event& event, FnT visitor) { - template <> - RoomEventPtr doMakeEvent<RoomEvent>(const QJsonObject& obj); + using event_type = fn_arg_t<FnT>; + if (is<event_type>(event)) + return visitor(static_cast<event_type>(event)); + return fn_return_t<FnT>(); } - class StateEventBase: public RoomEvent + template <typename FnT, typename... FnTs> + inline auto visit(const Event& event, FnT visitor1, FnTs&&... visitors) { - public: - explicit StateEventBase(Type type, const QJsonObject& obj) - : RoomEvent(obj.contains("state_key") ? type : Type::Unknown, - obj) - { } - explicit StateEventBase(Type type) - : RoomEvent(type) - { } - ~StateEventBase() override = default; - - virtual bool repeatsState() const; - }; - using StateEventPtr = event_ptr_tt<StateEventBase>; - using StateEvents = EventsArray<StateEventBase>; + using event_type1 = fn_arg_t<FnT>; + if (is<event_type1>(event)) + return visitor1(static_cast<event_type1&>(event)); - namespace _impl - { - template <> - StateEventPtr doMakeEvent<StateEventBase>(const QJsonObject& obj); + return visit(event, std::forward<FnTs>(visitors)...); } - template <typename ContentT> - struct Prev + template <typename BaseEventT, typename... FnTs> + inline auto visit(const event_ptr_tt<BaseEventT>& eptr, FnTs&&... visitors) { - template <typename... ContentParamTs> - explicit Prev(const QJsonObject& unsignedJson, - ContentParamTs&&... contentParams) - : senderId(unsignedJson.value("prev_sender").toString()) - , content(unsignedJson.value("prev_content").toObject(), - std::forward<ContentParamTs>(contentParams)...) - { } - - QString senderId; - ContentT content; - }; - - template <typename ContentT> - class StateEvent: public StateEventBase - { - public: - using content_type = ContentT; - - template <typename... ContentParamTs> - explicit StateEvent(Type type, const QJsonObject& obj, - ContentParamTs&&... contentParams) - : StateEventBase(type, obj) - , _content(contentJson(), - std::forward<ContentParamTs>(contentParams)...) - { - auto unsignedData = obj.value("unsigned").toObject(); - if (unsignedData.contains("prev_content")) - _prev = std::make_unique<Prev<ContentT>>(unsignedData, - std::forward<ContentParamTs>(contentParams)...); - } - template <typename... ContentParamTs> - explicit StateEvent(Type type, ContentParamTs&&... contentParams) - : StateEventBase(type) - , _content(std::forward<ContentParamTs>(contentParams)...) - { } - - QJsonObject toJson() const override { return _content.toJson(); } - - const ContentT& content() const { return _content; } - /** @deprecated Use prevContent instead */ - const ContentT* prev_content() const { return prevContent(); } - const ContentT* prevContent() const - { return _prev ? &_prev->content : nullptr; } - QString prevSenderId() const { return _prev ? _prev->senderId : ""; } + using return_type = decltype(visit(*eptr, visitors...)); + if (eptr) + return visit(*eptr, visitors...); + return return_type(); + } - protected: - ContentT _content; - std::unique_ptr<Prev<ContentT>> _prev; - }; } // namespace QMatrixClient Q_DECLARE_METATYPE(QMatrixClient::Event*) -Q_DECLARE_METATYPE(QMatrixClient::RoomEvent*) Q_DECLARE_METATYPE(const QMatrixClient::Event*) -Q_DECLARE_METATYPE(const QMatrixClient::RoomEvent*) diff --git a/lib/events/eventcontent.cpp b/lib/events/eventcontent.cpp index f5974b46..a6b1c763 100644 --- a/lib/events/eventcontent.cpp +++ b/lib/events/eventcontent.cpp @@ -17,8 +17,8 @@ */ #include "eventcontent.h" +#include "util.h" -#include <QtCore/QUrl> #include <QtCore/QMimeDatabase> using namespace QMatrixClient::EventContent; @@ -39,9 +39,9 @@ FileInfo::FileInfo(const QUrl& u, int payloadSize, const QMimeType& mimeType, FileInfo::FileInfo(const QUrl& u, const QJsonObject& infoJson, const QString& originalFilename) : originalInfoJson(infoJson) - , mimeType(QMimeDatabase().mimeTypeForName(infoJson["mimetype"].toString())) + , mimeType(QMimeDatabase().mimeTypeForName(infoJson["mimetype"_ls].toString())) , url(u) - , payloadSize(infoJson["size"].toInt()) + , payloadSize(infoJson["size"_ls].toInt()) , originalName(originalFilename) { if (!mimeType.isValid()) @@ -51,8 +51,8 @@ FileInfo::FileInfo(const QUrl& u, const QJsonObject& infoJson, void FileInfo::fillInfoJson(QJsonObject* infoJson) const { Q_ASSERT(infoJson); - infoJson->insert("size", payloadSize); - infoJson->insert("mimetype", mimeType.name()); + infoJson->insert(QStringLiteral("size"), payloadSize); + infoJson->insert(QStringLiteral("mimetype"), mimeType.name()); } ImageInfo::ImageInfo(const QUrl& u, int fileSize, QMimeType mimeType, @@ -63,23 +63,24 @@ ImageInfo::ImageInfo(const QUrl& u, int fileSize, QMimeType mimeType, ImageInfo::ImageInfo(const QUrl& u, const QJsonObject& infoJson, const QString& originalFilename) : FileInfo(u, infoJson, originalFilename) - , imageSize(infoJson["w"].toInt(), infoJson["h"].toInt()) + , imageSize(infoJson["w"_ls].toInt(), infoJson["h"_ls].toInt()) { } void ImageInfo::fillInfoJson(QJsonObject* infoJson) const { FileInfo::fillInfoJson(infoJson); - infoJson->insert("w", imageSize.width()); - infoJson->insert("h", imageSize.height()); + infoJson->insert(QStringLiteral("w"), imageSize.width()); + infoJson->insert(QStringLiteral("h"), imageSize.height()); } Thumbnail::Thumbnail(const QJsonObject& infoJson) - : ImageInfo(infoJson["thumbnail_url"].toString(), - infoJson["thumbnail_info"].toObject()) + : ImageInfo(infoJson["thumbnail_url"_ls].toString(), + infoJson["thumbnail_info"_ls].toObject()) { } void Thumbnail::fillInfoJson(QJsonObject* infoJson) const { - infoJson->insert("thumbnail_url", url.toString()); - infoJson->insert("thumbnail_info", toInfoJson<ImageInfo>(*this)); + infoJson->insert(QStringLiteral("thumbnail_url"), url.toString()); + infoJson->insert(QStringLiteral("thumbnail_info"), + toInfoJson<ImageInfo>(*this)); } diff --git a/lib/events/eventcontent.h b/lib/events/eventcontent.h index 9d44aec0..91d7a8c8 100644 --- a/lib/events/eventcontent.h +++ b/lib/events/eventcontent.h @@ -21,14 +21,11 @@ // This file contains generic event content definitions, applicable to room // message events as well as other events (e.g., avatars). -#include "converters.h" - +#include <QtCore/QJsonObject> #include <QtCore/QMimeType> #include <QtCore/QUrl> #include <QtCore/QSize> -#include <functional> - namespace QMatrixClient { namespace EventContent @@ -58,37 +55,6 @@ namespace QMatrixClient virtual void fillJson(QJsonObject* o) const = 0; }; - template <typename T = QString> - class SimpleContent: public Base - { - public: - using value_type = T; - - // The constructor is templated to enable perfect forwarding - template <typename TT> - SimpleContent(QString keyName, TT&& value) - : value(std::forward<TT>(value)), key(std::move(keyName)) - { } - SimpleContent(const QJsonObject& json, QString keyName) - : Base(json) - , value(QMatrixClient::fromJson<T>(json[keyName])) - , key(std::move(keyName)) - { } - - public: - T value; - - protected: - QString key; - - private: - void fillJson(QJsonObject* json) const override - { - Q_ASSERT(json); - json->insert(key, QMatrixClient::toJson(value)); - } - }; - // The below structures fairly follow CS spec 11.2.1.6. The overall // set of attributes for each content types is a superset of the spec // but specific aggregation structure is altered. See doc comments to diff --git a/lib/events/eventloader.h b/lib/events/eventloader.h new file mode 100644 index 00000000..5f1e3b57 --- /dev/null +++ b/lib/events/eventloader.h @@ -0,0 +1,57 @@ +/****************************************************************************** +* Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#include "stateevent.h" +#include "converters.h" + +namespace QMatrixClient { + /** Create an event with proper type from a JSON object + * Use this factory template to detect the type from the JSON object + * contents (the detected event type should derive from the template + * parameter type) and create an event object of that type. + */ + template <typename BaseEventT> + inline event_ptr_tt<BaseEventT> loadEvent(const QJsonObject& fullJson) + { + return EventFactory<BaseEventT> + ::make(fullJson, fullJson[TypeKeyL].toString()); + } + + /** Create an event from a type string and content JSON + * Use this factory template to resolve the C++ type from the Matrix + * type string in \p matrixType and create an event of that type that has + * its content part set to \p content. + */ + template <typename BaseEventT> + inline event_ptr_tt<BaseEventT> loadEvent(const QString& matrixType, + const QJsonObject& content) + { + return EventFactory<BaseEventT> + ::make(basicEventJson(matrixType, content), matrixType); + } + + template <typename EventT> struct FromJson<event_ptr_tt<EventT>> + { + auto operator()(const QJsonValue& jv) const + { + return loadEvent<EventT>(jv.toObject()); + } + }; +} // namespace QMatrixClient diff --git a/lib/events/receiptevent.cpp b/lib/events/receiptevent.cpp index a12f4c05..47e1398c 100644 --- a/lib/events/receiptevent.cpp +++ b/lib/events/receiptevent.cpp @@ -41,11 +41,9 @@ Example of a Receipt Event: using namespace QMatrixClient; ReceiptEvent::ReceiptEvent(const QJsonObject& obj) - : Event(Type::Receipt, obj) + : Event(typeId(), obj) { - Q_ASSERT(obj["type"].toString() == typeId()); - - const QJsonObject contents = contentJson(); + const auto& contents = contentJson(); _eventsWithReceipts.reserve(contents.size()); for( auto eventIt = contents.begin(); eventIt != contents.end(); ++eventIt ) { @@ -55,14 +53,15 @@ ReceiptEvent::ReceiptEvent(const QJsonObject& obj) qCDebug(EPHEMERAL) << "ReceiptEvent content follows:\n" << contents; continue; } - const QJsonObject reads = eventIt.value().toObject().value("m.read").toObject(); + const QJsonObject reads = eventIt.value().toObject() + .value("m.read"_ls).toObject(); QVector<Receipt> receipts; receipts.reserve(reads.size()); for( auto userIt = reads.begin(); userIt != reads.end(); ++userIt ) { const QJsonObject user = userIt.value().toObject(); receipts.push_back({userIt.key(), - QMatrixClient::fromJson<QDateTime>(user["ts"])}); + fromJson<QDateTime>(user["ts"_ls])}); } _eventsWithReceipts.push_back({eventIt.key(), std::move(receipts)}); } diff --git a/lib/events/receiptevent.h b/lib/events/receiptevent.h index e8d3a65f..c15a01c2 100644 --- a/lib/events/receiptevent.h +++ b/lib/events/receiptevent.h @@ -21,6 +21,7 @@ #include "event.h" #include <QtCore/QVector> +#include <QtCore/QDateTime> namespace QMatrixClient { @@ -39,14 +40,15 @@ namespace QMatrixClient class ReceiptEvent: public Event { public: + DEFINE_EVENT_TYPEID("m.receipt", ReceiptEvent) explicit ReceiptEvent(const QJsonObject& obj); - EventsWithReceipts eventsWithReceipts() const + const EventsWithReceipts& eventsWithReceipts() const { return _eventsWithReceipts; } - static constexpr const char* typeId() { return "m.receipt"; } - private: EventsWithReceipts _eventsWithReceipts; }; + REGISTER_EVENT_TYPE(ReceiptEvent) + DEFINE_EVENTTYPE_ALIAS(Receipt, ReceiptEvent) } // namespace QMatrixClient diff --git a/lib/events/redactionevent.h b/lib/events/redactionevent.h index dad54788..64504d57 100644 --- a/lib/events/redactionevent.h +++ b/lib/events/redactionevent.h @@ -25,19 +25,17 @@ namespace QMatrixClient class RedactionEvent : public RoomEvent { public: - static constexpr const char* typeId() { return "m.room.redaction"; } + DEFINE_EVENT_TYPEID("m.room.redaction", RedactionEvent) explicit RedactionEvent(const QJsonObject& obj) - : RoomEvent(Type::Redaction, obj) - , _redactedEvent(obj.value("redacts").toString()) - , _reason(contentJson().value("reason").toString()) + : RoomEvent(typeId(), obj) { } - const QString& redactedEvent() const { return _redactedEvent; } - const QString& reason() const { return _reason; } - - private: - QString _redactedEvent; - QString _reason; + QString redactedEvent() const + { return fullJson()["redacts"_ls].toString(); } + QString reason() const + { return contentJson()["reason"_ls].toString(); } }; + REGISTER_EVENT_TYPE(RedactionEvent) + DEFINE_EVENTTYPE_ALIAS(Redaction, RedactionEvent) } // namespace QMatrixClient diff --git a/lib/events/roomavatarevent.h b/lib/events/roomavatarevent.h index 0e44ad7c..491861b1 100644 --- a/lib/events/roomavatarevent.h +++ b/lib/events/roomavatarevent.h @@ -20,8 +20,6 @@ #include "event.h" -#include <utility> - #include "eventcontent.h" namespace QMatrixClient @@ -33,11 +31,12 @@ namespace QMatrixClient // without a thumbnail. But The Spec says there be thumbnails, and // we follow The Spec. public: + DEFINE_EVENT_TYPEID("m.room.avatar", RoomAvatarEvent) explicit RoomAvatarEvent(const QJsonObject& obj) - : StateEvent(Type::RoomAvatar, obj) + : StateEvent(typeId(), obj) { } - - static constexpr const char* typeId() { return "m.room.avatar"; } + QUrl url() const { return content().url; } }; - + REGISTER_EVENT_TYPE(RoomAvatarEvent) + DEFINE_EVENTTYPE_ALIAS(RoomAvatar, RoomAvatarEvent) } // namespace QMatrixClient diff --git a/lib/events/roomevent.cpp b/lib/events/roomevent.cpp new file mode 100644 index 00000000..3d09af8a --- /dev/null +++ b/lib/events/roomevent.cpp @@ -0,0 +1,82 @@ +/****************************************************************************** +* Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "roomevent.h" + +#include "redactionevent.h" +#include "converters.h" +#include "logging.h" + +using namespace QMatrixClient; + +[[gnu::unused]] static auto roomEventTypeInitialised = + Event::factory_t::chainFactory<RoomEvent>(); + +RoomEvent::RoomEvent(Type type, event_mtype_t matrixType, + const QJsonObject& contentJson) + : Event(type, matrixType, contentJson) +{ } + +RoomEvent::RoomEvent(Type type, const QJsonObject& json) + : Event(type, json) +{ + const auto unsignedData = json[UnsignedKeyL].toObject(); + const auto redaction = unsignedData[RedactedCauseKeyL]; + if (redaction.isObject()) + { + _redactedBecause = makeEvent<RedactionEvent>(redaction.toObject()); + return; + } + + _txnId = unsignedData.value("transactionId"_ls).toString(); + if (!_txnId.isEmpty()) + qCDebug(EVENTS) << "Event transactionId:" << _txnId; +} + +RoomEvent::~RoomEvent() = default; // Let the smart pointer do its job + +QString RoomEvent::id() const +{ + return fullJson()[EventIdKeyL].toString(); +} + +QDateTime RoomEvent::timestamp() const +{ + return QMatrixClient::fromJson<QDateTime>(fullJson()["origin_server_ts"_ls]); +} + +QString RoomEvent::roomId() const +{ + return fullJson()["room_id"_ls].toString(); +} + +QString RoomEvent::senderId() const +{ + return fullJson()["sender"_ls].toString(); +} + +QString RoomEvent::redactionReason() const +{ + return isRedacted() ? _redactedBecause->reason() : QString{}; +} + +void RoomEvent::addId(const QString& newId) +{ + Q_ASSERT(id().isEmpty()); Q_ASSERT(!newId.isEmpty()); + editJson().insert(EventIdKey, newId); +} diff --git a/lib/events/roomevent.h b/lib/events/roomevent.h new file mode 100644 index 00000000..d2bc6edc --- /dev/null +++ b/lib/events/roomevent.h @@ -0,0 +1,91 @@ +/****************************************************************************** +* Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#include "event.h" + +#include <QtCore/QDateTime> + +namespace QMatrixClient { + class RedactionEvent; + + /** This class corresponds to m.room.* events */ + class RoomEvent : public Event + { + Q_GADGET + Q_PROPERTY(QString id READ id) + Q_PROPERTY(QDateTime timestamp READ timestamp CONSTANT) + Q_PROPERTY(QString roomId READ roomId CONSTANT) + Q_PROPERTY(QString senderId READ senderId CONSTANT) + Q_PROPERTY(QString redactionReason READ redactionReason) + Q_PROPERTY(bool isRedacted READ isRedacted) + Q_PROPERTY(QString transactionId READ transactionId) + public: + using factory_t = EventFactory<RoomEvent>; + + // RedactionEvent is an incomplete type here so we cannot inline + // constructors and destructors and we cannot use 'using'. + RoomEvent(Type type, event_mtype_t matrixType, + const QJsonObject& contentJson = {}); + RoomEvent(Type type, const QJsonObject& json); + ~RoomEvent() override; + + QString id() const; + QDateTime timestamp() const; + QString roomId() const; + QString senderId() const; + bool isRedacted() const { return bool(_redactedBecause); } + const event_ptr_tt<RedactionEvent>& redactedBecause() const + { + return _redactedBecause; + } + QString redactionReason() const; + const QString& transactionId() const { return _txnId; } + + /** + * Sets the transaction id for locally created events. This should be + * done before the event is exposed to any code using the respective + * Q_PROPERTY. + * + * \param txnId - transaction id, normally obtained from + * Connection::generateTxnId() + */ + void setTransactionId(const QString& txnId) { _txnId = txnId; } + + /** + * Sets event id for locally created events + * + * When a new event is created locally, it has no server id yet. + * This function allows to add the id once the confirmation from + * the server is received. There should be no id set previously + * in the event. It's the responsibility of the code calling addId() + * to notify clients that use Q_PROPERTY(id) about its change + */ + void addId(const QString& newId); + + private: + event_ptr_tt<RedactionEvent> _redactedBecause; + QString _txnId; + }; + using RoomEventPtr = event_ptr_tt<RoomEvent>; + using RoomEvents = EventsArray<RoomEvent>; + using RoomEventsRange = Range<RoomEvents>; +} // namespace QMatrixClient +Q_DECLARE_METATYPE(QMatrixClient::RoomEvent*) +Q_DECLARE_METATYPE(const QMatrixClient::RoomEvent*) diff --git a/lib/events/roommemberevent.cpp b/lib/events/roommemberevent.cpp index 76b003c2..79e4af2d 100644 --- a/lib/events/roommemberevent.cpp +++ b/lib/events/roommemberevent.cpp @@ -18,6 +18,7 @@ #include "roommemberevent.h" +#include "converters.h" #include "logging.h" #include <array> @@ -50,10 +51,10 @@ namespace QMatrixClient } MemberEventContent::MemberEventContent(const QJsonObject& json) - : membership(fromJson<MembershipType>(json["membership"])) - , isDirect(json["is_direct"].toBool()) - , displayName(json["displayname"].toString()) - , avatarUrl(json["avatar_url"].toString()) + : membership(fromJson<MembershipType>(json["membership"_ls])) + , isDirect(json["is_direct"_ls].toBool()) + , displayName(json["displayname"_ls].toString()) + , avatarUrl(json["avatar_url"_ls].toString()) { } void MemberEventContent::fillJson(QJsonObject* o) const @@ -62,8 +63,8 @@ void MemberEventContent::fillJson(QJsonObject* o) const Q_ASSERT_X(membership != MembershipType::Undefined, __FUNCTION__, "The key 'membership' must be explicit in MemberEventContent"); if (membership != MembershipType::Undefined) - o->insert("membership", membershipStrings[membership]); - o->insert("displayname", displayName); + o->insert(QStringLiteral("membership"), membershipStrings[membership]); + o->insert(QStringLiteral("displayname"), displayName); if (avatarUrl.isValid()) - o->insert("avatar_url", avatarUrl.toString()); + o->insert(QStringLiteral("avatar_url"), avatarUrl.toString()); } diff --git a/lib/events/roommemberevent.h b/lib/events/roommemberevent.h index 8e0cc0a4..f3e4f53a 100644 --- a/lib/events/roommemberevent.h +++ b/lib/events/roommemberevent.h @@ -18,12 +18,9 @@ #pragma once -#include "event.h" - +#include "stateevent.h" #include "eventcontent.h" -#include <QtCore/QUrl> - namespace QMatrixClient { class MemberEventContent: public EventContent::Base @@ -36,6 +33,9 @@ namespace QMatrixClient : membership(mt) { } explicit MemberEventContent(const QJsonObject& json); + explicit MemberEventContent(const QJsonValue& jv) + : MemberEventContent(jv.toObject()) + { } MembershipType membership; bool isDirect = false; @@ -52,23 +52,26 @@ namespace QMatrixClient { Q_GADGET public: - static constexpr const char* typeId() { return "m.room.member"; } + DEFINE_EVENT_TYPEID("m.room.member", RoomMemberEvent) using MembershipType = MemberEventContent::MembershipType; - explicit RoomMemberEvent(Type type, const QJsonObject& obj) - : StateEvent(type, obj) + explicit RoomMemberEvent(const QJsonObject& obj) + : StateEvent(typeId(), obj) { } RoomMemberEvent(MemberEventContent&& c) - : StateEvent(Type::RoomMember, c) + : StateEvent(typeId(), matrixTypeId(), c.toJson()) { } - explicit RoomMemberEvent(const QJsonObject& obj) - : RoomMemberEvent(Type::RoomMember, obj) + + // This is a special constructor enabling RoomMemberEvent to be + // a base class for more specific member events. + RoomMemberEvent(Type type, const QJsonObject& fullJson) + : StateEvent(type, fullJson) { } MembershipType membership() const { return content().membership; } QString userId() const - { return originalJsonObject().value("state_key").toString(); } + { return fullJson()["state_key"_ls].toString(); } bool isDirect() const { return content().isDirect; } QString displayName() const { return content().displayName; } QUrl avatarUrl() const { return content().avatarUrl; } @@ -76,4 +79,6 @@ namespace QMatrixClient private: REGISTER_ENUM(MembershipType) }; + REGISTER_EVENT_TYPE(RoomMemberEvent) + DEFINE_EVENTTYPE_ALIAS(RoomMember, RoomMemberEvent) } // namespace QMatrixClient diff --git a/lib/events/roommessageevent.cpp b/lib/events/roommessageevent.cpp index 1a4e74bf..e07054a4 100644 --- a/lib/events/roommessageevent.cpp +++ b/lib/events/roommessageevent.cpp @@ -35,7 +35,7 @@ TypedBase* make(const QJsonObject& json) struct MsgTypeDesc { - QString jsonType; + QString matrixType; MsgType enumType; TypedBase* (*maker)(const QJsonObject&); }; @@ -56,39 +56,56 @@ QString msgTypeToJson(MsgType enumType) auto it = std::find_if(msgTypes.begin(), msgTypes.end(), [=](const MsgTypeDesc& mtd) { return mtd.enumType == enumType; }); if (it != msgTypes.end()) - return it->jsonType; + return it->matrixType; return {}; } -MsgType jsonToMsgType(const QString& jsonType) +MsgType jsonToMsgType(const QString& matrixType) { auto it = std::find_if(msgTypes.begin(), msgTypes.end(), - [=](const MsgTypeDesc& mtd) { return mtd.jsonType == jsonType; }); + [=](const MsgTypeDesc& mtd) { return mtd.matrixType == matrixType; }); if (it != msgTypes.end()) return it->enumType; return MsgType::Unknown; } +inline QJsonObject toMsgJson(const QString& plainBody, const QString& jsonMsgType, + TypedBase* content) +{ + auto json = content ? content->toJson() : QJsonObject(); + json.insert(QStringLiteral("msgtype"), jsonMsgType); + json.insert(QStringLiteral("body"), plainBody); + return json; +} + +static const auto MsgTypeKey = "msgtype"_ls; +static const auto BodyKey = "body"_ls; + +RoomMessageEvent::RoomMessageEvent(const QString& plainBody, + const QString& jsonMsgType, TypedBase* content) + : RoomEvent(typeId(), matrixTypeId(), + toMsgJson(plainBody, jsonMsgType, content)) + , _content(content) +{ } + RoomMessageEvent::RoomMessageEvent(const QString& plainBody, MsgType msgType, TypedBase* content) : RoomMessageEvent(plainBody, msgTypeToJson(msgType), content) { } RoomMessageEvent::RoomMessageEvent(const QJsonObject& obj) - : RoomEvent(Type::RoomMessage, obj), _content(nullptr) + : RoomEvent(typeId(), obj), _content(nullptr) { if (isRedacted()) return; const QJsonObject content = contentJson(); - if ( content.contains("msgtype") && content.contains("body") ) + if ( content.contains(MsgTypeKey) && content.contains(BodyKey) ) { - _plainBody = content["body"].toString(); - - _msgtype = content["msgtype"].toString(); + auto msgtype = content[MsgTypeKey].toString(); for (const auto& mt: msgTypes) - if (mt.jsonType == _msgtype) + if (mt.matrixType == msgtype) _content.reset(mt.maker(content)); if (!_content) @@ -107,13 +124,25 @@ RoomMessageEvent::RoomMessageEvent(const QJsonObject& obj) RoomMessageEvent::MsgType RoomMessageEvent::msgtype() const { - return jsonToMsgType(_msgtype); + return jsonToMsgType(rawMsgtype()); +} + +QString RoomMessageEvent::rawMsgtype() const +{ + return contentJson()[MsgTypeKey].toString(); +} + +QString RoomMessageEvent::plainBody() const +{ + return contentJson()[BodyKey].toString(); } QMimeType RoomMessageEvent::mimeType() const { - return _content ? _content->type() : - QMimeDatabase().mimeTypeForName("text/plain"); + static const auto PlainTextMimeType = + QMimeDatabase().mimeTypeForName("text/plain"); + return _content ? _content->type() : PlainTextMimeType; + ; } bool RoomMessageEvent::hasTextContent() const @@ -133,14 +162,6 @@ bool RoomMessageEvent::hasThumbnail() const return content() && content()->thumbnailInfo(); } -QJsonObject RoomMessageEvent::toJson() const -{ - QJsonObject obj = _content ? _content->toJson() : QJsonObject(); - obj.insert("msgtype", msgTypeToJson(msgtype())); - obj.insert("body", plainBody()); - return obj; -} - TextContent::TextContent(const QString& text, const QString& contentType) : mimeType(QMimeDatabase().mimeTypeForName(contentType)), body(text) { } @@ -148,26 +169,29 @@ TextContent::TextContent(const QString& text, const QString& contentType) TextContent::TextContent(const QJsonObject& json) { QMimeDatabase db; + static const auto PlainTextMimeType = db.mimeTypeForName("text/plain"); + static const auto HtmlMimeType = db.mimeTypeForName("text/html"); // Special-casing the custom matrix.org's (actually, Riot's) way // of sending HTML messages. - if (json["format"].toString() == "org.matrix.custom.html") + if (json["format"_ls].toString() == "org.matrix.custom.html") { - mimeType = db.mimeTypeForName("text/html"); - body = json["formatted_body"].toString(); + mimeType = HtmlMimeType; + body = json["formatted_body"_ls].toString(); } else { // Falling back to plain text, as there's no standard way to describe // rich text in messages. - mimeType = db.mimeTypeForName("text/plain"); - body = json["body"].toString(); + mimeType = PlainTextMimeType; + body = json[BodyKey].toString(); } } void TextContent::fillJson(QJsonObject* json) const { Q_ASSERT(json); - json->insert("format", QStringLiteral("org.matrix.custom.html")); - json->insert("formatted_body", body); + json->insert(QStringLiteral("format"), + QStringLiteral("org.matrix.custom.html")); + json->insert(QStringLiteral("formatted_body"), body); } LocationContent::LocationContent(const QString& geoUri, const ImageInfo& thumbnail) @@ -176,8 +200,8 @@ LocationContent::LocationContent(const QString& geoUri, const ImageInfo& thumbna LocationContent::LocationContent(const QJsonObject& json) : TypedBase(json) - , geoUri(json["geo_uri"].toString()) - , thumbnail(json["info"].toObject()) + , geoUri(json["geo_uri"_ls].toString()) + , thumbnail(json["info"_ls].toObject()) { } QMimeType LocationContent::type() const @@ -188,6 +212,6 @@ QMimeType LocationContent::type() const void LocationContent::fillJson(QJsonObject* o) const { Q_ASSERT(o); - o->insert("geo_uri", geoUri); - o->insert("info", toInfoJson(thumbnail)); + o->insert(QStringLiteral("geo_uri"), geoUri); + o->insert(QStringLiteral("info"), toInfoJson(thumbnail)); } diff --git a/lib/events/roommessageevent.h b/lib/events/roommessageevent.h index 075d7188..4c29a93e 100644 --- a/lib/events/roommessageevent.h +++ b/lib/events/roommessageevent.h @@ -18,8 +18,7 @@ #pragma once -#include "event.h" - +#include "roomevent.h" #include "eventcontent.h" namespace QMatrixClient @@ -37,6 +36,8 @@ namespace QMatrixClient Q_PROPERTY(QMimeType mimeType READ mimeType STORED false CONSTANT) Q_PROPERTY(EventContent::TypedBase* content READ content CONSTANT) public: + DEFINE_EVENT_TYPEID("m.room.message", RoomMessageEvent) + enum class MsgType { Text, Emote, Notice, Image, File, Location, Video, Audio, Unknown @@ -44,18 +45,15 @@ namespace QMatrixClient RoomMessageEvent(const QString& plainBody, const QString& jsonMsgType, - EventContent::TypedBase* content = nullptr) - : RoomEvent(Type::RoomMessage) - , _msgtype(jsonMsgType), _plainBody(plainBody), _content(content) - { } + EventContent::TypedBase* content = nullptr); explicit RoomMessageEvent(const QString& plainBody, MsgType msgType = MsgType::Text, EventContent::TypedBase* content = nullptr); explicit RoomMessageEvent(const QJsonObject& obj); MsgType msgtype() const; - QString rawMsgtype() const { return _msgtype; } - const QString& plainBody() const { return _plainBody; } + QString rawMsgtype() const; + QString plainBody() const; EventContent::TypedBase* content() const { return _content.data(); } QMimeType mimeType() const; @@ -63,17 +61,13 @@ namespace QMatrixClient bool hasFileContent() const; bool hasThumbnail() const; - QJsonObject toJson() const override; - - static constexpr const char* typeId() { return "m.room.message"; } - private: - QString _msgtype; - QString _plainBody; QScopedPointer<EventContent::TypedBase> _content; REGISTER_ENUM(MsgType) }; + REGISTER_EVENT_TYPE(RoomMessageEvent) + DEFINE_EVENTTYPE_ALIAS(RoomMessage, RoomMessageEvent) using MessageEventType = RoomMessageEvent::MsgType; namespace EventContent @@ -140,16 +134,16 @@ namespace QMatrixClient public: PlayableContent(const QJsonObject& json) : ContentT(json) - , duration(ContentT::originalInfoJson["duration"].toInt()) + , duration(ContentT::originalInfoJson["duration"_ls].toInt()) { } protected: void fillJson(QJsonObject* json) const override { ContentT::fillJson(json); - auto infoJson = json->take("info").toObject(); - infoJson.insert("duration", duration); - json->insert("info", infoJson); + auto infoJson = json->take("info"_ls).toObject(); + infoJson.insert(QStringLiteral("duration"), duration); + json->insert(QStringLiteral("info"), infoJson); } public: diff --git a/lib/events/simplestateevents.h b/lib/events/simplestateevents.h index d9f403e8..fa1ca8f4 100644 --- a/lib/events/simplestateevents.h +++ b/lib/events/simplestateevents.h @@ -18,36 +18,76 @@ #pragma once -#include "event.h" +#include "stateevent.h" #include "eventcontent.h" namespace QMatrixClient { -#define DEFINE_SIMPLE_STATE_EVENT(_Name, _TypeId, _EnumType, _ContentType, _ContentKey) \ - class _Name \ - : public StateEvent<EventContent::SimpleContent<_ContentType>> \ + namespace EventContent + { + template <typename T> + class SimpleContent: public Base + { + public: + using value_type = T; + + // The constructor is templated to enable perfect forwarding + template <typename TT> + SimpleContent(QString keyName, TT&& value) + : value(std::forward<TT>(value)), key(std::move(keyName)) + { } + SimpleContent(const QJsonObject& json, QString keyName) + : Base(json) + , value(QMatrixClient::fromJson<T>(json[keyName])) + , key(std::move(keyName)) + { } + + public: + T value; + + protected: + QString key; + + private: + void fillJson(QJsonObject* json) const override + { + Q_ASSERT(json); + json->insert(key, QMatrixClient::toJson(value)); + } + }; + } // namespace EventContent + +#define DEFINE_SIMPLE_STATE_EVENT(_Name, _TypeId, _ContentType, _ContentKey) \ + class _Name : public StateEvent<EventContent::SimpleContent<_ContentType>> \ { \ public: \ - static constexpr const char* typeId() { return _TypeId; } \ + using content_type = _ContentType; \ + DEFINE_EVENT_TYPEID(_TypeId, _Name) \ explicit _Name(const QJsonObject& obj) \ - : StateEvent(_EnumType, obj, QStringLiteral(#_ContentKey)) \ + : StateEvent(typeId(), obj, QStringLiteral(#_ContentKey)) \ { } \ template <typename T> \ explicit _Name(T&& value) \ - : StateEvent(_EnumType, QStringLiteral(#_ContentKey), \ + : StateEvent(typeId(), matrixTypeId(), \ + QStringLiteral(#_ContentKey), \ std::forward<T>(value)) \ { } \ - const _ContentType& _ContentKey() const { return content().value; } \ - }; + auto _ContentKey() const { return content().value; } \ + }; \ + REGISTER_EVENT_TYPE(_Name) \ + // End of macro - DEFINE_SIMPLE_STATE_EVENT(RoomNameEvent, "m.room.name", - Event::Type::RoomName, QString, name) + DEFINE_SIMPLE_STATE_EVENT(RoomNameEvent, "m.room.name", QString, name) + DEFINE_EVENTTYPE_ALIAS(RoomName, RoomNameEvent) DEFINE_SIMPLE_STATE_EVENT(RoomAliasesEvent, "m.room.aliases", - Event::Type::RoomAliases, QStringList, aliases) + QStringList, aliases) + DEFINE_EVENTTYPE_ALIAS(RoomAliases, RoomAliasesEvent) DEFINE_SIMPLE_STATE_EVENT(RoomCanonicalAliasEvent, "m.room.canonical_alias", - Event::Type::RoomCanonicalAlias, QString, alias) - DEFINE_SIMPLE_STATE_EVENT(RoomTopicEvent, "m.room.topic", - Event::Type::RoomTopic, QString, topic) + QString, alias) + DEFINE_EVENTTYPE_ALIAS(RoomCanonicalAlias, RoomCanonicalAliasEvent) + DEFINE_SIMPLE_STATE_EVENT(RoomTopicEvent, "m.room.topic", QString, topic) + DEFINE_EVENTTYPE_ALIAS(RoomTopic, RoomTopicEvent) DEFINE_SIMPLE_STATE_EVENT(EncryptionEvent, "m.room.encryption", - Event::Type::RoomEncryption, QString, algorithm) + QString, algorithm) + DEFINE_EVENTTYPE_ALIAS(RoomEncryption, EncryptionEvent) } // namespace QMatrixClient diff --git a/lib/events/stateevent.cpp b/lib/events/stateevent.cpp new file mode 100644 index 00000000..fd5d2642 --- /dev/null +++ b/lib/events/stateevent.cpp @@ -0,0 +1,30 @@ +/****************************************************************************** +* Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "stateevent.h" + +using namespace QMatrixClient; + +[[gnu::unused]] static auto stateEventTypeInitialised = + RoomEvent::factory_t::chainFactory<StateEventBase>(); + +bool StateEventBase::repeatsState() const +{ + const auto prevContentJson = unsignedJson().value(PrevContentKeyL); + return fullJson().value(ContentKeyL) == prevContentJson; +} diff --git a/lib/events/stateevent.h b/lib/events/stateevent.h new file mode 100644 index 00000000..6032132e --- /dev/null +++ b/lib/events/stateevent.h @@ -0,0 +1,92 @@ +/****************************************************************************** +* Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net> +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#include "roomevent.h" + +namespace QMatrixClient { + class StateEventBase: public RoomEvent + { + public: + using factory_t = EventFactory<StateEventBase>; + + using RoomEvent::RoomEvent; + ~StateEventBase() override = default; + + bool isStateEvent() const override { return true; } + virtual bool repeatsState() const; + }; + using StateEventPtr = event_ptr_tt<StateEventBase>; + using StateEvents = EventsArray<StateEventBase>; + + template <typename ContentT> + struct Prev + { + template <typename... ContentParamTs> + explicit Prev(const QJsonObject& unsignedJson, + ContentParamTs&&... contentParams) + : senderId(unsignedJson.value("prev_sender"_ls).toString()) + , content(unsignedJson.value(PrevContentKeyL).toObject(), + std::forward<ContentParamTs>(contentParams)...) + { } + + QString senderId; + ContentT content; + }; + + template <typename ContentT> + class StateEvent: public StateEventBase + { + public: + using content_type = ContentT; + + template <typename... ContentParamTs> + explicit StateEvent(Type type, const QJsonObject& fullJson, + ContentParamTs&&... contentParams) + : StateEventBase(type, fullJson) + , _content(contentJson(), + std::forward<ContentParamTs>(contentParams)...) + { + const auto& unsignedData = unsignedJson(); + if (unsignedData.contains(PrevContentKeyL)) + _prev = std::make_unique<Prev<ContentT>>(unsignedData, + std::forward<ContentParamTs>(contentParams)...); + } + template <typename... ContentParamTs> + explicit StateEvent(Type type, event_mtype_t matrixType, + ContentParamTs&&... contentParams) + : StateEventBase(type, matrixType) + , _content(std::forward<ContentParamTs>(contentParams)...) + { + editJson().insert(ContentKey, _content.toJson()); + } + + const ContentT& content() const { return _content; } + [[deprecated("Use prevContent instead")]] + const ContentT* prev_content() const { return prevContent(); } + const ContentT* prevContent() const + { return _prev ? &_prev->content : nullptr; } + QString prevSenderId() const + { return _prev ? _prev->senderId : QString(); } + + protected: + ContentT _content; + std::unique_ptr<Prev<ContentT>> _prev; + }; +} // namespace QMatrixClient diff --git a/lib/events/typingevent.cpp b/lib/events/typingevent.cpp index a4d3bae4..0d39d1be 100644 --- a/lib/events/typingevent.cpp +++ b/lib/events/typingevent.cpp @@ -18,15 +18,15 @@ #include "typingevent.h" +#include <QtCore/QJsonArray> + using namespace QMatrixClient; TypingEvent::TypingEvent(const QJsonObject& obj) - : Event(Type::Typing, obj) + : Event(typeId(), obj) { - QJsonValue result; - result= contentJson()["user_ids"]; - QJsonArray array = result.toArray(); - for( const QJsonValue& user: array ) + const auto& array = contentJson()["user_ids"_ls].toArray(); + for(const auto& user: array ) _users.push_back(user.toString()); } diff --git a/lib/events/typingevent.h b/lib/events/typingevent.h index 6ccbc1c8..27b668b4 100644 --- a/lib/events/typingevent.h +++ b/lib/events/typingevent.h @@ -20,20 +20,20 @@ #include "event.h" -#include <QtCore/QStringList> - namespace QMatrixClient { class TypingEvent: public Event { public: - static constexpr const char* typeId() { return "m.typing"; } + DEFINE_EVENT_TYPEID("m.typing", TypingEvent) TypingEvent(const QJsonObject& obj); - QStringList users() const { return _users; } + const QStringList& users() const { return _users; } private: QStringList _users; }; + REGISTER_EVENT_TYPE(TypingEvent) + DEFINE_EVENTTYPE_ALIAS(Typing, TypingEvent) } // namespace QMatrixClient diff --git a/lib/jobs/basejob.cpp b/lib/jobs/basejob.cpp index 607a6c04..f9628c19 100644 --- a/lib/jobs/basejob.cpp +++ b/lib/jobs/basejob.cpp @@ -19,6 +19,7 @@ #include "basejob.h" #include "connectiondata.h" +#include "util.h" #include <QtNetwork/QNetworkAccessManager> #include <QtNetwork/QNetworkRequest> @@ -196,7 +197,7 @@ void BaseJob::Private::sendRequest(bool inBackground) { makeRequestUrl(connection->baseUrl(), apiEndpoint, requestQuery) }; if (!requestHeaders.contains("Content-Type")) req.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - req.setRawHeader(QByteArray("Authorization"), + req.setRawHeader("Authorization", QByteArray("Bearer ") + connection->accessToken()); req.setAttribute(QNetworkRequest::BackgroundRequestAttribute, inBackground); #if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) @@ -292,11 +293,12 @@ void BaseJob::gotReply() if (jsonBody) { auto json = QJsonDocument::fromJson(d->rawResponse).object(); + const auto errCode = json.value("errcode"_ls).toString(); if (error() == TooManyRequestsError || - json.value("errcode").toString() == "M_LIMIT_EXCEEDED") + errCode == "M_LIMIT_EXCEEDED") { QString msg = tr("Too many requests"); - auto retryInterval = json.value("retry_after_ms").toInt(-1); + auto retryInterval = json.value("retry_after_ms"_ls).toInt(-1); if (retryInterval != -1) msg += tr(", next retry advised after %1 ms") .arg(retryInterval); @@ -313,13 +315,14 @@ void BaseJob::gotReply() emit retryScheduled(d->retriesTaken, retryInterval); return; } - if (json.value("errcode").toString() == "M_CONSENT_NOT_GIVEN") + if (errCode == "M_CONSENT_NOT_GIVEN") { d->status.code = UserConsentRequiredError; - d->errorUrl = json.value("consent_uri").toString(); + d->errorUrl = json.value("consent_uri"_ls).toString(); } - else if (!json.isEmpty()) // FIXME: The below is not localisable - setStatus(IncorrectRequestError, json.value("error").toString()); + else if (!json.isEmpty()) // Not localisable on the client side + setStatus(IncorrectRequestError, + json.value("error"_ls).toString()); } } @@ -366,7 +369,8 @@ BaseJob::Status BaseJob::doCheckReply(QNetworkReply* reply) const return { NetworkError, reply->errorString() }; } - const QString replyState = reply->isRunning() ? "(tentative)" : "(final)"; + const QString replyState = reply->isRunning() ? + QStringLiteral("(tentative)") : QStringLiteral("(final)"); const auto urlString = '|' + d->reply->url().toDisplayString(); const auto httpCode = httpCodeHeader.toInt(); const auto reason = @@ -375,12 +379,11 @@ BaseJob::Status BaseJob::doCheckReply(QNetworkReply* reply) const { qCDebug(d->logCat).noquote().nospace() << this << urlString; qCDebug(d->logCat).noquote() << " " << httpCode << reason << replyState; - if (checkContentType(reply->rawHeader("Content-Type"), + if (!checkContentType(reply->rawHeader("Content-Type"), d->expectedContentTypes)) - return NoError; - else // A warning in the logs might be more proper instead return { UnexpectedResponseTypeWarning, "Unexpected content type of the response" }; + return NoError; } qCWarning(d->logCat).noquote().nospace() << this << urlString; diff --git a/lib/jobs/sendeventjob.cpp b/lib/jobs/sendeventjob.cpp index f5190d4b..e5852c65 100644 --- a/lib/jobs/sendeventjob.cpp +++ b/lib/jobs/sendeventjob.cpp @@ -35,7 +35,7 @@ void SendEventJob::beforeStart(const ConnectionData* connData) BaseJob::Status SendEventJob::parseJson(const QJsonDocument& data) { - _eventId = data.object().value("event_id").toString(); + _eventId = data.object().value("event_id"_ls).toString(); if (!_eventId.isEmpty()) return Success; diff --git a/lib/jobs/sendeventjob.h b/lib/jobs/sendeventjob.h index a3e9a291..af81ae26 100644 --- a/lib/jobs/sendeventjob.h +++ b/lib/jobs/sendeventjob.h @@ -32,9 +32,9 @@ namespace QMatrixClient SendEventJob(const QString& roomId, const EvT& event) : BaseJob(HttpVerb::Put, QStringLiteral("SendEventJob"), QStringLiteral("_matrix/client/r0/rooms/%1/send/%2/") - .arg(roomId, EvT::typeId()), // See also beforeStart() + .arg(roomId, EvT::matrixTypeId()), // See also beforeStart() Query(), - Data(event.toJson())) + Data(event.contentJson())) { } /** diff --git a/lib/jobs/syncjob.cpp b/lib/jobs/syncjob.cpp index cbdc37b4..02690e6d 100644 --- a/lib/jobs/syncjob.cpp +++ b/lib/jobs/syncjob.cpp @@ -18,6 +18,8 @@ #include "syncjob.h" +#include "events/eventloader.h" + #include <QtCore/QElapsedTimer> using namespace QMatrixClient; @@ -32,13 +34,13 @@ SyncJob::SyncJob(const QString& since, const QString& filter, int timeout, setLoggingCategory(SYNCJOB); QUrlQuery query; if( !filter.isEmpty() ) - query.addQueryItem("filter", filter); + query.addQueryItem(QStringLiteral("filter"), filter); if( !presence.isEmpty() ) - query.addQueryItem("set_presence", presence); + query.addQueryItem(QStringLiteral("set_presence"), presence); if( timeout >= 0 ) - query.addQueryItem("timeout", QString::number(timeout)); + query.addQueryItem(QStringLiteral("timeout"), QString::number(timeout)); if( !since.isEmpty() ) - query.addQueryItem("since", since); + query.addQueryItem(QStringLiteral("since"), since); setRequestQuery(query); setMaxRetries(std::numeric_limits<int>::max()); @@ -72,7 +74,7 @@ Events&&SyncData::takeToDeviceEvents() template <typename EventsArrayT, typename StrT> inline EventsArrayT load(const QJsonObject& batches, StrT keyName) { - return fromJson<EventsArrayT>(batches[keyName].toObject().value("events")); + return fromJson<EventsArrayT>(batches[keyName].toObject().value("events"_ls)); } BaseJob::Status SyncJob::parseJson(const QJsonDocument& data) @@ -85,12 +87,12 @@ BaseJob::Status SyncData::parseJson(const QJsonDocument &data) QElapsedTimer et; et.start(); auto json = data.object(); - nextBatch_ = json.value("next_batch").toString(); - presenceData = load<Events>(json, "presence"); - accountData = load<Events>(json, "account_data"); - toDeviceEvents = load<Events>(json, "to_device"); + nextBatch_ = json.value("next_batch"_ls).toString(); + presenceData = load<Events>(json, "presence"_ls); + accountData = load<Events>(json, "account_data"_ls); + toDeviceEvents = load<Events>(json, "to_device"_ls); - QJsonObject rooms = json.value("rooms").toObject(); + auto rooms = json.value("rooms"_ls).toObject(); JoinStates::Int ii = 1; // ii is used to make a JoinState value auto totalRooms = 0; auto totalEvents = 0; @@ -123,30 +125,31 @@ SyncRoomData::SyncRoomData(const QString& roomId_, JoinState joinState_, : roomId(roomId_) , joinState(joinState_) , state(load<StateEvents>(room_, - joinState == JoinState::Invite ? "invite_state" : "state")) + joinState == JoinState::Invite ? "invite_state"_ls : "state"_ls)) { switch (joinState) { case JoinState::Join: - ephemeral = load<Events>(room_, "ephemeral"); - accountData = load<Events>(room_, "account_data"); + ephemeral = load<Events>(room_, "ephemeral"_ls); + accountData = load<Events>(room_, "account_data"_ls); FALLTHROUGH; case JoinState::Leave: { - timeline = load<RoomEvents>(room_, "timeline"); - auto timelineJson = room_.value("timeline").toObject(); - timelineLimited = timelineJson.value("limited").toBool(); - timelinePrevBatch = timelineJson.value("prev_batch").toString(); + timeline = load<RoomEvents>(room_, "timeline"_ls); + const auto timelineJson = room_.value("timeline"_ls).toObject(); + timelineLimited = timelineJson.value("limited"_ls).toBool(); + timelinePrevBatch = timelineJson.value("prev_batch"_ls).toString(); break; } default: /* nothing on top of state */; } - auto unreadJson = room_.value("unread_notifications").toObject(); + const auto unreadJson = room_.value("unread_notifications"_ls).toObject(); unreadCount = unreadJson.value(UnreadCountKey).toInt(-2); - highlightCount = unreadJson.value("highlight_count").toInt(); - notificationCount = unreadJson.value("notification_count").toInt(); + highlightCount = unreadJson.value("highlight_count"_ls).toInt(); + notificationCount = unreadJson.value("notification_count"_ls).toInt(); if (highlightCount > 0 || notificationCount > 0) - qCDebug(SYNCJOB) << "Highlights: " << highlightCount - << " Notifications:" << notificationCount; + qCDebug(SYNCJOB) << "Room" << roomId_ + << "has highlights:" << highlightCount + << "and notifications:" << notificationCount; } diff --git a/lib/jobs/syncjob.h b/lib/jobs/syncjob.h index ca30848e..6b9bedfa 100644 --- a/lib/jobs/syncjob.h +++ b/lib/jobs/syncjob.h @@ -21,7 +21,7 @@ #include "basejob.h" #include "joinstate.h" -#include "events/event.h" +#include "events/stateevent.h" #include "util.h" namespace QMatrixClient diff --git a/lib/room.cpp b/lib/room.cpp index 8e1eb8e8..080ad30d 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -110,7 +110,7 @@ class Room::Private QHash<const User*, QString> lastReadEventIds; QString serverReadMarker; TagsMap tags; - QHash<QString, AccountDataMap> accountData; + std::unordered_map<QString, EventPtr> accountData; QString prevBatch; QPointer<GetRoomEventsJob> eventsHistoryJob; @@ -168,7 +168,7 @@ class Room::Private { return !ti->isRedacted() && ti->senderId() != connection->userId() && - ti->type() == EventType::RoomMessage; + is<RoomMessageEvent>(*ti); } void addNewMessageEvents(RoomEvents&& events); @@ -203,14 +203,14 @@ class Room::Private auto requestSetState(const QString& stateKey, const EvT& event) { return connection->callApi<SetRoomStateWithKeyJob>( - id, EvT::typeId(), stateKey, event.toJson()); + id, EvT::matrixTypeId(), stateKey, event.contentJson()); } template <typename EvT> auto requestSetState(const EvT& event) { return connection->callApi<SetRoomStateJob>( - id, EvT::typeId(), event.toJson()); + id, EvT::matrixTypeId(), event.contentJson()); } /** @@ -224,8 +224,8 @@ class Room::Private void broadcastTagUpdates() { connection->callApi<SetAccountDataPerRoomJob>( - connection->userId(), id, TagEvent::typeId(), - TagEvent(tags).toJson()); + connection->userId(), id, TagEvent::matrixTypeId(), + TagEvent(tags).fullJson()); emit q->tagsChanged(); } @@ -650,12 +650,14 @@ void Room::resetHighlightCount() bool Room::hasAccountData(const QString& type) const { - return d->accountData.contains(type); + return d->accountData.find(type) != d->accountData.end(); } -Room::AccountDataMap Room::accountData(const QString& type) const +const EventPtr& Room::accountData(const QString& type) const { - return d->accountData.value(type); + static EventPtr NoEventPtr {}; + const auto it = d->accountData.find(type); + return it != d->accountData.end() ? it->second : NoEventPtr; } QStringList Room::tagNames() const @@ -723,8 +725,7 @@ const RoomMessageEvent* Room::Private::getEventWithFile(const QString& eventId) const { auto evtIt = q->findInTimeline(eventId); - if (evtIt != timeline.rend() && - evtIt->event()->type() == EventType::RoomMessage) + if (evtIt != timeline.rend() && is<RoomMessageEvent>(**evtIt)) { auto* event = evtIt->viewAs<RoomMessageEvent>(); if (event->hasFileContent()) @@ -1274,7 +1275,7 @@ void Room::Private::dropDuplicateEvents(RoomEvents& events) const inline bool isRedaction(const RoomEventPtr& e) { - return e->type() == EventType::Redaction; + return e && is<RedactionEvent>(*e); } void Room::Private::processRedaction(event_ptr_tt<RedactionEvent>&& redaction) @@ -1292,26 +1293,30 @@ void Room::Private::processRedaction(event_ptr_tt<RedactionEvent>&& redaction) // Apply the redaction procedure from chapter 6.5 of The Spec auto originalJson = ti->originalJsonObject(); - if (originalJson.value("unsigned").toObject() - .value("redacted_because").toObject() - .value("event_id") == redaction->id()) + if (originalJson.value(UnsignedKeyL).toObject() + .value(RedactedCauseKeyL).toObject() + .value(EventIdKeyL) == redaction->id()) { qCDebug(MAIN) << "Redaction" << redaction->id() << "of event" << ti.event()->id() << "already done, skipping"; return; } static const QStringList keepKeys = - { "event_id", "type", "room_id", "sender", "state_key", - "prev_content", "content", "origin_server_ts" }; - static const - std::vector<std::pair<EventType, QStringList>> keepContentKeysMap - { { Event::Type::RoomMember, { "membership" } } - , { Event::Type::RoomCreate, { "creator" } } - , { Event::Type::RoomJoinRules, { "join_rule" } } - , { Event::Type::RoomPowerLevels, - { "ban", "events", "events_default", "kick", "redact", - "state_default", "users", "users_default" } } - , { Event::Type::RoomAliases, { "alias" } } + { EventIdKey, TypeKey, QStringLiteral("room_id"), + QStringLiteral("sender"), QStringLiteral("state_key"), + QStringLiteral("prev_content"), ContentKey, + QStringLiteral("origin_server_ts") }; + + std::vector<std::pair<Event::Type, QStringList>> keepContentKeysMap + { { RoomMemberEvent::typeId(), { QStringLiteral("membership") } } +// , { RoomCreateEvent::typeId(), { QStringLiteral("creator") } } +// , { RoomJoinRules::typeId(), { QStringLiteral("join_rule") } } +// , { RoomPowerLevels::typeId(), +// { QStringLiteral("ban"), QStringLiteral("events"), +// QStringLiteral("events_default"), QStringLiteral("kick"), +// QStringLiteral("redact"), QStringLiteral("state_default"), +// QStringLiteral("users"), QStringLiteral("users_default") } } + , { RoomAliasesEvent::typeId(), { QStringLiteral("alias") } } }; for (auto it = originalJson.begin(); it != originalJson.end();) { @@ -1325,10 +1330,10 @@ void Room::Private::processRedaction(event_ptr_tt<RedactionEvent>&& redaction) [&ti](const auto& t) { return ti->type() == t.first; } ); if (keepContentKeys == keepContentKeysMap.end()) { - originalJson.remove("content"); - originalJson.remove("prev_content"); + originalJson.remove(ContentKeyL); + originalJson.remove(PrevContentKeyL); } else { - auto content = originalJson.take("content").toObject(); + auto content = originalJson.take(ContentKeyL).toObject(); for (auto it = content.begin(); it != content.end(); ) { if (!keepContentKeys->second.contains(it.key())) @@ -1336,16 +1341,15 @@ void Room::Private::processRedaction(event_ptr_tt<RedactionEvent>&& redaction) else ++it; } - originalJson.insert("content", content); + originalJson.insert(ContentKey, content); } - auto unsignedData = originalJson.take("unsigned").toObject(); - unsignedData["redacted_because"] = redaction->originalJsonObject(); - originalJson.insert("unsigned", unsignedData); + auto unsignedData = originalJson.take(UnsignedKeyL).toObject(); + unsignedData[RedactedCauseKeyL] = redaction->originalJsonObject(); + originalJson.insert(QStringLiteral("unsigned"), unsignedData); // Make a new event from the redacted JSON, exchange events, // notify everyone and delete the old event - RoomEventPtr oldEvent - { ti.replaceEvent(makeEvent<RoomEvent>(originalJson)) }; + auto oldEvent = ti.replaceEvent(loadEvent<RoomEvent>(originalJson)); q->onRedaction(*oldEvent, *ti.event()); qCDebug(MAIN) << "Redacted" << oldEvent->id() << "with" << redaction->id(); emit q->replacedEvent(ti.event(), rawPtr(oldEvent)); @@ -1442,52 +1446,48 @@ void Room::Private::addHistoricalMessageEvents(RoomEvents&& events) bool Room::processStateEvent(const RoomEvent& e) { - switch (e.type()) - { - case EventType::RoomName: { - d->name = static_cast<const RoomNameEvent&>(e).name(); + return visit(e + , [this] (const RoomNameEvent& evt) { + d->name = evt.name(); qCDebug(MAIN) << "Room name updated:" << d->name; return true; } - case EventType::RoomAliases: { - d->aliases = static_cast<const RoomAliasesEvent&>(e).aliases(); + , [this] (const RoomAliasesEvent& evt) { + d->aliases = evt.aliases(); qCDebug(MAIN) << "Room aliases updated:" << d->aliases; return true; } - case EventType::RoomCanonicalAlias: { - d->canonicalAlias = - static_cast<const RoomCanonicalAliasEvent&>(e).alias(); + , [this] (const RoomCanonicalAliasEvent& evt) { + d->canonicalAlias = evt.alias(); setObjectName(d->canonicalAlias); - qCDebug(MAIN) << "Room canonical alias updated:" << d->canonicalAlias; + qCDebug(MAIN) << "Room canonical alias updated:" + << d->canonicalAlias; return true; } - case EventType::RoomTopic: { - d->topic = static_cast<const RoomTopicEvent&>(e).topic(); + , [this] (const RoomTopicEvent& evt) { + d->topic = evt.topic(); qCDebug(MAIN) << "Room topic updated:" << d->topic; emit topicChanged(); return false; } - case EventType::RoomAvatar: { - const auto& avatarEventContent = - static_cast<const RoomAvatarEvent&>(e).content(); - if (d->avatar.updateUrl(avatarEventContent.url)) + , [this] (const RoomAvatarEvent& evt) { + if (d->avatar.updateUrl(evt.url())) { qCDebug(MAIN) << "Room avatar URL updated:" - << avatarEventContent.url.toString(); + << evt.url().toString(); emit avatarChanged(); } return false; } - case EventType::RoomMember: { - const auto& memberEvent = static_cast<const RoomMemberEvent&>(e); - auto* u = user(memberEvent.userId()); - u->processEvent(memberEvent, this); + , [this] (const RoomMemberEvent& evt) { + auto* u = user(evt.userId()); + u->processEvent(evt, this); if (u == localUser() && memberJoinState(u) == JoinState::Invite - && memberEvent.isDirect()) + && evt.isDirect()) connection()->addToDirectChats(this, - user(memberEvent.senderId())); + user(evt.senderId())); - if( memberEvent.membership() == MembershipType::Join ) + if( evt.membership() == MembershipType::Join ) { if (memberJoinState(u) != JoinState::Join) { @@ -1505,7 +1505,7 @@ bool Room::processStateEvent(const RoomEvent& e) emit userAdded(u); } } - else if( memberEvent.membership() == MembershipType::Leave ) + else if( evt.membership() == MembershipType::Leave ) { if (memberJoinState(u) == JoinState::Join) { @@ -1517,52 +1517,43 @@ bool Room::processStateEvent(const RoomEvent& e) } return false; } - case EventType::RoomEncryption: - { - d->encryptionAlgorithm = - static_cast<const EncryptionEvent&>(e).algorithm(); - qCDebug(MAIN) << "Encryption switched on in" << displayName(); + , [this] (const EncryptionEvent& evt) { + d->encryptionAlgorithm = evt.algorithm(); + qCDebug(MAIN) << "Encryption switched on in room" << id() + << "with algorithm" << d->encryptionAlgorithm; emit encryption(); return false; } - default: - /* Ignore events of other types */ - return false; - } + ); } void Room::processEphemeralEvent(EventPtr&& event) { QElapsedTimer et; et.start(); - switch (event->type()) - { - case EventType::Typing: { - auto typingEvent = ptrCast<TypingEvent>(move(event)); + visit(event + , [this,et] (const TypingEvent& evt) { d->usersTyping.clear(); - for( const QString& userId: typingEvent->users() ) + for( const QString& userId: qAsConst(evt.users()) ) { auto u = user(userId); if (memberJoinState(u) == JoinState::Join) d->usersTyping.append(u); } - if (!typingEvent->users().isEmpty()) + if (!evt.users().isEmpty()) qCDebug(PROFILER) << "*** Room::processEphemeralEvent(typing):" - << typingEvent->users().size() << "users," << et; + << evt.users().size() << "users," << et; emit typingChanged(); - break; } - case EventType::Receipt: { - auto receiptEvent = ptrCast<ReceiptEvent>(move(event)); - for( const auto &p: receiptEvent->eventsWithReceipts() ) + , [this,et] (const ReceiptEvent& evt) { + for( const auto &p: qAsConst(evt.eventsWithReceipts()) ) { { if (p.receipts.size() == 1) qCDebug(EPHEMERAL) << "Marking" << p.evtId - << "as read for" << p.receipts[0].userId; + << "as read for" << p.receipts[0].userId; else qCDebug(EPHEMERAL) << "Marking" << p.evtId - << "as read for" - << p.receipts.size() << "users"; + << "as read for" << p.receipts.size() << "users"; } const auto newMarker = findInTimeline(p.evtId); if (newMarker != timelineEdge()) @@ -1578,7 +1569,7 @@ void Room::processEphemeralEvent(EventPtr&& event) } else { qCDebug(EPHEMERAL) << "Event" << p.evtId - << "not found; saving read receipts anyway"; + << "not found; saving read receipts anyway"; // If the event is not found (most likely, because it's too old // and hasn't been fetched from the server yet), but there is // a previous marker for a user, keep the previous marker. @@ -1594,37 +1585,28 @@ void Room::processEphemeralEvent(EventPtr&& event) } } } - if (!receiptEvent->eventsWithReceipts().isEmpty()) + if (!evt.eventsWithReceipts().isEmpty()) qCDebug(PROFILER) << "*** Room::processEphemeralEvent(receipts):" - << receiptEvent->eventsWithReceipts().size() + << evt.eventsWithReceipts().size() << "events with receipts," << et; - break; } - default: - qCWarning(EPHEMERAL) << "Unexpected event type in 'ephemeral' batch:" - << event->jsonType(); - } + ); } void Room::processAccountDataEvent(EventPtr&& event) { - switch (event->type()) - { - case EventType::Tag: - { - auto newTags = ptrCast<const TagEvent>(move(event))->tags(); + visit(event + , [this] (const TagEvent& evt) { + auto newTags = evt.tags(); if (newTags == d->tags) - break; + return; d->tags = newTags; qCDebug(MAIN) << "Room" << id() << "is tagged with:" << tagNames().join(", "); emit tagsChanged(); - break; } - case EventType::ReadMarker: - { - auto readEventId = - ptrCast<const ReadMarkerEvent>(move(event))->event_id(); + , [this] (const ReadMarkerEvent& evt) { + auto readEventId = evt.event_id(); qCDebug(MAIN) << "Server-side read marker at" << readEventId; d->serverReadMarker = readEventId; const auto newMarker = findInTimeline(readEventId); @@ -1632,12 +1614,18 @@ void Room::processAccountDataEvent(EventPtr&& event) d->markMessagesAsRead(newMarker); else d->setLastReadEvent(localUser(), readEventId); - break; } - default: - d->accountData[event->jsonType()] = - fromJson<AccountDataMap>(event->contentJson()); - emit accountDataChanged(event->jsonType()); + ); + // For all account data events + auto& currentData = d->accountData[event->matrixType()]; + // A polymorphic event-specific comparison might be a bit more + // efficient; maaybe do it another day + if (!currentData || currentData->contentJson() != event->contentJson()) + { + currentData = std::move(event); + qCDebug(MAIN) << "Updated account data of type" + << currentData->matrixType(); + emit accountDataChanged(currentData->matrixType()); } } @@ -1674,8 +1662,8 @@ QString Room::Private::roomNameFromMemberNames(const QList<User *> &userlist) co // ii. Two users besides the current one. if (userlist.size() == 3) return tr("%1 and %2") - .arg(q->roomMembername(first_two[0])) - .arg(q->roomMembername(first_two[1])); + .arg(q->roomMembername(first_two[0]), + q->roomMembername(first_two[1])); // iii. More users. if (userlist.size() > 3) @@ -1731,11 +1719,11 @@ void appendStateEvent(QJsonArray& events, const QString& type, const QJsonObject& content, const QString& stateKey = {}) { if (!content.isEmpty() || !stateKey.isEmpty()) - events.append(QJsonObject - { { QStringLiteral("type"), type } - , { QStringLiteral("content"), content } - , { QStringLiteral("state_key"), stateKey } - }); + { + auto json = basicEventJson(type, content); + json.insert(QStringLiteral("state_key"), stateKey); + events.append(json); + } } #define ADD_STATE_EVENT(events, type, name, content) \ @@ -1746,16 +1734,13 @@ void appendEvent(QJsonArray& events, const QString& type, const QJsonObject& content) { if (!content.isEmpty()) - events.append(QJsonObject - { { QStringLiteral("type"), type } - , { QStringLiteral("content"), content } - }); + events.append(basicEventJson(type, content)); } template <typename EvtT> void appendEvent(QJsonArray& events, const EvtT& event) { - appendEvent(events, EvtT::typeId(), event.toJson()); + appendEvent(events, EvtT::matrixTypeId(), event.toJson()); } QJsonObject Room::Private::toJson() const @@ -1790,29 +1775,23 @@ QJsonObject Room::Private::toJson() const } QJsonArray accountDataEvents; - if (!tags.empty()) - appendEvent(accountDataEvents, TagEvent(tags)); - - if (!serverReadMarker.isEmpty()) - appendEvent(accountDataEvents, ReadMarkerEvent(serverReadMarker)); - if (!accountData.empty()) { - for (auto it = accountData.begin(); it != accountData.end(); ++it) - appendEvent(accountDataEvents, it.key(), - QMatrixClient::toJson(it.value())); + for (const auto& e: accountData) + appendEvent(accountDataEvents, e.first, e.second->contentJson()); } - result.insert("account_data", QJsonObject {{ "events", accountDataEvents }}); + result.insert(QStringLiteral("account_data"), + QJsonObject {{ QStringLiteral("events"), accountDataEvents }}); - QJsonObject unreadNotificationsObj; + QJsonObject unreadNotifObj + { { SyncRoomData::UnreadCountKey, unreadMessages } }; - unreadNotificationsObj.insert(SyncRoomData::UnreadCountKey, unreadMessages); if (highlightCount > 0) - unreadNotificationsObj.insert("highlight_count", highlightCount); + unreadNotifObj.insert(QStringLiteral("highlight_count"), highlightCount); if (notificationCount > 0) - unreadNotificationsObj.insert("notification_count", notificationCount); + unreadNotifObj.insert(QStringLiteral("notification_count"), notificationCount); - result.insert("unread_notifications", unreadNotificationsObj); + result.insert(QStringLiteral("unread_notifications"), unreadNotifObj); if (et.elapsed() > 50) qCDebug(PROFILER) << "Room::toJson() for" << displayname << "took" << et; @@ -48,12 +48,16 @@ namespace QMatrixClient using index_t = int; TimelineItem(RoomEventPtr&& e, index_t number) - : evt(std::move(e)), idx(number) { } + : evt(std::move(e)), idx(number) + { + Q_ASSERT(evt); + } const RoomEvent* event() const { return rawPtr(evt); } template <typename EventT> const EventT* viewAs() const { return weakPtrCast<const EventT>(evt); } const RoomEventPtr& operator->() const { return evt; } + const RoomEvent& operator*() const { return *evt; } index_t index() const { return idx; } // Used for event redaction @@ -129,10 +133,6 @@ namespace QMatrixClient using rev_iter_t = Timeline::const_reverse_iterator; using timeline_iter_t = Timeline::const_iterator; - using AccountDataMap = std::conditional_t< - QT_VERSION >= QT_VERSION_CHECK(5, 5, 0), - QVariantHash, QVariantMap>; - Room(Connection* connection, QString id, JoinState initialJoinState); ~Room() override; @@ -279,7 +279,7 @@ namespace QMatrixClient * stored on the server. Tags and read markers cannot be retrieved * using this method _yet_. */ - AccountDataMap accountData(const QString& type) const; + const EventPtr& accountData(const QString& type) const; QStringList tagNames() const; TagsMap tags() const; @@ -106,10 +106,18 @@ namespace QMatrixClient void processEvent(const RoomMemberEvent& event, const Room* r); public 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 */ void rename(const QString& newName, const Room* r); + /** Upload the file and use it as an avatar */ bool setAvatar(const QString& fileName); + /** Upload contents of the QIODevice and set that as an avatar */ bool setAvatar(QIODevice* source); + /** Create or find a direct chat with this user + * The resulting chat is returned asynchronously via + * Connection::directChatAvailable() + */ void requestDirectChat(); signals: @@ -59,6 +59,42 @@ namespace QMatrixClient return std::unique_ptr<T1>(static_cast<T1*>(p.release())); } + /** Determine traits of an arbitrary function/lambda/functor + * This only works with arity of 1 (1-argument) for now but is extendable + * to other cases. Also, doesn't work with generic lambdas and function + * objects that have operator() overloaded + * \sa https://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda#7943765 + */ + template <typename T> + struct function_traits : public function_traits<decltype(&T::operator())> + { }; // A generic function object that has (non-overloaded) operator() + + // Specialisation for a function + template <typename ReturnT, typename ArgT> + struct function_traits<ReturnT(ArgT)> + { + using return_type = ReturnT; + using arg_type = ArgT; + }; + + // Specialisation for a member function + template <typename ReturnT, typename ClassT, typename ArgT> + struct function_traits<ReturnT(ClassT::*)(ArgT)> + : function_traits<ReturnT(ArgT)> + { }; + + // Specialisation for a const member function + template <typename ReturnT, typename ClassT, typename ArgT> + struct function_traits<ReturnT(ClassT::*)(ArgT) const> + : function_traits<ReturnT(ArgT)> + { }; + + template <typename FnT> + using fn_return_t = typename function_traits<FnT>::return_type; + + template <typename FnT> + using fn_arg_t = typename function_traits<FnT>::arg_type; + #if QT_VERSION < QT_VERSION_CHECK(5, 7, 0) // Copy-pasted from Qt 5.10 template <typename T> @@ -68,6 +104,11 @@ namespace QMatrixClient static void qAsConst(const T &&) Q_DECL_EQ_DELETE; #endif + inline auto operator"" _ls(const char* s, std::size_t size) + { + return QLatin1String(s, int(size)); + } + /** An abstraction over a pair of iterators * This is a very basic range type over a container with iterators that * are at least ForwardIterators. Inspired by Ranges TS. |