aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/qmc-example.cpp126
-rw-r--r--lib/application-service/definitions/location.cpp20
-rw-r--r--lib/application-service/definitions/location.h8
-rw-r--r--lib/application-service/definitions/protocol.cpp66
-rw-r--r--lib/application-service/definitions/protocol.h24
-rw-r--r--lib/application-service/definitions/user.cpp20
-rw-r--r--lib/application-service/definitions/user.h8
-rw-r--r--lib/connection.cpp30
-rw-r--r--lib/connection.h7
-rw-r--r--lib/converters.cpp38
-rw-r--r--lib/converters.h293
-rw-r--r--lib/csapi/admin.cpp40
-rw-r--r--lib/csapi/administrative_contact.cpp42
-rw-r--r--lib/csapi/administrative_contact.h2
-rw-r--r--lib/csapi/content-repo.cpp8
-rw-r--r--lib/csapi/create_room.cpp34
-rw-r--r--lib/csapi/create_room.h2
-rw-r--r--lib/csapi/definitions/auth_data.cpp19
-rw-r--r--lib/csapi/definitions/auth_data.h8
-rw-r--r--lib/csapi/definitions/client_device.cpp23
-rw-r--r--lib/csapi/definitions/client_device.h8
-rw-r--r--lib/csapi/definitions/device_keys.cpp26
-rw-r--r--lib/csapi/definitions/device_keys.h8
-rw-r--r--lib/csapi/definitions/event_filter.cpp26
-rw-r--r--lib/csapi/definitions/event_filter.h8
-rw-r--r--lib/csapi/definitions/public_rooms_response.cpp61
-rw-r--r--lib/csapi/definitions/public_rooms_response.h16
-rw-r--r--lib/csapi/definitions/push_condition.cpp23
-rw-r--r--lib/csapi/definitions/push_condition.h8
-rw-r--r--lib/csapi/definitions/push_rule.cpp29
-rw-r--r--lib/csapi/definitions/push_rule.h12
-rw-r--r--lib/csapi/definitions/push_ruleset.cpp26
-rw-r--r--lib/csapi/definitions/push_ruleset.h8
-rw-r--r--lib/csapi/definitions/room_event_filter.cpp28
-rw-r--r--lib/csapi/definitions/room_event_filter.h16
-rw-r--r--lib/csapi/definitions/sync_filter.cpp74
-rw-r--r--lib/csapi/definitions/sync_filter.h51
-rw-r--r--lib/csapi/definitions/user_identifier.cpp16
-rw-r--r--lib/csapi/definitions/user_identifier.h8
-rw-r--r--lib/csapi/definitions/wellknown/homeserver.cpp14
-rw-r--r--lib/csapi/definitions/wellknown/homeserver.h8
-rw-r--r--lib/csapi/definitions/wellknown/identity_server.cpp14
-rw-r--r--lib/csapi/definitions/wellknown/identity_server.h8
-rw-r--r--lib/csapi/device_management.cpp4
-rw-r--r--lib/csapi/directory.cpp4
-rw-r--r--lib/csapi/event_context.cpp12
-rw-r--r--lib/csapi/filter.cpp4
-rw-r--r--lib/csapi/gtad.yaml11
-rw-r--r--lib/csapi/joining.cpp51
-rw-r--r--lib/csapi/joining.h4
-rw-r--r--lib/csapi/keys.cpp35
-rw-r--r--lib/csapi/list_joined_rooms.cpp2
-rw-r--r--lib/csapi/list_public_rooms.cpp19
-rw-r--r--lib/csapi/list_public_rooms.h2
-rw-r--r--lib/csapi/login.cpp20
-rw-r--r--lib/csapi/message_pagination.cpp6
-rw-r--r--lib/csapi/notifications.cpp29
-rw-r--r--lib/csapi/openid.cpp8
-rw-r--r--lib/csapi/peeking_events.cpp6
-rw-r--r--lib/csapi/presence.cpp14
-rw-r--r--lib/csapi/presence.h2
-rw-r--r--lib/csapi/profile.cpp8
-rw-r--r--lib/csapi/pusher.cpp61
-rw-r--r--lib/csapi/pusher.h2
-rw-r--r--lib/csapi/pushrules.cpp8
-rw-r--r--lib/csapi/redaction.cpp2
-rw-r--r--lib/csapi/registration.cpp24
-rw-r--r--lib/csapi/registration.h4
-rw-r--r--lib/csapi/room_send.cpp2
-rw-r--r--lib/csapi/room_state.cpp4
-rw-r--r--lib/csapi/rooms.cpp40
-rw-r--r--lib/csapi/rooms.h13
-rw-r--r--lib/csapi/search.cpp179
-rw-r--r--lib/csapi/search.h4
-rw-r--r--lib/csapi/tags.cpp14
-rw-r--r--lib/csapi/third_party_lookup.cpp12
-rw-r--r--lib/csapi/users.cpp20
-rw-r--r--lib/csapi/versions.cpp2
-rw-r--r--lib/csapi/voip.cpp2
-rw-r--r--lib/csapi/wellknown.cpp4
-rw-r--r--lib/csapi/whoami.cpp2
-rw-r--r--lib/csapi/{{base}}.cpp.mustache69
-rw-r--r--lib/csapi/{{base}}.h.mustache13
-rw-r--r--lib/events/accountdataevents.h35
-rw-r--r--lib/events/eventcontent.h3
-rw-r--r--lib/events/eventloader.h10
-rw-r--r--lib/events/roommemberevent.cpp12
-rw-r--r--lib/events/roommemberevent.h24
-rw-r--r--lib/identity/definitions/request_email_validation.cpp23
-rw-r--r--lib/identity/definitions/request_email_validation.h8
-rw-r--r--lib/identity/definitions/request_msisdn_validation.cpp26
-rw-r--r--lib/identity/definitions/request_msisdn_validation.h8
-rw-r--r--lib/identity/definitions/sid.cpp14
-rw-r--r--lib/identity/definitions/sid.h8
-rw-r--r--lib/jobs/syncjob.cpp7
-rw-r--r--lib/jobs/syncjob.h3
-rw-r--r--lib/room.cpp205
-rw-r--r--lib/room.h25
-rw-r--r--lib/syncdata.cpp48
-rw-r--r--lib/syncdata.h32
-rw-r--r--lib/util.h16
101 files changed, 1299 insertions, 1244 deletions
diff --git a/examples/qmc-example.cpp b/examples/qmc-example.cpp
index 9c86d4a9..48787e44 100644
--- a/examples/qmc-example.cpp
+++ b/examples/qmc-example.cpp
@@ -20,12 +20,13 @@ using namespace std::placeholders;
class QMCTest : public QObject
{
public:
- QMCTest(Connection* conn, const QString& testRoomName, QString source);
+ QMCTest(Connection* conn, QString testRoomName, QString source);
private slots:
- void setup(const QString& testRoomName);
+ void setup();
void onNewRoom(Room* r);
void startTests();
+ void loadMembers();
void sendMessage();
void addAndRemoveTag();
void sendAndRedact();
@@ -43,45 +44,56 @@ class QMCTest : public QObject
QStringList succeeded;
QStringList failed;
QString origin;
+ QString testRoomName;
Room* targetRoom = nullptr;
};
#define QMC_CHECK(description, condition) \
{ \
- const bool result = !!(condition); \
Q_ASSERT(running.removeOne(description)); \
- (result ? succeeded : failed).push_back(description); \
- cout << (description) << (result ? " successul" : " FAILED") << endl; \
- if (targetRoom) \
- targetRoom->postMessage(origin % ": " % QStringLiteral(description) % \
- (result ? QStringLiteral(" successful") : QStringLiteral(" FAILED")), \
- result ? MessageEventType::Notice : MessageEventType::Text); \
+ if (!!(condition)) \
+ { \
+ succeeded.push_back(description); \
+ cout << (description) << " successful" << endl; \
+ if (targetRoom) \
+ targetRoom->postMessage( \
+ origin % ": " % (description) % " successful", \
+ MessageEventType::Notice); \
+ } else { \
+ failed.push_back(description); \
+ cout << (description) << " FAILED" << endl; \
+ if (targetRoom) \
+ targetRoom->postPlainText( \
+ origin % ": " % (description) % " FAILED"); \
+ } \
}
-QMCTest::QMCTest(Connection* conn, const QString& testRoomName, QString source)
- : c(conn), origin(std::move(source))
+QMCTest::QMCTest(Connection* conn, QString testRoomName, QString source)
+ : c(conn), origin(std::move(source)), testRoomName(std::move(testRoomName))
{
if (!origin.isEmpty())
cout << "Origin for the test message: " << origin.toStdString() << endl;
if (!testRoomName.isEmpty())
cout << "Test room name: " << testRoomName.toStdString() << endl;
- connect(c.data(), &Connection::connected,
- this, std::bind(&QMCTest::setup, this, testRoomName));
+ connect(c.data(), &Connection::connected, this, &QMCTest::setup);
connect(c.data(), &Connection::loadedRoomState, this, &QMCTest::onNewRoom);
// Big countdown watchdog
QTimer::singleShot(180000, this, &QMCTest::leave);
}
-void QMCTest::setup(const QString& testRoomName)
+void QMCTest::setup()
{
cout << "Connected, server: "
<< c->homeserver().toDisplayString().toStdString() << endl;
cout << "Access token: " << c->accessToken().toStdString() << endl;
// Setting up sync loop
+ c->setLazyLoading(true);
c->sync();
- connect(c.data(), &Connection::syncDone, c.data(), [this,testRoomName] {
+ connectSingleShot(c.data(), &Connection::syncDone,
+ this, &QMCTest::startTests);
+ connect(c.data(), &Connection::syncDone, c.data(), [this] {
cout << "Sync complete, "
<< running.size() << " tests in the air" << endl;
if (!running.isEmpty())
@@ -94,29 +106,6 @@ void QMCTest::setup(const QString& testRoomName)
else
finalize();
});
-
- // Join a testroom, if provided
- if (!targetRoom && !testRoomName.isEmpty())
- {
- cout << "Joining " << testRoomName.toStdString() << endl;
- running.push_back("Join room");
- auto joinJob = c->joinRoom(testRoomName);
- connect(joinJob, &BaseJob::failure, this,
- [this] { QMC_CHECK("Join room", false); finalize(); });
- // As of BaseJob::success, a Room object is not guaranteed to even
- // exist; it's a mere confirmation that the server processed
- // the request.
- connect(c.data(), &Connection::loadedRoomState, this,
- [this,testRoomName] (Room* room) {
- Q_ASSERT(room); // It's a grave failure if room is nullptr here
- if (room->canonicalAlias() != testRoomName)
- return; // Not our room
-
- targetRoom = room;
- QMC_CHECK("Join room", true);
- startTests();
- });
- }
}
void QMCTest::onNewRoom(Room* r)
@@ -141,11 +130,62 @@ void QMCTest::onNewRoom(Room* r)
void QMCTest::startTests()
{
- cout << "Starting tests" << endl;
- sendMessage();
- addAndRemoveTag();
- sendAndRedact();
- markDirectChat();
+ if (testRoomName.isEmpty())
+ return;
+
+ cout << "Joining " << testRoomName.toStdString() << endl;
+ running.push_back("Join room");
+ auto joinJob = c->joinRoom(testRoomName);
+ connect(joinJob, &BaseJob::failure, this,
+ [this] { QMC_CHECK("Join room", false); finalize(); });
+ // As of BaseJob::success, a Room object is not guaranteed to even
+ // exist; it's a mere confirmation that the server processed
+ // the request.
+ connect(c.data(), &Connection::loadedRoomState, this,
+ [this] (Room* room) {
+ Q_ASSERT(room); // It's a grave failure if room is nullptr here
+ if (room->canonicalAlias() != testRoomName)
+ return; // Not our room
+
+ targetRoom = room;
+ QMC_CHECK("Join room", true);
+ cout << "Starting tests" << endl;
+
+ loadMembers();
+ sendMessage();
+ addAndRemoveTag();
+ sendAndRedact();
+ markDirectChat();
+ });
+}
+
+void QMCTest::loadMembers()
+{
+ running.push_back("Loading members");
+ // The dedicated qmc-test room is too small to test
+ // lazy-loading-then-full-loading; use #test:matrix.org instead.
+ // TODO: #264
+ auto* r = c->room(QStringLiteral("!vfFxDRtZSSdspfTSEr:matrix.org"));
+ if (!r)
+ {
+ cout << "#test:matrix.org is not found in the test user's rooms" << endl;
+ QMC_CHECK("Loading members", false);
+ return;
+ }
+ // It's not exactly correct because an arbitrary server might not support
+ // lazy loading; but in the absence of capabilities framework we assume
+ // it does.
+ if (r->memberNames().size() >= r->joinedCount())
+ {
+ cout << "Lazy loading doesn't seem to be enabled" << endl;
+ QMC_CHECK("Loading members", false);
+ return;
+ }
+ r->setDisplayed();
+ connect(r, &Room::allMembersLoaded, [this,r] {
+ QMC_CHECK("Loading members",
+ r->memberNames().size() + 1 >= r->joinedCount());
+ });
}
void QMCTest::sendMessage()
diff --git a/lib/application-service/definitions/location.cpp b/lib/application-service/definitions/location.cpp
index 958a55bf..a53db8d7 100644
--- a/lib/application-service/definitions/location.cpp
+++ b/lib/application-service/definitions/location.cpp
@@ -6,25 +6,19 @@
using namespace QMatrixClient;
-QJsonObject QMatrixClient::toJson(const ThirdPartyLocation& pod)
+void JsonObjectConverter<ThirdPartyLocation>::dumpTo(
+ QJsonObject& jo, const ThirdPartyLocation& pod)
{
- QJsonObject jo;
addParam<>(jo, QStringLiteral("alias"), pod.alias);
addParam<>(jo, QStringLiteral("protocol"), pod.protocol);
addParam<>(jo, QStringLiteral("fields"), pod.fields);
- return jo;
}
-ThirdPartyLocation FromJsonObject<ThirdPartyLocation>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<ThirdPartyLocation>::fillFrom(
+ const QJsonObject& jo, ThirdPartyLocation& result)
{
- ThirdPartyLocation result;
- result.alias =
- fromJson<QString>(jo.value("alias"_ls));
- result.protocol =
- fromJson<QString>(jo.value("protocol"_ls));
- result.fields =
- fromJson<QJsonObject>(jo.value("fields"_ls));
-
- return result;
+ fromJson(jo.value("alias"_ls), result.alias);
+ fromJson(jo.value("protocol"_ls), result.protocol);
+ fromJson(jo.value("fields"_ls), result.fields);
}
diff --git a/lib/application-service/definitions/location.h b/lib/application-service/definitions/location.h
index 89b48a43..5586cfc6 100644
--- a/lib/application-service/definitions/location.h
+++ b/lib/application-service/definitions/location.h
@@ -21,12 +21,10 @@ namespace QMatrixClient
/// Information used to identify this third party location.
QJsonObject fields;
};
-
- QJsonObject toJson(const ThirdPartyLocation& pod);
-
- template <> struct FromJsonObject<ThirdPartyLocation>
+ template <> struct JsonObjectConverter<ThirdPartyLocation>
{
- ThirdPartyLocation operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const ThirdPartyLocation& pod);
+ static void fillFrom(const QJsonObject& jo, ThirdPartyLocation& pod);
};
} // namespace QMatrixClient
diff --git a/lib/application-service/definitions/protocol.cpp b/lib/application-service/definitions/protocol.cpp
index 04bb7dfc..2a62b15d 100644
--- a/lib/application-service/definitions/protocol.cpp
+++ b/lib/application-service/definitions/protocol.cpp
@@ -6,75 +6,55 @@
using namespace QMatrixClient;
-QJsonObject QMatrixClient::toJson(const FieldType& pod)
+void JsonObjectConverter<FieldType>::dumpTo(
+ QJsonObject& jo, const FieldType& pod)
{
- QJsonObject jo;
addParam<>(jo, QStringLiteral("regexp"), pod.regexp);
addParam<>(jo, QStringLiteral("placeholder"), pod.placeholder);
- return jo;
}
-FieldType FromJsonObject<FieldType>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<FieldType>::fillFrom(
+ const QJsonObject& jo, FieldType& result)
{
- FieldType result;
- result.regexp =
- fromJson<QString>(jo.value("regexp"_ls));
- result.placeholder =
- fromJson<QString>(jo.value("placeholder"_ls));
-
- return result;
+ fromJson(jo.value("regexp"_ls), result.regexp);
+ fromJson(jo.value("placeholder"_ls), result.placeholder);
}
-QJsonObject QMatrixClient::toJson(const ProtocolInstance& pod)
+void JsonObjectConverter<ProtocolInstance>::dumpTo(
+ QJsonObject& jo, const ProtocolInstance& pod)
{
- QJsonObject jo;
addParam<>(jo, QStringLiteral("desc"), pod.desc);
addParam<IfNotEmpty>(jo, QStringLiteral("icon"), pod.icon);
addParam<>(jo, QStringLiteral("fields"), pod.fields);
addParam<>(jo, QStringLiteral("network_id"), pod.networkId);
- return jo;
}
-ProtocolInstance FromJsonObject<ProtocolInstance>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<ProtocolInstance>::fillFrom(
+ const QJsonObject& jo, ProtocolInstance& result)
{
- ProtocolInstance result;
- result.desc =
- fromJson<QString>(jo.value("desc"_ls));
- result.icon =
- fromJson<QString>(jo.value("icon"_ls));
- result.fields =
- fromJson<QJsonObject>(jo.value("fields"_ls));
- result.networkId =
- fromJson<QString>(jo.value("network_id"_ls));
-
- return result;
+ fromJson(jo.value("desc"_ls), result.desc);
+ fromJson(jo.value("icon"_ls), result.icon);
+ fromJson(jo.value("fields"_ls), result.fields);
+ fromJson(jo.value("network_id"_ls), result.networkId);
}
-QJsonObject QMatrixClient::toJson(const ThirdPartyProtocol& pod)
+void JsonObjectConverter<ThirdPartyProtocol>::dumpTo(
+ QJsonObject& jo, const ThirdPartyProtocol& pod)
{
- QJsonObject jo;
addParam<>(jo, QStringLiteral("user_fields"), pod.userFields);
addParam<>(jo, QStringLiteral("location_fields"), pod.locationFields);
addParam<>(jo, QStringLiteral("icon"), pod.icon);
addParam<>(jo, QStringLiteral("field_types"), pod.fieldTypes);
addParam<>(jo, QStringLiteral("instances"), pod.instances);
- return jo;
}
-ThirdPartyProtocol FromJsonObject<ThirdPartyProtocol>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<ThirdPartyProtocol>::fillFrom(
+ const QJsonObject& jo, ThirdPartyProtocol& result)
{
- ThirdPartyProtocol result;
- result.userFields =
- fromJson<QStringList>(jo.value("user_fields"_ls));
- result.locationFields =
- fromJson<QStringList>(jo.value("location_fields"_ls));
- result.icon =
- fromJson<QString>(jo.value("icon"_ls));
- result.fieldTypes =
- fromJson<QHash<QString, FieldType>>(jo.value("field_types"_ls));
- result.instances =
- fromJson<QVector<ProtocolInstance>>(jo.value("instances"_ls));
-
- return result;
+ fromJson(jo.value("user_fields"_ls), result.userFields);
+ fromJson(jo.value("location_fields"_ls), result.locationFields);
+ fromJson(jo.value("icon"_ls), result.icon);
+ fromJson(jo.value("field_types"_ls), result.fieldTypes);
+ fromJson(jo.value("instances"_ls), result.instances);
}
diff --git a/lib/application-service/definitions/protocol.h b/lib/application-service/definitions/protocol.h
index 2aca7d66..0a1f9a21 100644
--- a/lib/application-service/definitions/protocol.h
+++ b/lib/application-service/definitions/protocol.h
@@ -25,12 +25,10 @@ namespace QMatrixClient
/// An placeholder serving as a valid example of the field value.
QString placeholder;
};
-
- QJsonObject toJson(const FieldType& pod);
-
- template <> struct FromJsonObject<FieldType>
+ template <> struct JsonObjectConverter<FieldType>
{
- FieldType operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const FieldType& pod);
+ static void fillFrom(const QJsonObject& jo, FieldType& pod);
};
struct ProtocolInstance
@@ -45,12 +43,10 @@ namespace QMatrixClient
/// A unique identifier across all instances.
QString networkId;
};
-
- QJsonObject toJson(const ProtocolInstance& pod);
-
- template <> struct FromJsonObject<ProtocolInstance>
+ template <> struct JsonObjectConverter<ProtocolInstance>
{
- ProtocolInstance operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const ProtocolInstance& pod);
+ static void fillFrom(const QJsonObject& jo, ProtocolInstance& pod);
};
struct ThirdPartyProtocol
@@ -78,12 +74,10 @@ namespace QMatrixClient
/// same application service.
QVector<ProtocolInstance> instances;
};
-
- QJsonObject toJson(const ThirdPartyProtocol& pod);
-
- template <> struct FromJsonObject<ThirdPartyProtocol>
+ template <> struct JsonObjectConverter<ThirdPartyProtocol>
{
- ThirdPartyProtocol operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const ThirdPartyProtocol& pod);
+ static void fillFrom(const QJsonObject& jo, ThirdPartyProtocol& pod);
};
} // namespace QMatrixClient
diff --git a/lib/application-service/definitions/user.cpp b/lib/application-service/definitions/user.cpp
index ca334236..8ba92321 100644
--- a/lib/application-service/definitions/user.cpp
+++ b/lib/application-service/definitions/user.cpp
@@ -6,25 +6,19 @@
using namespace QMatrixClient;
-QJsonObject QMatrixClient::toJson(const ThirdPartyUser& pod)
+void JsonObjectConverter<ThirdPartyUser>::dumpTo(
+ QJsonObject& jo, const ThirdPartyUser& pod)
{
- QJsonObject jo;
addParam<>(jo, QStringLiteral("userid"), pod.userid);
addParam<>(jo, QStringLiteral("protocol"), pod.protocol);
addParam<>(jo, QStringLiteral("fields"), pod.fields);
- return jo;
}
-ThirdPartyUser FromJsonObject<ThirdPartyUser>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<ThirdPartyUser>::fillFrom(
+ const QJsonObject& jo, ThirdPartyUser& result)
{
- ThirdPartyUser result;
- result.userid =
- fromJson<QString>(jo.value("userid"_ls));
- result.protocol =
- fromJson<QString>(jo.value("protocol"_ls));
- result.fields =
- fromJson<QJsonObject>(jo.value("fields"_ls));
-
- return result;
+ fromJson(jo.value("userid"_ls), result.userid);
+ fromJson(jo.value("protocol"_ls), result.protocol);
+ fromJson(jo.value("fields"_ls), result.fields);
}
diff --git a/lib/application-service/definitions/user.h b/lib/application-service/definitions/user.h
index 79ca7789..062d2cac 100644
--- a/lib/application-service/definitions/user.h
+++ b/lib/application-service/definitions/user.h
@@ -21,12 +21,10 @@ namespace QMatrixClient
/// Information used to identify this third party location.
QJsonObject fields;
};
-
- QJsonObject toJson(const ThirdPartyUser& pod);
-
- template <> struct FromJsonObject<ThirdPartyUser>
+ template <> struct JsonObjectConverter<ThirdPartyUser>
{
- ThirdPartyUser operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const ThirdPartyUser& pod);
+ static void fillFrom(const QJsonObject& jo, ThirdPartyUser& pod);
};
} // namespace QMatrixClient
diff --git a/lib/connection.cpp b/lib/connection.cpp
index 26c33767..a16bc753 100644
--- a/lib/connection.cpp
+++ b/lib/connection.cpp
@@ -94,6 +94,7 @@ class Connection::Private
bool cacheState = true;
bool cacheToBinary = SettingsGroup("libqmatrixclient")
.value("cache_type").toString() != "json";
+ bool lazyLoading = false;
void connectWithToken(const QString& user, const QString& accessToken,
const QString& deviceId);
@@ -287,11 +288,11 @@ void Connection::sync(int timeout)
if (d->syncJob)
return;
- // Raw string: http://en.cppreference.com/w/cpp/language/string_literal
- const auto filter =
- QStringLiteral(R"({"room": { "timeline": { "limit": 100 } } })");
+ Filter filter;
+ filter.room->timeline->limit = 100;
+ filter.room->state->lazyLoadMembers = d->lazyLoading;
auto job = d->syncJob = callApi<SyncJob>(BackgroundRequest,
- d->data->lastEvent(), filter, timeout);
+ d->data->lastEvent(), filter, timeout);
connect( job, &SyncJob::success, this, [this, job] {
onSyncSuccess(job->takeData());
d->syncJob = nullptr;
@@ -411,6 +412,11 @@ void Connection::stopSync()
}
}
+QString Connection::nextBatchToken() const
+{
+ return d->data->lastEvent();
+}
+
PostReceiptJob* Connection::postReceipt(Room* room, RoomEvent* event) const
{
return callApi<PostReceiptJob>(room->id(), "m.read", event->id());
@@ -561,7 +567,7 @@ void Connection::doInDirectChat(User* u,
{
Q_ASSERT(r->id() == roomId);
// A direct chat with yourself should only involve yourself :)
- if (userId == d->userId && r->memberCount() > 1)
+ if (userId == d->userId && r->totalMemberCount() > 1)
continue;
qCDebug(MAIN) << "Requested direct chat with" << userId
<< "is already available as" << r->id();
@@ -1181,6 +1187,20 @@ void Connection::setCacheState(bool newValue)
}
}
+bool QMatrixClient::Connection::lazyLoading() const
+{
+ return d->lazyLoading;
+}
+
+void QMatrixClient::Connection::setLazyLoading(bool newValue)
+{
+ if (d->lazyLoading != newValue)
+ {
+ d->lazyLoading = newValue;
+ emit lazyLoadingChanged();
+ }
+}
+
void Connection::getTurnServers()
{
auto job = callApi<GetTurnServerJob>();
diff --git a/lib/connection.h b/lib/connection.h
index 32533b6e..9a94aad6 100644
--- a/lib/connection.h
+++ b/lib/connection.h
@@ -122,6 +122,8 @@ namespace QMatrixClient
Q_PROPERTY(QByteArray accessToken READ accessToken NOTIFY stateChanged)
Q_PROPERTY(QUrl homeserver READ homeserver WRITE setHomeserver NOTIFY homeserverChanged)
Q_PROPERTY(bool cacheState READ cacheState WRITE setCacheState NOTIFY cacheStateChanged)
+ Q_PROPERTY(bool lazyLoading READ lazyLoading WRITE setLazyLoading NOTIFY lazyLoadingChanged)
+
public:
// Room ids, rather than room pointers, are used in the direct chat
// map types because the library keeps Invite rooms separate from
@@ -308,6 +310,9 @@ namespace QMatrixClient
bool cacheState() const;
void setCacheState(bool newValue);
+ bool lazyLoading() const;
+ void setLazyLoading(bool newValue);
+
/** Start a job of a specified type with specified arguments and policy
*
* This is a universal method to start a job of a type passed
@@ -385,6 +390,7 @@ namespace QMatrixClient
void sync(int timeout = -1);
void stopSync();
+ QString nextBatchToken() const;
virtual MediaThumbnailJob* getThumbnail(const QString& mediaId,
QSize requestedSize, RunningPolicy policy = BackgroundRequest) const;
@@ -655,6 +661,7 @@ namespace QMatrixClient
IgnoredUsersList removals);
void cacheStateChanged();
+ void lazyLoadingChanged();
void turnServersChanged(const QJsonObject& servers);
protected:
diff --git a/lib/converters.cpp b/lib/converters.cpp
index 41a9a65e..88f5267e 100644
--- a/lib/converters.cpp
+++ b/lib/converters.cpp
@@ -22,38 +22,34 @@
using namespace QMatrixClient;
-QJsonValue QMatrixClient::variantToJson(const QVariant& v)
+QJsonValue JsonConverter<QVariant>::dump(const QVariant& v)
{
return QJsonValue::fromVariant(v);
}
-QJsonObject QMatrixClient::toJson(const QVariantMap& map)
+QVariant JsonConverter<QVariant>::load(const QJsonValue& jv)
{
- return QJsonObject::fromVariantMap(map);
+ return jv.toVariant();
}
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
-QJsonObject QMatrixClient::toJson(const QVariantHash& hMap)
+QJsonObject JsonConverter<variant_map_t>::dump(const variant_map_t& map)
{
- return QJsonObject::fromVariantHash(hMap);
-}
+ return
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
+ QJsonObject::fromVariantHash
+#else
+ QJsonObject::fromVariantMap
#endif
-
-QVariant FromJson<QVariant>::operator()(const QJsonValue& jv) const
-{
- return jv.toVariant();
+ (map);
}
-QMap<QString, QVariant>
-FromJson<QMap<QString, QVariant>>::operator()(const QJsonValue& jv) const
+variant_map_t JsonConverter<QVariantHash>::load(const QJsonValue& jv)
{
- return jv.toObject().toVariantMap();
-}
-
+ return jv.toObject().
#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
-QHash<QString, QVariant>
-FromJson<QHash<QString, QVariant>>::operator()(const QJsonValue& jv) const
-{
- return jv.toObject().toVariantHash();
-}
+ toVariantHash
+#else
+ toVariantMap
#endif
+ ();
+}
diff --git a/lib/converters.h b/lib/converters.h
index 53855a1f..af2be645 100644
--- a/lib/converters.h
+++ b/lib/converters.h
@@ -57,238 +57,226 @@ class QVariant;
namespace QMatrixClient
{
- // This catches anything implicitly convertible to QJsonValue/Object/Array
- inline auto toJson(const QJsonValue& val) { return val; }
- inline auto toJson(const QJsonObject& o) { return o; }
- inline auto toJson(const QJsonArray& arr) { return arr; }
- // Special-case QString to avoid ambiguity between QJsonValue
- // and QVariant (also, QString.isEmpty() is used in _impl::AddNode<> below)
- inline auto toJson(const QString& s) { return s; }
-
- inline QJsonArray toJson(const QStringList& strings)
- {
- return QJsonArray::fromStringList(strings);
- }
-
- inline QString toJson(const QByteArray& bytes)
+ template <typename T>
+ struct JsonObjectConverter
{
- return bytes.constData();
- }
+ static void dumpTo(QJsonObject& jo, const T& pod) { jo = pod; }
+ static void fillFrom(const QJsonObject& jo, T& pod) { pod = jo; }
+ };
- // QVariant is outrageously omnivorous - it consumes whatever is not
- // exactly matching the signature of other toJson overloads. The trick
- // below disables implicit conversion to QVariant through its numerous
- // non-explicit constructors.
- QJsonValue variantToJson(const QVariant& v);
template <typename T>
- inline auto toJson(T&& /* const QVariant& or QVariant&& */ var)
- -> std::enable_if_t<std::is_same<std::decay_t<T>, QVariant>::value,
- QJsonValue>
+ struct JsonConverter
{
- return variantToJson(var);
- }
- QJsonObject toJson(const QMap<QString, QVariant>& map);
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
- QJsonObject toJson(const QHash<QString, QVariant>& hMap);
-#endif
+ static QJsonObject dump(const T& pod)
+ {
+ QJsonObject jo;
+ JsonObjectConverter<T>::dumpTo(jo, pod);
+ return jo;
+ }
+ static T doLoad(const QJsonObject& jo)
+ {
+ T pod;
+ JsonObjectConverter<T>::fillFrom(jo, pod);
+ return pod;
+ }
+ static T load(const QJsonValue& jv) { return doLoad(jv.toObject()); }
+ static T load(const QJsonDocument& jd) { return doLoad(jd.object()); }
+ };
template <typename T>
- inline QJsonArray toJson(const std::vector<T>& vals)
+ inline auto toJson(const T& pod)
{
- QJsonArray ar;
- for (const auto& v: vals)
- ar.push_back(toJson(v));
- return ar;
+ return JsonConverter<T>::dump(pod);
}
template <typename T>
- inline QJsonArray toJson(const QVector<T>& vals)
+ inline auto fillJson(QJsonObject& json, const T& data)
{
- QJsonArray ar;
- for (const auto& v: vals)
- ar.push_back(toJson(v));
- return ar;
+ JsonObjectConverter<T>::dumpTo(json, data);
}
template <typename T>
- inline QJsonObject toJson(const QSet<T>& set)
+ inline auto fromJson(const QJsonValue& jv)
{
- QJsonObject json;
- for (auto e: set)
- json.insert(toJson(e), QJsonObject{});
- return json;
+ return JsonConverter<T>::load(jv);
}
template <typename T>
- inline QJsonObject toJson(const QHash<QString, T>& hashMap)
+ inline T fromJson(const QJsonDocument& jd)
{
- QJsonObject json;
- for (auto it = hashMap.begin(); it != hashMap.end(); ++it)
- json.insert(it.key(), toJson(it.value()));
- return json;
+ return JsonConverter<T>::load(jd);
}
template <typename T>
- inline QJsonObject toJson(const std::unordered_map<QString, T>& hashMap)
+ inline void fromJson(const QJsonValue& jv, T& pod)
{
- QJsonObject json;
- for (auto it = hashMap.begin(); it != hashMap.end(); ++it)
- json.insert(it.key(), toJson(it.value()));
- return json;
+ if (!jv.isUndefined())
+ pod = fromJson<T>(jv);
}
template <typename T>
- struct FromJsonObject
+ inline void fromJson(const QJsonDocument& jd, T& pod)
{
- T operator()(const QJsonObject& jo) const { return T(jo); }
- };
+ pod = fromJson<T>(jd);
+ }
+ // Unfolds Omittable<>
template <typename T>
- struct FromJson
+ inline void fromJson(const QJsonValue& jv, Omittable<T>& pod)
{
- T operator()(const QJsonValue& jv) const
- {
- return FromJsonObject<T>()(jv.toObject());
- }
- T operator()(const QJsonDocument& jd) const
- {
- return FromJsonObject<T>()(jd.object());
- }
- };
+ if (jv.isUndefined())
+ pod = none;
+ else
+ pod = fromJson<T>(jv);
+ }
template <typename T>
- inline auto fromJson(const QJsonValue& jv)
+ inline void fillFromJson(const QJsonValue& jv, T& pod)
{
- return FromJson<T>()(jv);
+ if (jv.isObject())
+ JsonObjectConverter<T>::fillFrom(jv.toObject(), pod);
}
+ // JsonConverter<> specialisations
+
template <typename T>
- inline auto fromJson(const QJsonDocument& jd)
+ struct TrivialJsonDumper
{
- return FromJson<T>()(jd);
- }
+ // Works for: QJsonValue (and all things it can consume),
+ // QJsonObject, QJsonArray
+ static auto dump(const T& val) { return val; }
+ };
- template <> struct FromJson<bool>
+ template <> struct JsonConverter<bool> : public TrivialJsonDumper<bool>
{
- auto operator()(const QJsonValue& jv) const { return jv.toBool(); }
+ static auto load(const QJsonValue& jv) { return jv.toBool(); }
};
- template <> struct FromJson<int>
+ template <> struct JsonConverter<int> : public TrivialJsonDumper<int>
{
- auto operator()(const QJsonValue& jv) const { return jv.toInt(); }
+ static auto load(const QJsonValue& jv) { return jv.toInt(); }
};
- template <> struct FromJson<double>
+ template <> struct JsonConverter<double>
+ : public TrivialJsonDumper<double>
{
- auto operator()(const QJsonValue& jv) const { return jv.toDouble(); }
+ static auto load(const QJsonValue& jv) { return jv.toDouble(); }
};
- template <> struct FromJson<float>
+ template <> struct JsonConverter<float> : public TrivialJsonDumper<float>
{
- auto operator()(const QJsonValue& jv) const { return float(jv.toDouble()); }
+ static auto load(const QJsonValue& jv) { return float(jv.toDouble()); }
};
- template <> struct FromJson<qint64>
+ template <> struct JsonConverter<qint64>
+ : public TrivialJsonDumper<qint64>
{
- auto operator()(const QJsonValue& jv) const { return qint64(jv.toDouble()); }
+ static auto load(const QJsonValue& jv) { return qint64(jv.toDouble()); }
};
- template <> struct FromJson<QString>
+ template <> struct JsonConverter<QString>
+ : public TrivialJsonDumper<QString>
{
- auto operator()(const QJsonValue& jv) const { return jv.toString(); }
+ static auto load(const QJsonValue& jv) { return jv.toString(); }
};
- template <> struct FromJson<QDateTime>
+ template <> struct JsonConverter<QDateTime>
{
- auto operator()(const QJsonValue& jv) const
+ static auto dump(const QDateTime& val) = delete; // not provided yet
+ static auto load(const QJsonValue& jv)
{
- return QDateTime::fromMSecsSinceEpoch(fromJson<qint64>(jv), Qt::UTC);
+ return QDateTime::fromMSecsSinceEpoch(
+ fromJson<qint64>(jv), Qt::UTC);
}
};
- template <> struct FromJson<QDate>
+ template <> struct JsonConverter<QDate>
{
- auto operator()(const QJsonValue& jv) const
+ static auto dump(const QDate& val) = delete; // not provided yet
+ static auto load(const QJsonValue& jv)
{
return fromJson<QDateTime>(jv).date();
}
};
- template <> struct FromJson<QJsonArray>
+ template <> struct JsonConverter<QJsonArray>
+ : public TrivialJsonDumper<QJsonArray>
{
- auto operator()(const QJsonValue& jv) const
- {
- return jv.toArray();
- }
+ static auto load(const QJsonValue& jv) { return jv.toArray(); }
};
- template <> struct FromJson<QByteArray>
+ template <> struct JsonConverter<QByteArray>
{
- auto operator()(const QJsonValue& jv) const
+ static QString dump(const QByteArray& ba) { return ba.constData(); }
+ static auto load(const QJsonValue& jv)
{
return fromJson<QString>(jv).toLatin1();
}
};
- template <> struct FromJson<QVariant>
+ template <> struct JsonConverter<QVariant>
{
- QVariant operator()(const QJsonValue& jv) const;
+ static QJsonValue dump(const QVariant& v);
+ static QVariant load(const QJsonValue& jv);
};
- template <typename VectorT>
- struct ArrayFromJson
+ template <typename VectorT,
+ typename T = typename VectorT::value_type>
+ struct JsonArrayConverter
{
- auto operator()(const QJsonArray& ja) const
+ static void dumpTo(QJsonArray& ar, const VectorT& vals)
{
- using size_type = typename VectorT::size_type;
- VectorT vect; vect.resize(size_type(ja.size()));
- std::transform(ja.begin(), ja.end(),
- vect.begin(), FromJson<typename VectorT::value_type>());
- return vect;
+ for (const auto& v: vals)
+ ar.push_back(toJson(v));
}
- auto operator()(const QJsonValue& jv) const
+ static auto dump(const VectorT& vals)
{
- return operator()(jv.toArray());
+ QJsonArray ja;
+ dumpTo(ja, vals);
+ return ja;
}
- auto operator()(const QJsonDocument& jd) const
+ static auto load(const QJsonArray& ja)
{
- return operator()(jd.array());
+ VectorT vect; vect.reserve(typename VectorT::size_type(ja.size()));
+ for (const auto& i: ja)
+ vect.push_back(fromJson<T>(i));
+ return vect;
}
+ static auto load(const QJsonValue& jv) { return load(jv.toArray()); }
+ static auto load(const QJsonDocument& jd) { return load(jd.array()); }
};
- template <typename T>
- struct FromJson<std::vector<T>> : ArrayFromJson<std::vector<T>>
+ template <typename T> struct JsonConverter<std::vector<T>>
+ : public JsonArrayConverter<std::vector<T>>
{ };
- template <typename T>
- struct FromJson<QVector<T>> : ArrayFromJson<QVector<T>>
+ template <typename T> struct JsonConverter<QVector<T>>
+ : public JsonArrayConverter<QVector<T>>
+ { };
+
+ template <typename T> struct JsonConverter<QList<T>>
+ : public JsonArrayConverter<QList<T>>
{ };
- template <typename T> struct FromJson<QList<T>>
+ template <> struct JsonConverter<QStringList>
+ : public JsonConverter<QList<QString>>
{
- auto operator()(const QJsonValue& jv) const
+ static auto dump(const QStringList& sl)
{
- const auto jsonArray = jv.toArray();
- QList<T> sl; sl.reserve(jsonArray.size());
- std::transform(jsonArray.begin(), jsonArray.end(),
- std::back_inserter(sl), FromJson<T>());
- return sl;
+ return QJsonArray::fromStringList(sl);
}
};
- template <> struct FromJson<QStringList> : FromJson<QList<QString>> { };
-
- template <> struct FromJson<QMap<QString, QVariant>>
+ template <> struct JsonObjectConverter<QSet<QString>>
{
- QMap<QString, QVariant> operator()(const QJsonValue& jv) const;
- };
-
- template <typename T> struct FromJson<QSet<T>>
- {
- auto operator()(const QJsonValue& jv) const
+ static void dumpTo(QJsonObject& json, const QSet<QString>& s)
+ {
+ for (const auto& e: s)
+ json.insert(toJson(e), QJsonObject{});
+ }
+ static auto fillFrom(const QJsonObject& json, QSet<QString>& s)
{
- const auto json = jv.toObject();
- QSet<T> s; s.reserve(json.size());
+ s.reserve(s.size() + json.size());
for (auto it = json.begin(); it != json.end(); ++it)
s.insert(it.key());
return s;
@@ -298,39 +286,44 @@ namespace QMatrixClient
template <typename HashMapT>
struct HashMapFromJson
{
- auto operator()(const QJsonObject& jo) const
+ static void dumpTo(QJsonObject& json, const HashMapT& hashMap)
+ {
+ for (auto it = hashMap.begin(); it != hashMap.end(); ++it)
+ json.insert(it.key(), toJson(it.value()));
+ }
+ static void fillFrom(const QJsonObject& jo, HashMapT& h)
{
- HashMapT h; h.reserve(jo.size());
+ h.reserve(jo.size());
for (auto it = jo.begin(); it != jo.end(); ++it)
h[it.key()] =
fromJson<typename HashMapT::mapped_type>(it.value());
- return h;
- }
- auto operator()(const QJsonValue& jv) const
- {
- return operator()(jv.toObject());
- }
- auto operator()(const QJsonDocument& jd) const
- {
- return operator()(jd.object());
}
};
template <typename T>
- struct FromJson<std::unordered_map<QString, T>>
- : HashMapFromJson<std::unordered_map<QString, T>>
+ struct JsonObjectConverter<std::unordered_map<QString, T>>
+ : public HashMapFromJson<std::unordered_map<QString, T>>
{ };
template <typename T>
- struct FromJson<QHash<QString, T>> : HashMapFromJson<QHash<QString, T>>
+ struct JsonObjectConverter<QHash<QString, T>>
+ : public HashMapFromJson<QHash<QString, T>>
{ };
+ // We could use std::conditional<> below but QT_VERSION* macros in C++ code
+ // cause (kinda valid but useless and noisy) compiler warnings about
+ // bitwise operations on signed integers; so use the preprocessor for now.
+ using variant_map_t =
#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
- template <> struct FromJson<QHash<QString, QVariant>>
+ QVariantHash;
+#else
+ QVariantMap;
+#endif
+ template <> struct JsonConverter<variant_map_t>
{
- QHash<QString, QVariant> operator()(const QJsonValue& jv) const;
+ static QJsonObject dump(const variant_map_t& vh);
+ static QVariantHash load(const QJsonValue& jv);
};
-#endif
// Conditional insertion into a QJsonObject
diff --git a/lib/csapi/admin.cpp b/lib/csapi/admin.cpp
index 6066d4d9..ce06a56d 100644
--- a/lib/csapi/admin.cpp
+++ b/lib/csapi/admin.cpp
@@ -16,43 +16,29 @@ namespace QMatrixClient
{
// Converters
- template <> struct FromJsonObject<GetWhoIsJob::ConnectionInfo>
+ template <> struct JsonObjectConverter<GetWhoIsJob::ConnectionInfo>
{
- GetWhoIsJob::ConnectionInfo operator()(const QJsonObject& jo) const
+ static void fillFrom(const QJsonObject& jo, GetWhoIsJob::ConnectionInfo& result)
{
- GetWhoIsJob::ConnectionInfo result;
- result.ip =
- fromJson<QString>(jo.value("ip"_ls));
- result.lastSeen =
- fromJson<qint64>(jo.value("last_seen"_ls));
- result.userAgent =
- fromJson<QString>(jo.value("user_agent"_ls));
-
- return result;
+ fromJson(jo.value("ip"_ls), result.ip);
+ fromJson(jo.value("last_seen"_ls), result.lastSeen);
+ fromJson(jo.value("user_agent"_ls), result.userAgent);
}
};
- template <> struct FromJsonObject<GetWhoIsJob::SessionInfo>
+ template <> struct JsonObjectConverter<GetWhoIsJob::SessionInfo>
{
- GetWhoIsJob::SessionInfo operator()(const QJsonObject& jo) const
+ static void fillFrom(const QJsonObject& jo, GetWhoIsJob::SessionInfo& result)
{
- GetWhoIsJob::SessionInfo result;
- result.connections =
- fromJson<QVector<GetWhoIsJob::ConnectionInfo>>(jo.value("connections"_ls));
-
- return result;
+ fromJson(jo.value("connections"_ls), result.connections);
}
};
- template <> struct FromJsonObject<GetWhoIsJob::DeviceInfo>
+ template <> struct JsonObjectConverter<GetWhoIsJob::DeviceInfo>
{
- GetWhoIsJob::DeviceInfo operator()(const QJsonObject& jo) const
+ static void fillFrom(const QJsonObject& jo, GetWhoIsJob::DeviceInfo& result)
{
- GetWhoIsJob::DeviceInfo result;
- result.sessions =
- fromJson<QVector<GetWhoIsJob::SessionInfo>>(jo.value("sessions"_ls));
-
- return result;
+ fromJson(jo.value("sessions"_ls), result.sessions);
}
};
} // namespace QMatrixClient
@@ -94,8 +80,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"_ls));
- d->devices = fromJson<QHash<QString, DeviceInfo>>(json.value("devices"_ls));
+ fromJson(json.value("user_id"_ls), d->userId);
+ fromJson(json.value("devices"_ls), d->devices);
return Success;
}
diff --git a/lib/csapi/administrative_contact.cpp b/lib/csapi/administrative_contact.cpp
index f62002a6..11385dff 100644
--- a/lib/csapi/administrative_contact.cpp
+++ b/lib/csapi/administrative_contact.cpp
@@ -16,21 +16,14 @@ namespace QMatrixClient
{
// Converters
- template <> struct FromJsonObject<GetAccount3PIDsJob::ThirdPartyIdentifier>
+ template <> struct JsonObjectConverter<GetAccount3PIDsJob::ThirdPartyIdentifier>
{
- GetAccount3PIDsJob::ThirdPartyIdentifier operator()(const QJsonObject& jo) const
+ static void fillFrom(const QJsonObject& jo, GetAccount3PIDsJob::ThirdPartyIdentifier& result)
{
- GetAccount3PIDsJob::ThirdPartyIdentifier result;
- result.medium =
- fromJson<QString>(jo.value("medium"_ls));
- result.address =
- fromJson<QString>(jo.value("address"_ls));
- result.validatedAt =
- fromJson<qint64>(jo.value("validated_at"_ls));
- result.addedAt =
- fromJson<qint64>(jo.value("added_at"_ls));
-
- return result;
+ fromJson(jo.value("medium"_ls), result.medium);
+ fromJson(jo.value("address"_ls), result.address);
+ fromJson(jo.value("validated_at"_ls), result.validatedAt);
+ fromJson(jo.value("added_at"_ls), result.addedAt);
}
};
} // namespace QMatrixClient
@@ -66,7 +59,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"_ls));
+ fromJson(json.value("threepids"_ls), d->threepids);
return Success;
}
@@ -74,19 +67,20 @@ namespace QMatrixClient
{
// Converters
- QJsonObject toJson(const Post3PIDsJob::ThreePidCredentials& pod)
+ template <> struct JsonObjectConverter<Post3PIDsJob::ThreePidCredentials>
{
- QJsonObject jo;
- addParam<>(jo, QStringLiteral("client_secret"), pod.clientSecret);
- addParam<>(jo, QStringLiteral("id_server"), pod.idServer);
- addParam<>(jo, QStringLiteral("sid"), pod.sid);
- return jo;
- }
+ static void dumpTo(QJsonObject& jo, const Post3PIDsJob::ThreePidCredentials& pod)
+ {
+ addParam<>(jo, QStringLiteral("client_secret"), pod.clientSecret);
+ addParam<>(jo, QStringLiteral("id_server"), pod.idServer);
+ addParam<>(jo, QStringLiteral("sid"), pod.sid);
+ }
+ };
} // namespace QMatrixClient
static const auto Post3PIDsJobName = QStringLiteral("Post3PIDsJob");
-Post3PIDsJob::Post3PIDsJob(const ThreePidCredentials& threePidCreds, bool bind)
+Post3PIDsJob::Post3PIDsJob(const ThreePidCredentials& threePidCreds, Omittable<bool> bind)
: BaseJob(HttpVerb::Post, Post3PIDsJobName,
basePath % "/account/3pid")
{
@@ -139,7 +133,7 @@ const Sid& RequestTokenTo3PIDEmailJob::data() const
BaseJob::Status RequestTokenTo3PIDEmailJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<Sid>(data);
+ fromJson(data, d->data);
return Success;
}
@@ -175,7 +169,7 @@ const Sid& RequestTokenTo3PIDMSISDNJob::data() const
BaseJob::Status RequestTokenTo3PIDMSISDNJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<Sid>(data);
+ fromJson(data, d->data);
return Success;
}
diff --git a/lib/csapi/administrative_contact.h b/lib/csapi/administrative_contact.h
index 3fb3d44c..02aeee4d 100644
--- a/lib/csapi/administrative_contact.h
+++ b/lib/csapi/administrative_contact.h
@@ -113,7 +113,7 @@ namespace QMatrixClient
* identifier to the account's Matrix ID with the passed identity
* server. Default: ``false``.
*/
- explicit Post3PIDsJob(const ThreePidCredentials& threePidCreds, bool bind = false);
+ explicit Post3PIDsJob(const ThreePidCredentials& threePidCreds, Omittable<bool> bind = none);
};
/// Deletes a third party identifier from the user's account
diff --git a/lib/csapi/content-repo.cpp b/lib/csapi/content-repo.cpp
index 9b590e42..22223985 100644
--- a/lib/csapi/content-repo.cpp
+++ b/lib/csapi/content-repo.cpp
@@ -52,7 +52,7 @@ BaseJob::Status UploadContentJob::parseJson(const QJsonDocument& data)
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"_ls));
+ fromJson(json.value("content_uri"_ls), d->contentUri);
return Success;
}
@@ -276,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"_ls));
- d->ogImage = fromJson<QString>(json.value("og:image"_ls));
+ fromJson(json.value("matrix:image:size"_ls), d->matrixImageSize);
+ fromJson(json.value("og:image"_ls), d->ogImage);
return Success;
}
@@ -312,7 +312,7 @@ Omittable<qint64> GetConfigJob::uploadSize() const
BaseJob::Status GetConfigJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
- d->uploadSize = fromJson<qint64>(json.value("m.upload.size"_ls));
+ fromJson(json.value("m.upload.size"_ls), d->uploadSize);
return Success;
}
diff --git a/lib/csapi/create_room.cpp b/lib/csapi/create_room.cpp
index 36f83727..448547ae 100644
--- a/lib/csapi/create_room.cpp
+++ b/lib/csapi/create_room.cpp
@@ -16,23 +16,25 @@ namespace QMatrixClient
{
// Converters
- QJsonObject toJson(const CreateRoomJob::Invite3pid& pod)
+ template <> struct JsonObjectConverter<CreateRoomJob::Invite3pid>
{
- QJsonObject jo;
- addParam<>(jo, QStringLiteral("id_server"), pod.idServer);
- addParam<>(jo, QStringLiteral("medium"), pod.medium);
- addParam<>(jo, QStringLiteral("address"), pod.address);
- return jo;
- }
+ static void dumpTo(QJsonObject& jo, const CreateRoomJob::Invite3pid& pod)
+ {
+ addParam<>(jo, QStringLiteral("id_server"), pod.idServer);
+ addParam<>(jo, QStringLiteral("medium"), pod.medium);
+ addParam<>(jo, QStringLiteral("address"), pod.address);
+ }
+ };
- QJsonObject toJson(const CreateRoomJob::StateEvent& pod)
+ template <> struct JsonObjectConverter<CreateRoomJob::StateEvent>
{
- QJsonObject jo;
- addParam<>(jo, QStringLiteral("type"), pod.type);
- addParam<IfNotEmpty>(jo, QStringLiteral("state_key"), pod.stateKey);
- addParam<>(jo, QStringLiteral("content"), pod.content);
- return jo;
- }
+ static void dumpTo(QJsonObject& jo, const CreateRoomJob::StateEvent& pod)
+ {
+ addParam<>(jo, QStringLiteral("type"), pod.type);
+ addParam<IfNotEmpty>(jo, QStringLiteral("state_key"), pod.stateKey);
+ addParam<>(jo, QStringLiteral("content"), pod.content);
+ }
+ };
} // namespace QMatrixClient
class CreateRoomJob::Private
@@ -43,7 +45,7 @@ class CreateRoomJob::Private
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 QString& roomVersion, const QJsonObject& creationContent, const QVector<StateEvent>& initialState, const QString& preset, bool isDirect, const QJsonObject& powerLevelContentOverride)
+CreateRoomJob::CreateRoomJob(const QString& visibility, const QString& roomAliasName, const QString& name, const QString& topic, const QStringList& invite, const QVector<Invite3pid>& invite3pid, const QString& roomVersion, const QJsonObject& creationContent, const QVector<StateEvent>& initialState, const QString& preset, Omittable<bool> isDirect, const QJsonObject& powerLevelContentOverride)
: BaseJob(HttpVerb::Post, CreateRoomJobName,
basePath % "/createRoom")
, d(new Private)
@@ -77,7 +79,7 @@ BaseJob::Status CreateRoomJob::parseJson(const QJsonDocument& data)
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"_ls));
+ fromJson(json.value("room_id"_ls), d->roomId);
return Success;
}
diff --git a/lib/csapi/create_room.h b/lib/csapi/create_room.h
index a0a64df0..d7c01d00 100644
--- a/lib/csapi/create_room.h
+++ b/lib/csapi/create_room.h
@@ -216,7 +216,7 @@ namespace QMatrixClient
* event content prior to it being sent to the room. Defaults to
* overriding nothing.
*/
- explicit CreateRoomJob(const QString& visibility = {}, const QString& roomAliasName = {}, const QString& name = {}, const QString& topic = {}, const QStringList& invite = {}, const QVector<Invite3pid>& invite3pid = {}, const QString& roomVersion = {}, const QJsonObject& creationContent = {}, const QVector<StateEvent>& initialState = {}, const QString& preset = {}, bool isDirect = false, const QJsonObject& powerLevelContentOverride = {});
+ explicit CreateRoomJob(const QString& visibility = {}, const QString& roomAliasName = {}, const QString& name = {}, const QString& topic = {}, const QStringList& invite = {}, const QVector<Invite3pid>& invite3pid = {}, const QString& roomVersion = {}, const QJsonObject& creationContent = {}, const QVector<StateEvent>& initialState = {}, const QString& preset = {}, Omittable<bool> isDirect = none, const QJsonObject& powerLevelContentOverride = {});
~CreateRoomJob() override;
// Result properties
diff --git a/lib/csapi/definitions/auth_data.cpp b/lib/csapi/definitions/auth_data.cpp
index f8639432..006b8c7e 100644
--- a/lib/csapi/definitions/auth_data.cpp
+++ b/lib/csapi/definitions/auth_data.cpp
@@ -6,23 +6,20 @@
using namespace QMatrixClient;
-QJsonObject QMatrixClient::toJson(const AuthenticationData& pod)
+void JsonObjectConverter<AuthenticationData>::dumpTo(
+ QJsonObject& jo, const AuthenticationData& pod)
{
- QJsonObject jo = toJson(pod.authInfo);
+ fillJson(jo, pod.authInfo);
addParam<>(jo, QStringLiteral("type"), pod.type);
addParam<IfNotEmpty>(jo, QStringLiteral("session"), pod.session);
- return jo;
}
-AuthenticationData FromJsonObject<AuthenticationData>::operator()(QJsonObject jo) const
+void JsonObjectConverter<AuthenticationData>::fillFrom(
+ QJsonObject jo, AuthenticationData& result)
{
- AuthenticationData result;
- result.type =
- fromJson<QString>(jo.take("type"_ls));
- result.session =
- fromJson<QString>(jo.take("session"_ls));
+ fromJson(jo.take("type"_ls), result.type);
+ fromJson(jo.take("session"_ls), result.session);
- result.authInfo = fromJson<QHash<QString, QJsonObject>>(jo);
- return result;
+ fromJson(jo, result.authInfo);
}
diff --git a/lib/csapi/definitions/auth_data.h b/lib/csapi/definitions/auth_data.h
index 661d3e5f..26eb205c 100644
--- a/lib/csapi/definitions/auth_data.h
+++ b/lib/csapi/definitions/auth_data.h
@@ -23,12 +23,10 @@ namespace QMatrixClient
/// Keys dependent on the login type
QHash<QString, QJsonObject> authInfo;
};
-
- QJsonObject toJson(const AuthenticationData& pod);
-
- template <> struct FromJsonObject<AuthenticationData>
+ template <> struct JsonObjectConverter<AuthenticationData>
{
- AuthenticationData operator()(QJsonObject jo) const;
+ static void dumpTo(QJsonObject& jo, const AuthenticationData& pod);
+ static void fillFrom(QJsonObject jo, AuthenticationData& pod);
};
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/client_device.cpp b/lib/csapi/definitions/client_device.cpp
index 4a192f85..752b806a 100644
--- a/lib/csapi/definitions/client_device.cpp
+++ b/lib/csapi/definitions/client_device.cpp
@@ -6,28 +6,21 @@
using namespace QMatrixClient;
-QJsonObject QMatrixClient::toJson(const Device& pod)
+void JsonObjectConverter<Device>::dumpTo(
+ QJsonObject& jo, const Device& pod)
{
- QJsonObject jo;
addParam<>(jo, QStringLiteral("device_id"), pod.deviceId);
addParam<IfNotEmpty>(jo, QStringLiteral("display_name"), pod.displayName);
addParam<IfNotEmpty>(jo, QStringLiteral("last_seen_ip"), pod.lastSeenIp);
addParam<IfNotEmpty>(jo, QStringLiteral("last_seen_ts"), pod.lastSeenTs);
- return jo;
}
-Device FromJsonObject<Device>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<Device>::fillFrom(
+ const QJsonObject& jo, Device& result)
{
- Device result;
- result.deviceId =
- fromJson<QString>(jo.value("device_id"_ls));
- result.displayName =
- fromJson<QString>(jo.value("display_name"_ls));
- result.lastSeenIp =
- fromJson<QString>(jo.value("last_seen_ip"_ls));
- result.lastSeenTs =
- fromJson<qint64>(jo.value("last_seen_ts"_ls));
-
- return result;
+ fromJson(jo.value("device_id"_ls), result.deviceId);
+ fromJson(jo.value("display_name"_ls), result.displayName);
+ fromJson(jo.value("last_seen_ip"_ls), result.lastSeenIp);
+ fromJson(jo.value("last_seen_ts"_ls), result.lastSeenTs);
}
diff --git a/lib/csapi/definitions/client_device.h b/lib/csapi/definitions/client_device.h
index 9f10888a..a6224f71 100644
--- a/lib/csapi/definitions/client_device.h
+++ b/lib/csapi/definitions/client_device.h
@@ -28,12 +28,10 @@ namespace QMatrixClient
/// reasons).
Omittable<qint64> lastSeenTs;
};
-
- QJsonObject toJson(const Device& pod);
-
- template <> struct FromJsonObject<Device>
+ template <> struct JsonObjectConverter<Device>
{
- Device operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const Device& pod);
+ static void fillFrom(const QJsonObject& jo, Device& pod);
};
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/device_keys.cpp b/lib/csapi/definitions/device_keys.cpp
index a0e0ca42..1e79499f 100644
--- a/lib/csapi/definitions/device_keys.cpp
+++ b/lib/csapi/definitions/device_keys.cpp
@@ -6,31 +6,23 @@
using namespace QMatrixClient;
-QJsonObject QMatrixClient::toJson(const DeviceKeys& pod)
+void JsonObjectConverter<DeviceKeys>::dumpTo(
+ QJsonObject& jo, const DeviceKeys& pod)
{
- QJsonObject jo;
addParam<>(jo, QStringLiteral("user_id"), pod.userId);
addParam<>(jo, QStringLiteral("device_id"), pod.deviceId);
addParam<>(jo, QStringLiteral("algorithms"), pod.algorithms);
addParam<>(jo, QStringLiteral("keys"), pod.keys);
addParam<>(jo, QStringLiteral("signatures"), pod.signatures);
- return jo;
}
-DeviceKeys FromJsonObject<DeviceKeys>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<DeviceKeys>::fillFrom(
+ const QJsonObject& jo, DeviceKeys& result)
{
- DeviceKeys result;
- result.userId =
- fromJson<QString>(jo.value("user_id"_ls));
- result.deviceId =
- fromJson<QString>(jo.value("device_id"_ls));
- result.algorithms =
- fromJson<QStringList>(jo.value("algorithms"_ls));
- result.keys =
- fromJson<QHash<QString, QString>>(jo.value("keys"_ls));
- result.signatures =
- fromJson<QHash<QString, QHash<QString, QString>>>(jo.value("signatures"_ls));
-
- return result;
+ fromJson(jo.value("user_id"_ls), result.userId);
+ fromJson(jo.value("device_id"_ls), result.deviceId);
+ fromJson(jo.value("algorithms"_ls), result.algorithms);
+ fromJson(jo.value("keys"_ls), result.keys);
+ fromJson(jo.value("signatures"_ls), result.signatures);
}
diff --git a/lib/csapi/definitions/device_keys.h b/lib/csapi/definitions/device_keys.h
index 6023e7e8..8ebe1125 100644
--- a/lib/csapi/definitions/device_keys.h
+++ b/lib/csapi/definitions/device_keys.h
@@ -34,12 +34,10 @@ namespace QMatrixClient
/// JSON`_.
QHash<QString, QHash<QString, QString>> signatures;
};
-
- QJsonObject toJson(const DeviceKeys& pod);
-
- template <> struct FromJsonObject<DeviceKeys>
+ template <> struct JsonObjectConverter<DeviceKeys>
{
- DeviceKeys operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const DeviceKeys& pod);
+ static void fillFrom(const QJsonObject& jo, DeviceKeys& pod);
};
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/event_filter.cpp b/lib/csapi/definitions/event_filter.cpp
index cc444db0..b20d7807 100644
--- a/lib/csapi/definitions/event_filter.cpp
+++ b/lib/csapi/definitions/event_filter.cpp
@@ -6,31 +6,23 @@
using namespace QMatrixClient;
-QJsonObject QMatrixClient::toJson(const EventFilter& pod)
+void JsonObjectConverter<EventFilter>::dumpTo(
+ QJsonObject& jo, const EventFilter& pod)
{
- QJsonObject jo;
addParam<IfNotEmpty>(jo, QStringLiteral("limit"), pod.limit);
addParam<IfNotEmpty>(jo, QStringLiteral("not_senders"), pod.notSenders);
addParam<IfNotEmpty>(jo, QStringLiteral("not_types"), pod.notTypes);
addParam<IfNotEmpty>(jo, QStringLiteral("senders"), pod.senders);
addParam<IfNotEmpty>(jo, QStringLiteral("types"), pod.types);
- return jo;
}
-EventFilter FromJsonObject<EventFilter>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<EventFilter>::fillFrom(
+ const QJsonObject& jo, EventFilter& result)
{
- EventFilter result;
- result.limit =
- fromJson<int>(jo.value("limit"_ls));
- result.notSenders =
- fromJson<QStringList>(jo.value("not_senders"_ls));
- result.notTypes =
- fromJson<QStringList>(jo.value("not_types"_ls));
- result.senders =
- fromJson<QStringList>(jo.value("senders"_ls));
- result.types =
- fromJson<QStringList>(jo.value("types"_ls));
-
- return result;
+ fromJson(jo.value("limit"_ls), result.limit);
+ fromJson(jo.value("not_senders"_ls), result.notSenders);
+ fromJson(jo.value("not_types"_ls), result.notTypes);
+ fromJson(jo.value("senders"_ls), result.senders);
+ fromJson(jo.value("types"_ls), result.types);
}
diff --git a/lib/csapi/definitions/event_filter.h b/lib/csapi/definitions/event_filter.h
index 5c6a5b27..6de1fe79 100644
--- a/lib/csapi/definitions/event_filter.h
+++ b/lib/csapi/definitions/event_filter.h
@@ -25,12 +25,10 @@ namespace QMatrixClient
/// A list of event types to include. If this list is absent then all event types are included. A ``'*'`` can be used as a wildcard to match any sequence of characters.
QStringList types;
};
-
- QJsonObject toJson(const EventFilter& pod);
-
- template <> struct FromJsonObject<EventFilter>
+ template <> struct JsonObjectConverter<EventFilter>
{
- EventFilter operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const EventFilter& pod);
+ static void fillFrom(const QJsonObject& jo, EventFilter& pod);
};
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/public_rooms_response.cpp b/lib/csapi/definitions/public_rooms_response.cpp
index 2f52501d..0d26662c 100644
--- a/lib/csapi/definitions/public_rooms_response.cpp
+++ b/lib/csapi/definitions/public_rooms_response.cpp
@@ -6,9 +6,9 @@
using namespace QMatrixClient;
-QJsonObject QMatrixClient::toJson(const PublicRoomsChunk& pod)
+void JsonObjectConverter<PublicRoomsChunk>::dumpTo(
+ QJsonObject& jo, const PublicRoomsChunk& pod)
{
- QJsonObject jo;
addParam<IfNotEmpty>(jo, QStringLiteral("aliases"), pod.aliases);
addParam<IfNotEmpty>(jo, QStringLiteral("canonical_alias"), pod.canonicalAlias);
addParam<IfNotEmpty>(jo, QStringLiteral("name"), pod.name);
@@ -18,56 +18,37 @@ QJsonObject QMatrixClient::toJson(const PublicRoomsChunk& pod)
addParam<>(jo, QStringLiteral("world_readable"), pod.worldReadable);
addParam<>(jo, QStringLiteral("guest_can_join"), pod.guestCanJoin);
addParam<IfNotEmpty>(jo, QStringLiteral("avatar_url"), pod.avatarUrl);
- return jo;
}
-PublicRoomsChunk FromJsonObject<PublicRoomsChunk>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<PublicRoomsChunk>::fillFrom(
+ const QJsonObject& jo, PublicRoomsChunk& result)
{
- PublicRoomsChunk result;
- result.aliases =
- fromJson<QStringList>(jo.value("aliases"_ls));
- result.canonicalAlias =
- fromJson<QString>(jo.value("canonical_alias"_ls));
- result.name =
- fromJson<QString>(jo.value("name"_ls));
- result.numJoinedMembers =
- fromJson<int>(jo.value("num_joined_members"_ls));
- result.roomId =
- fromJson<QString>(jo.value("room_id"_ls));
- result.topic =
- fromJson<QString>(jo.value("topic"_ls));
- result.worldReadable =
- fromJson<bool>(jo.value("world_readable"_ls));
- result.guestCanJoin =
- fromJson<bool>(jo.value("guest_can_join"_ls));
- result.avatarUrl =
- fromJson<QString>(jo.value("avatar_url"_ls));
-
- return result;
+ fromJson(jo.value("aliases"_ls), result.aliases);
+ fromJson(jo.value("canonical_alias"_ls), result.canonicalAlias);
+ fromJson(jo.value("name"_ls), result.name);
+ fromJson(jo.value("num_joined_members"_ls), result.numJoinedMembers);
+ fromJson(jo.value("room_id"_ls), result.roomId);
+ fromJson(jo.value("topic"_ls), result.topic);
+ fromJson(jo.value("world_readable"_ls), result.worldReadable);
+ fromJson(jo.value("guest_can_join"_ls), result.guestCanJoin);
+ fromJson(jo.value("avatar_url"_ls), result.avatarUrl);
}
-QJsonObject QMatrixClient::toJson(const PublicRoomsResponse& pod)
+void JsonObjectConverter<PublicRoomsResponse>::dumpTo(
+ QJsonObject& jo, const PublicRoomsResponse& pod)
{
- QJsonObject jo;
addParam<>(jo, QStringLiteral("chunk"), pod.chunk);
addParam<IfNotEmpty>(jo, QStringLiteral("next_batch"), pod.nextBatch);
addParam<IfNotEmpty>(jo, QStringLiteral("prev_batch"), pod.prevBatch);
addParam<IfNotEmpty>(jo, QStringLiteral("total_room_count_estimate"), pod.totalRoomCountEstimate);
- return jo;
}
-PublicRoomsResponse FromJsonObject<PublicRoomsResponse>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<PublicRoomsResponse>::fillFrom(
+ const QJsonObject& jo, PublicRoomsResponse& result)
{
- PublicRoomsResponse result;
- result.chunk =
- fromJson<QVector<PublicRoomsChunk>>(jo.value("chunk"_ls));
- result.nextBatch =
- fromJson<QString>(jo.value("next_batch"_ls));
- result.prevBatch =
- fromJson<QString>(jo.value("prev_batch"_ls));
- result.totalRoomCountEstimate =
- fromJson<int>(jo.value("total_room_count_estimate"_ls));
-
- return result;
+ fromJson(jo.value("chunk"_ls), result.chunk);
+ fromJson(jo.value("next_batch"_ls), result.nextBatch);
+ fromJson(jo.value("prev_batch"_ls), result.prevBatch);
+ fromJson(jo.value("total_room_count_estimate"_ls), result.totalRoomCountEstimate);
}
diff --git a/lib/csapi/definitions/public_rooms_response.h b/lib/csapi/definitions/public_rooms_response.h
index 88c805ba..4c54ac25 100644
--- a/lib/csapi/definitions/public_rooms_response.h
+++ b/lib/csapi/definitions/public_rooms_response.h
@@ -36,12 +36,10 @@ namespace QMatrixClient
/// The URL for the room's avatar, if one is set.
QString avatarUrl;
};
-
- QJsonObject toJson(const PublicRoomsChunk& pod);
-
- template <> struct FromJsonObject<PublicRoomsChunk>
+ template <> struct JsonObjectConverter<PublicRoomsChunk>
{
- PublicRoomsChunk operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const PublicRoomsChunk& pod);
+ static void fillFrom(const QJsonObject& jo, PublicRoomsChunk& pod);
};
/// A list of the rooms on the server.
@@ -61,12 +59,10 @@ namespace QMatrixClient
/// server has an estimate.
Omittable<int> totalRoomCountEstimate;
};
-
- QJsonObject toJson(const PublicRoomsResponse& pod);
-
- template <> struct FromJsonObject<PublicRoomsResponse>
+ template <> struct JsonObjectConverter<PublicRoomsResponse>
{
- PublicRoomsResponse operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const PublicRoomsResponse& pod);
+ static void fillFrom(const QJsonObject& jo, PublicRoomsResponse& pod);
};
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/push_condition.cpp b/lib/csapi/definitions/push_condition.cpp
index 045094bc..ace02755 100644
--- a/lib/csapi/definitions/push_condition.cpp
+++ b/lib/csapi/definitions/push_condition.cpp
@@ -6,28 +6,21 @@
using namespace QMatrixClient;
-QJsonObject QMatrixClient::toJson(const PushCondition& pod)
+void JsonObjectConverter<PushCondition>::dumpTo(
+ QJsonObject& jo, const PushCondition& pod)
{
- QJsonObject jo;
addParam<>(jo, QStringLiteral("kind"), pod.kind);
addParam<IfNotEmpty>(jo, QStringLiteral("key"), pod.key);
addParam<IfNotEmpty>(jo, QStringLiteral("pattern"), pod.pattern);
addParam<IfNotEmpty>(jo, QStringLiteral("is"), pod.is);
- return jo;
}
-PushCondition FromJsonObject<PushCondition>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<PushCondition>::fillFrom(
+ const QJsonObject& jo, PushCondition& result)
{
- PushCondition result;
- result.kind =
- fromJson<QString>(jo.value("kind"_ls));
- result.key =
- fromJson<QString>(jo.value("key"_ls));
- result.pattern =
- fromJson<QString>(jo.value("pattern"_ls));
- result.is =
- fromJson<QString>(jo.value("is"_ls));
-
- return result;
+ fromJson(jo.value("kind"_ls), result.kind);
+ fromJson(jo.value("key"_ls), result.key);
+ fromJson(jo.value("pattern"_ls), result.pattern);
+ fromJson(jo.value("is"_ls), result.is);
}
diff --git a/lib/csapi/definitions/push_condition.h b/lib/csapi/definitions/push_condition.h
index defcebb3..e45526d2 100644
--- a/lib/csapi/definitions/push_condition.h
+++ b/lib/csapi/definitions/push_condition.h
@@ -28,12 +28,10 @@ namespace QMatrixClient
/// so forth. If no prefix is present, this parameter defaults to ==.
QString is;
};
-
- QJsonObject toJson(const PushCondition& pod);
-
- template <> struct FromJsonObject<PushCondition>
+ template <> struct JsonObjectConverter<PushCondition>
{
- PushCondition operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const PushCondition& pod);
+ static void fillFrom(const QJsonObject& jo, PushCondition& pod);
};
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/push_rule.cpp b/lib/csapi/definitions/push_rule.cpp
index baddd187..abbb04b5 100644
--- a/lib/csapi/definitions/push_rule.cpp
+++ b/lib/csapi/definitions/push_rule.cpp
@@ -6,34 +6,25 @@
using namespace QMatrixClient;
-QJsonObject QMatrixClient::toJson(const PushRule& pod)
+void JsonObjectConverter<PushRule>::dumpTo(
+ QJsonObject& jo, const PushRule& pod)
{
- QJsonObject jo;
addParam<>(jo, QStringLiteral("actions"), pod.actions);
addParam<>(jo, QStringLiteral("default"), pod.isDefault);
addParam<>(jo, QStringLiteral("enabled"), pod.enabled);
addParam<>(jo, QStringLiteral("rule_id"), pod.ruleId);
addParam<IfNotEmpty>(jo, QStringLiteral("conditions"), pod.conditions);
addParam<IfNotEmpty>(jo, QStringLiteral("pattern"), pod.pattern);
- return jo;
}
-PushRule FromJsonObject<PushRule>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<PushRule>::fillFrom(
+ const QJsonObject& jo, PushRule& result)
{
- PushRule result;
- result.actions =
- fromJson<QVector<QVariant>>(jo.value("actions"_ls));
- result.isDefault =
- fromJson<bool>(jo.value("default"_ls));
- result.enabled =
- fromJson<bool>(jo.value("enabled"_ls));
- result.ruleId =
- fromJson<QString>(jo.value("rule_id"_ls));
- result.conditions =
- fromJson<QVector<PushCondition>>(jo.value("conditions"_ls));
- result.pattern =
- fromJson<QString>(jo.value("pattern"_ls));
-
- return result;
+ fromJson(jo.value("actions"_ls), result.actions);
+ fromJson(jo.value("default"_ls), result.isDefault);
+ fromJson(jo.value("enabled"_ls), result.enabled);
+ fromJson(jo.value("rule_id"_ls), result.ruleId);
+ fromJson(jo.value("conditions"_ls), result.conditions);
+ fromJson(jo.value("pattern"_ls), result.pattern);
}
diff --git a/lib/csapi/definitions/push_rule.h b/lib/csapi/definitions/push_rule.h
index 5f52876d..bea13e96 100644
--- a/lib/csapi/definitions/push_rule.h
+++ b/lib/csapi/definitions/push_rule.h
@@ -7,10 +7,10 @@
#include "converters.h"
#include "csapi/definitions/push_condition.h"
-#include "converters.h"
+#include <QtCore/QJsonObject>
#include <QtCore/QVector>
#include <QtCore/QVariant>
-#include <QtCore/QJsonObject>
+#include "converters.h"
namespace QMatrixClient
{
@@ -34,12 +34,10 @@ namespace QMatrixClient
/// rules.
QString pattern;
};
-
- QJsonObject toJson(const PushRule& pod);
-
- template <> struct FromJsonObject<PushRule>
+ template <> struct JsonObjectConverter<PushRule>
{
- PushRule operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const PushRule& pod);
+ static void fillFrom(const QJsonObject& jo, PushRule& pod);
};
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/push_ruleset.cpp b/lib/csapi/definitions/push_ruleset.cpp
index 14b7a4b6..f1bad882 100644
--- a/lib/csapi/definitions/push_ruleset.cpp
+++ b/lib/csapi/definitions/push_ruleset.cpp
@@ -6,31 +6,23 @@
using namespace QMatrixClient;
-QJsonObject QMatrixClient::toJson(const PushRuleset& pod)
+void JsonObjectConverter<PushRuleset>::dumpTo(
+ QJsonObject& jo, const PushRuleset& pod)
{
- QJsonObject jo;
addParam<IfNotEmpty>(jo, QStringLiteral("content"), pod.content);
addParam<IfNotEmpty>(jo, QStringLiteral("override"), pod.override);
addParam<IfNotEmpty>(jo, QStringLiteral("room"), pod.room);
addParam<IfNotEmpty>(jo, QStringLiteral("sender"), pod.sender);
addParam<IfNotEmpty>(jo, QStringLiteral("underride"), pod.underride);
- return jo;
}
-PushRuleset FromJsonObject<PushRuleset>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<PushRuleset>::fillFrom(
+ const QJsonObject& jo, PushRuleset& result)
{
- PushRuleset result;
- result.content =
- fromJson<QVector<PushRule>>(jo.value("content"_ls));
- result.override =
- fromJson<QVector<PushRule>>(jo.value("override"_ls));
- result.room =
- fromJson<QVector<PushRule>>(jo.value("room"_ls));
- result.sender =
- fromJson<QVector<PushRule>>(jo.value("sender"_ls));
- result.underride =
- fromJson<QVector<PushRule>>(jo.value("underride"_ls));
-
- return result;
+ fromJson(jo.value("content"_ls), result.content);
+ fromJson(jo.value("override"_ls), result.override);
+ fromJson(jo.value("room"_ls), result.room);
+ fromJson(jo.value("sender"_ls), result.sender);
+ fromJson(jo.value("underride"_ls), result.underride);
}
diff --git a/lib/csapi/definitions/push_ruleset.h b/lib/csapi/definitions/push_ruleset.h
index a274b72a..f2d937c0 100644
--- a/lib/csapi/definitions/push_ruleset.h
+++ b/lib/csapi/definitions/push_ruleset.h
@@ -22,12 +22,10 @@ namespace QMatrixClient
QVector<PushRule> sender;
QVector<PushRule> underride;
};
-
- QJsonObject toJson(const PushRuleset& pod);
-
- template <> struct FromJsonObject<PushRuleset>
+ template <> struct JsonObjectConverter<PushRuleset>
{
- PushRuleset operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const PushRuleset& pod);
+ static void fillFrom(const QJsonObject& jo, PushRuleset& pod);
};
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/room_event_filter.cpp b/lib/csapi/definitions/room_event_filter.cpp
index 8cd2ded7..df92e684 100644
--- a/lib/csapi/definitions/room_event_filter.cpp
+++ b/lib/csapi/definitions/room_event_filter.cpp
@@ -6,31 +6,21 @@
using namespace QMatrixClient;
-QJsonObject QMatrixClient::toJson(const RoomEventFilter& pod)
+void JsonObjectConverter<RoomEventFilter>::dumpTo(
+ QJsonObject& jo, const RoomEventFilter& pod)
{
- QJsonObject jo;
+ fillJson<EventFilter>(jo, pod);
addParam<IfNotEmpty>(jo, QStringLiteral("not_rooms"), pod.notRooms);
addParam<IfNotEmpty>(jo, QStringLiteral("rooms"), pod.rooms);
addParam<IfNotEmpty>(jo, QStringLiteral("contains_url"), pod.containsUrl);
- addParam<IfNotEmpty>(jo, QStringLiteral("lazy_load_members"), pod.lazyLoadMembers);
- addParam<IfNotEmpty>(jo, QStringLiteral("include_redundant_members"), pod.includeRedundantMembers);
- return jo;
}
-RoomEventFilter FromJsonObject<RoomEventFilter>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<RoomEventFilter>::fillFrom(
+ const QJsonObject& jo, RoomEventFilter& result)
{
- RoomEventFilter result;
- result.notRooms =
- fromJson<QStringList>(jo.value("not_rooms"_ls));
- result.rooms =
- fromJson<QStringList>(jo.value("rooms"_ls));
- result.containsUrl =
- fromJson<bool>(jo.value("contains_url"_ls));
- result.lazyLoadMembers =
- fromJson<bool>(jo.value("lazy_load_members"_ls));
- result.includeRedundantMembers =
- fromJson<bool>(jo.value("include_redundant_members"_ls));
-
- return result;
+ fillFromJson<EventFilter>(jo, result);
+ fromJson(jo.value("not_rooms"_ls), result.notRooms);
+ fromJson(jo.value("rooms"_ls), result.rooms);
+ fromJson(jo.value("contains_url"_ls), result.containsUrl);
}
diff --git a/lib/csapi/definitions/room_event_filter.h b/lib/csapi/definitions/room_event_filter.h
index 87f01189..6eb9a390 100644
--- a/lib/csapi/definitions/room_event_filter.h
+++ b/lib/csapi/definitions/room_event_filter.h
@@ -19,19 +19,13 @@ namespace QMatrixClient
QStringList notRooms;
/// A list of room IDs to include. If this list is absent then all rooms are included.
QStringList rooms;
- /// If ``true``, includes only events with a ``url`` key in their content. If ``false``, excludes those events. Defaults to ``false``.
- bool containsUrl;
- /// If ``true``, the only ``m.room.member`` events returned in the ``state`` section of the ``/sync`` response are those which are definitely necessary for a client to display the ``sender`` of the timeline events in that response. If ``false``, ``m.room.member`` events are not filtered. By default, servers should suppress duplicate redundant lazy-loaded ``m.room.member`` events from being sent to a given client across multiple calls to ``/sync``, given that most clients cache membership events (see include_redundant_members to change this behaviour).
- bool lazyLoadMembers;
- /// If ``true``, the ``state`` section of the ``/sync`` response will always contain the ``m.room.member`` events required to display the ``sender`` of the timeline events in that response, assuming ``lazy_load_members`` is enabled. This means that redundant duplicate member events may be returned across multiple calls to ``/sync``. This is useful for naive clients who never track membership data. If ``false``, duplicate ``m.room.member`` events may be suppressed by the server across multiple calls to ``/sync``. If ``lazy_load_members`` is ``false`` this field is ignored.
- bool includeRedundantMembers;
+ /// If ``true``, includes only events with a ``url`` key in their content. If ``false``, excludes those events. If omitted, ``url`` key is not considered for filtering.
+ Omittable<bool> containsUrl;
};
-
- QJsonObject toJson(const RoomEventFilter& pod);
-
- template <> struct FromJsonObject<RoomEventFilter>
+ template <> struct JsonObjectConverter<RoomEventFilter>
{
- RoomEventFilter operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const RoomEventFilter& pod);
+ static void fillFrom(const QJsonObject& jo, RoomEventFilter& pod);
};
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/sync_filter.cpp b/lib/csapi/definitions/sync_filter.cpp
index bd87804c..32752d1f 100644
--- a/lib/csapi/definitions/sync_filter.cpp
+++ b/lib/csapi/definitions/sync_filter.cpp
@@ -6,9 +6,25 @@
using namespace QMatrixClient;
-QJsonObject QMatrixClient::toJson(const RoomFilter& pod)
+void JsonObjectConverter<StateFilter>::dumpTo(
+ QJsonObject& jo, const StateFilter& pod)
+{
+ fillJson<RoomEventFilter>(jo, pod);
+ addParam<IfNotEmpty>(jo, QStringLiteral("lazy_load_members"), pod.lazyLoadMembers);
+ addParam<IfNotEmpty>(jo, QStringLiteral("include_redundant_members"), pod.includeRedundantMembers);
+}
+
+void JsonObjectConverter<StateFilter>::fillFrom(
+ const QJsonObject& jo, StateFilter& result)
+{
+ fillFromJson<RoomEventFilter>(jo, result);
+ fromJson(jo.value("lazy_load_members"_ls), result.lazyLoadMembers);
+ fromJson(jo.value("include_redundant_members"_ls), result.includeRedundantMembers);
+}
+
+void JsonObjectConverter<RoomFilter>::dumpTo(
+ QJsonObject& jo, const RoomFilter& pod)
{
- QJsonObject jo;
addParam<IfNotEmpty>(jo, QStringLiteral("not_rooms"), pod.notRooms);
addParam<IfNotEmpty>(jo, QStringLiteral("rooms"), pod.rooms);
addParam<IfNotEmpty>(jo, QStringLiteral("ephemeral"), pod.ephemeral);
@@ -16,55 +32,37 @@ QJsonObject QMatrixClient::toJson(const RoomFilter& pod)
addParam<IfNotEmpty>(jo, QStringLiteral("state"), pod.state);
addParam<IfNotEmpty>(jo, QStringLiteral("timeline"), pod.timeline);
addParam<IfNotEmpty>(jo, QStringLiteral("account_data"), pod.accountData);
- return jo;
}
-RoomFilter FromJsonObject<RoomFilter>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<RoomFilter>::fillFrom(
+ const QJsonObject& jo, RoomFilter& result)
{
- RoomFilter result;
- result.notRooms =
- fromJson<QStringList>(jo.value("not_rooms"_ls));
- result.rooms =
- fromJson<QStringList>(jo.value("rooms"_ls));
- result.ephemeral =
- fromJson<RoomEventFilter>(jo.value("ephemeral"_ls));
- result.includeLeave =
- fromJson<bool>(jo.value("include_leave"_ls));
- result.state =
- fromJson<RoomEventFilter>(jo.value("state"_ls));
- result.timeline =
- fromJson<RoomEventFilter>(jo.value("timeline"_ls));
- result.accountData =
- fromJson<RoomEventFilter>(jo.value("account_data"_ls));
-
- return result;
+ fromJson(jo.value("not_rooms"_ls), result.notRooms);
+ fromJson(jo.value("rooms"_ls), result.rooms);
+ fromJson(jo.value("ephemeral"_ls), result.ephemeral);
+ fromJson(jo.value("include_leave"_ls), result.includeLeave);
+ fromJson(jo.value("state"_ls), result.state);
+ fromJson(jo.value("timeline"_ls), result.timeline);
+ fromJson(jo.value("account_data"_ls), result.accountData);
}
-QJsonObject QMatrixClient::toJson(const Filter& pod)
+void JsonObjectConverter<Filter>::dumpTo(
+ QJsonObject& jo, const Filter& pod)
{
- QJsonObject jo;
addParam<IfNotEmpty>(jo, QStringLiteral("event_fields"), pod.eventFields);
addParam<IfNotEmpty>(jo, QStringLiteral("event_format"), pod.eventFormat);
addParam<IfNotEmpty>(jo, QStringLiteral("presence"), pod.presence);
addParam<IfNotEmpty>(jo, QStringLiteral("account_data"), pod.accountData);
addParam<IfNotEmpty>(jo, QStringLiteral("room"), pod.room);
- return jo;
}
-Filter FromJsonObject<Filter>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<Filter>::fillFrom(
+ const QJsonObject& jo, Filter& result)
{
- Filter result;
- result.eventFields =
- fromJson<QStringList>(jo.value("event_fields"_ls));
- result.eventFormat =
- fromJson<QString>(jo.value("event_format"_ls));
- result.presence =
- fromJson<EventFilter>(jo.value("presence"_ls));
- result.accountData =
- fromJson<EventFilter>(jo.value("account_data"_ls));
- result.room =
- fromJson<RoomFilter>(jo.value("room"_ls));
-
- return result;
+ fromJson(jo.value("event_fields"_ls), result.eventFields);
+ fromJson(jo.value("event_format"_ls), result.eventFormat);
+ fromJson(jo.value("presence"_ls), result.presence);
+ fromJson(jo.value("account_data"_ls), result.accountData);
+ fromJson(jo.value("room"_ls), result.room);
}
diff --git a/lib/csapi/definitions/sync_filter.h b/lib/csapi/definitions/sync_filter.h
index ca275a9a..d94c74d7 100644
--- a/lib/csapi/definitions/sync_filter.h
+++ b/lib/csapi/definitions/sync_filter.h
@@ -14,6 +14,37 @@ namespace QMatrixClient
{
// Data structures
+ /// The state events to include for rooms.
+ struct StateFilter : RoomEventFilter
+ {
+ /// If ``true``, the only ``m.room.member`` events returned in
+ /// the ``state`` section of the ``/sync`` response are those
+ /// which are definitely necessary for a client to display
+ /// the ``sender`` of the timeline events in that response.
+ /// If ``false``, ``m.room.member`` events are not filtered.
+ /// By default, servers should suppress duplicate redundant
+ /// lazy-loaded ``m.room.member`` events from being sent to a given
+ /// client across multiple calls to ``/sync``, given that most clients
+ /// cache membership events (see ``include_redundant_members``
+ /// to change this behaviour).
+ Omittable<bool> lazyLoadMembers;
+ /// If ``true``, the ``state`` section of the ``/sync`` response will
+ /// always contain the ``m.room.member`` events required to display
+ /// the ``sender`` of the timeline events in that response, assuming
+ /// ``lazy_load_members`` is enabled. This means that redundant
+ /// duplicate member events may be returned across multiple calls to
+ /// ``/sync``. This is useful for naive clients who never track
+ /// membership data. If ``false``, duplicate ``m.room.member`` events
+ /// may be suppressed by the server across multiple calls to ``/sync``.
+ /// If ``lazy_load_members`` is ``false`` this field is ignored.
+ Omittable<bool> includeRedundantMembers;
+ };
+ template <> struct JsonObjectConverter<StateFilter>
+ {
+ static void dumpTo(QJsonObject& jo, const StateFilter& pod);
+ static void fillFrom(const QJsonObject& jo, StateFilter& pod);
+ };
+
/// Filters to be applied to room data.
struct RoomFilter
{
@@ -24,20 +55,18 @@ namespace QMatrixClient
/// The events that aren't recorded in the room history, e.g. typing and receipts, to include for rooms.
Omittable<RoomEventFilter> ephemeral;
/// Include rooms that the user has left in the sync, default false
- bool includeLeave;
+ Omittable<bool> includeLeave;
/// The state events to include for rooms.
- Omittable<RoomEventFilter> state;
+ Omittable<StateFilter> state;
/// The message and state update events to include for rooms.
Omittable<RoomEventFilter> timeline;
/// The per user account data to include for rooms.
Omittable<RoomEventFilter> accountData;
};
-
- QJsonObject toJson(const RoomFilter& pod);
-
- template <> struct FromJsonObject<RoomFilter>
+ template <> struct JsonObjectConverter<RoomFilter>
{
- RoomFilter operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const RoomFilter& pod);
+ static void fillFrom(const QJsonObject& jo, RoomFilter& pod);
};
struct Filter
@@ -53,12 +82,10 @@ namespace QMatrixClient
/// Filters to be applied to room data.
Omittable<RoomFilter> room;
};
-
- QJsonObject toJson(const Filter& pod);
-
- template <> struct FromJsonObject<Filter>
+ template <> struct JsonObjectConverter<Filter>
{
- Filter operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const Filter& pod);
+ static void fillFrom(const QJsonObject& jo, Filter& pod);
};
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/user_identifier.cpp b/lib/csapi/definitions/user_identifier.cpp
index 80a6d450..05a27c1c 100644
--- a/lib/csapi/definitions/user_identifier.cpp
+++ b/lib/csapi/definitions/user_identifier.cpp
@@ -6,20 +6,18 @@
using namespace QMatrixClient;
-QJsonObject QMatrixClient::toJson(const UserIdentifier& pod)
+void JsonObjectConverter<UserIdentifier>::dumpTo(
+ QJsonObject& jo, const UserIdentifier& pod)
{
- QJsonObject jo = toJson(pod.additionalProperties);
+ fillJson(jo, pod.additionalProperties);
addParam<>(jo, QStringLiteral("type"), pod.type);
- return jo;
}
-UserIdentifier FromJsonObject<UserIdentifier>::operator()(QJsonObject jo) const
+void JsonObjectConverter<UserIdentifier>::fillFrom(
+ QJsonObject jo, UserIdentifier& result)
{
- UserIdentifier result;
- result.type =
- fromJson<QString>(jo.take("type"_ls));
+ fromJson(jo.take("type"_ls), result.type);
- result.additionalProperties = fromJson<QVariantHash>(jo);
- return result;
+ fromJson(jo, result.additionalProperties);
}
diff --git a/lib/csapi/definitions/user_identifier.h b/lib/csapi/definitions/user_identifier.h
index 42614436..cbb1550f 100644
--- a/lib/csapi/definitions/user_identifier.h
+++ b/lib/csapi/definitions/user_identifier.h
@@ -20,12 +20,10 @@ namespace QMatrixClient
/// Identification information for a user
QVariantHash additionalProperties;
};
-
- QJsonObject toJson(const UserIdentifier& pod);
-
- template <> struct FromJsonObject<UserIdentifier>
+ template <> struct JsonObjectConverter<UserIdentifier>
{
- UserIdentifier operator()(QJsonObject jo) const;
+ static void dumpTo(QJsonObject& jo, const UserIdentifier& pod);
+ static void fillFrom(QJsonObject jo, UserIdentifier& pod);
};
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/wellknown/homeserver.cpp b/lib/csapi/definitions/wellknown/homeserver.cpp
index f1482ee4..0783f11b 100644
--- a/lib/csapi/definitions/wellknown/homeserver.cpp
+++ b/lib/csapi/definitions/wellknown/homeserver.cpp
@@ -6,19 +6,15 @@
using namespace QMatrixClient;
-QJsonObject QMatrixClient::toJson(const HomeserverInformation& pod)
+void JsonObjectConverter<HomeserverInformation>::dumpTo(
+ QJsonObject& jo, const HomeserverInformation& pod)
{
- QJsonObject jo;
addParam<>(jo, QStringLiteral("base_url"), pod.baseUrl);
- return jo;
}
-HomeserverInformation FromJsonObject<HomeserverInformation>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<HomeserverInformation>::fillFrom(
+ const QJsonObject& jo, HomeserverInformation& result)
{
- HomeserverInformation result;
- result.baseUrl =
- fromJson<QString>(jo.value("base_url"_ls));
-
- return result;
+ fromJson(jo.value("base_url"_ls), result.baseUrl);
}
diff --git a/lib/csapi/definitions/wellknown/homeserver.h b/lib/csapi/definitions/wellknown/homeserver.h
index 09d6ba63..f6761c30 100644
--- a/lib/csapi/definitions/wellknown/homeserver.h
+++ b/lib/csapi/definitions/wellknown/homeserver.h
@@ -17,12 +17,10 @@ namespace QMatrixClient
/// The base URL for the homeserver for client-server connections.
QString baseUrl;
};
-
- QJsonObject toJson(const HomeserverInformation& pod);
-
- template <> struct FromJsonObject<HomeserverInformation>
+ template <> struct JsonObjectConverter<HomeserverInformation>
{
- HomeserverInformation operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const HomeserverInformation& pod);
+ static void fillFrom(const QJsonObject& jo, HomeserverInformation& pod);
};
} // namespace QMatrixClient
diff --git a/lib/csapi/definitions/wellknown/identity_server.cpp b/lib/csapi/definitions/wellknown/identity_server.cpp
index f9d7bc37..99f36641 100644
--- a/lib/csapi/definitions/wellknown/identity_server.cpp
+++ b/lib/csapi/definitions/wellknown/identity_server.cpp
@@ -6,19 +6,15 @@
using namespace QMatrixClient;
-QJsonObject QMatrixClient::toJson(const IdentityServerInformation& pod)
+void JsonObjectConverter<IdentityServerInformation>::dumpTo(
+ QJsonObject& jo, const IdentityServerInformation& pod)
{
- QJsonObject jo;
addParam<>(jo, QStringLiteral("base_url"), pod.baseUrl);
- return jo;
}
-IdentityServerInformation FromJsonObject<IdentityServerInformation>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<IdentityServerInformation>::fillFrom(
+ const QJsonObject& jo, IdentityServerInformation& result)
{
- IdentityServerInformation result;
- result.baseUrl =
- fromJson<QString>(jo.value("base_url"_ls));
-
- return result;
+ fromJson(jo.value("base_url"_ls), result.baseUrl);
}
diff --git a/lib/csapi/definitions/wellknown/identity_server.h b/lib/csapi/definitions/wellknown/identity_server.h
index cb8ffcee..67d8b08d 100644
--- a/lib/csapi/definitions/wellknown/identity_server.h
+++ b/lib/csapi/definitions/wellknown/identity_server.h
@@ -17,12 +17,10 @@ namespace QMatrixClient
/// The base URL for the identity server for client-server connections.
QString baseUrl;
};
-
- QJsonObject toJson(const IdentityServerInformation& pod);
-
- template <> struct FromJsonObject<IdentityServerInformation>
+ template <> struct JsonObjectConverter<IdentityServerInformation>
{
- IdentityServerInformation operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const IdentityServerInformation& pod);
+ static void fillFrom(const QJsonObject& jo, IdentityServerInformation& pod);
};
} // namespace QMatrixClient
diff --git a/lib/csapi/device_management.cpp b/lib/csapi/device_management.cpp
index 861e1994..9c31db5d 100644
--- a/lib/csapi/device_management.cpp
+++ b/lib/csapi/device_management.cpp
@@ -43,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"_ls));
+ fromJson(json.value("devices"_ls), d->devices);
return Success;
}
@@ -77,7 +77,7 @@ const Device& GetDeviceJob::data() const
BaseJob::Status GetDeviceJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<Device>(data);
+ fromJson(data, d->data);
return Success;
}
diff --git a/lib/csapi/directory.cpp b/lib/csapi/directory.cpp
index 5353f3bc..4af86f7b 100644
--- a/lib/csapi/directory.cpp
+++ b/lib/csapi/directory.cpp
@@ -60,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"_ls));
- d->servers = fromJson<QStringList>(json.value("servers"_ls));
+ fromJson(json.value("room_id"_ls), d->roomId);
+ fromJson(json.value("servers"_ls), d->servers);
return Success;
}
diff --git a/lib/csapi/event_context.cpp b/lib/csapi/event_context.cpp
index 806c1613..bb1f5301 100644
--- a/lib/csapi/event_context.cpp
+++ b/lib/csapi/event_context.cpp
@@ -82,12 +82,12 @@ StateEvents&& GetEventContextJob::state()
BaseJob::Status GetEventContextJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
- 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));
+ fromJson(json.value("start"_ls), d->begin);
+ fromJson(json.value("end"_ls), d->end);
+ fromJson(json.value("events_before"_ls), d->eventsBefore);
+ fromJson(json.value("event"_ls), d->event);
+ fromJson(json.value("events_after"_ls), d->eventsAfter);
+ fromJson(json.value("state"_ls), d->state);
return Success;
}
diff --git a/lib/csapi/filter.cpp b/lib/csapi/filter.cpp
index 77dc9b92..982e60b5 100644
--- a/lib/csapi/filter.cpp
+++ b/lib/csapi/filter.cpp
@@ -41,7 +41,7 @@ BaseJob::Status DefineFilterJob::parseJson(const QJsonDocument& data)
if (!json.contains("filter_id"_ls))
return { JsonParseError,
"The key 'filter_id' not found in the response" };
- d->filterId = fromJson<QString>(json.value("filter_id"_ls));
+ fromJson(json.value("filter_id"_ls), d->filterId);
return Success;
}
@@ -75,7 +75,7 @@ const Filter& GetFilterJob::data() const
BaseJob::Status GetFilterJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<Filter>(data);
+ fromJson(data, d->data);
return Success;
}
diff --git a/lib/csapi/gtad.yaml b/lib/csapi/gtad.yaml
index cb5e553c..c6ea8a13 100644
--- a/lib/csapi/gtad.yaml
+++ b/lib/csapi/gtad.yaml
@@ -38,7 +38,7 @@ analyzer:
- number:
- float: float
- //: double
- - boolean: { type: bool, omittedValue: 'false' }
+ - boolean: bool
- string:
- byte: &ByteStream
type: QIODevice*
@@ -86,12 +86,9 @@ analyzer:
- /m\.room\.member$/:
type: "EventsArray<RoomMemberEvent>"
imports: '"events/roommemberevent.h"'
- - /state_event.yaml$/:
- type: StateEvents
- - /room_event.yaml$/:
- type: RoomEvents
- - /event.yaml$/:
- type: Events
+ - /state_event.yaml$/: StateEvents
+ - /room_event.yaml$/: RoomEvents
+ - /event.yaml$/: Events
- //: { type: "QVector<{{1}}>", imports: <QtCore/QVector> }
- map: # `additionalProperties` in OpenAPI
- RoomState:
diff --git a/lib/csapi/joining.cpp b/lib/csapi/joining.cpp
index 71781154..00d930fa 100644
--- a/lib/csapi/joining.cpp
+++ b/lib/csapi/joining.cpp
@@ -16,15 +16,16 @@ namespace QMatrixClient
{
// Converters
- QJsonObject toJson(const JoinRoomByIdJob::ThirdPartySigned& pod)
+ template <> struct JsonObjectConverter<JoinRoomByIdJob::ThirdPartySigned>
{
- QJsonObject jo;
- addParam<>(jo, QStringLiteral("sender"), pod.sender);
- addParam<>(jo, QStringLiteral("mxid"), pod.mxid);
- addParam<>(jo, QStringLiteral("token"), pod.token);
- addParam<>(jo, QStringLiteral("signatures"), pod.signatures);
- return jo;
- }
+ static void dumpTo(QJsonObject& jo, const JoinRoomByIdJob::ThirdPartySigned& pod)
+ {
+ addParam<>(jo, QStringLiteral("sender"), pod.sender);
+ addParam<>(jo, QStringLiteral("mxid"), pod.mxid);
+ addParam<>(jo, QStringLiteral("token"), pod.token);
+ addParam<>(jo, QStringLiteral("signatures"), pod.signatures);
+ }
+ };
} // namespace QMatrixClient
class JoinRoomByIdJob::Private
@@ -58,7 +59,7 @@ BaseJob::Status JoinRoomByIdJob::parseJson(const QJsonDocument& data)
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"_ls));
+ fromJson(json.value("room_id"_ls), d->roomId);
return Success;
}
@@ -66,22 +67,24 @@ namespace QMatrixClient
{
// Converters
- QJsonObject toJson(const JoinRoomJob::Signed& pod)
+ template <> struct JsonObjectConverter<JoinRoomJob::Signed>
{
- QJsonObject jo;
- addParam<>(jo, QStringLiteral("sender"), pod.sender);
- addParam<>(jo, QStringLiteral("mxid"), pod.mxid);
- addParam<>(jo, QStringLiteral("token"), pod.token);
- addParam<>(jo, QStringLiteral("signatures"), pod.signatures);
- return jo;
- }
-
- QJsonObject toJson(const JoinRoomJob::ThirdPartySigned& pod)
+ static void dumpTo(QJsonObject& jo, const JoinRoomJob::Signed& pod)
+ {
+ addParam<>(jo, QStringLiteral("sender"), pod.sender);
+ addParam<>(jo, QStringLiteral("mxid"), pod.mxid);
+ addParam<>(jo, QStringLiteral("token"), pod.token);
+ addParam<>(jo, QStringLiteral("signatures"), pod.signatures);
+ }
+ };
+
+ template <> struct JsonObjectConverter<JoinRoomJob::ThirdPartySigned>
{
- QJsonObject jo;
- addParam<>(jo, QStringLiteral("signed"), pod.signedData);
- return jo;
- }
+ static void dumpTo(QJsonObject& jo, const JoinRoomJob::ThirdPartySigned& pod)
+ {
+ addParam<>(jo, QStringLiteral("signed"), pod.signedData);
+ }
+ };
} // namespace QMatrixClient
class JoinRoomJob::Private
@@ -123,7 +126,7 @@ BaseJob::Status JoinRoomJob::parseJson(const QJsonDocument& data)
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"_ls));
+ fromJson(json.value("room_id"_ls), d->roomId);
return Success;
}
diff --git a/lib/csapi/joining.h b/lib/csapi/joining.h
index 137afbfc..52c8ea42 100644
--- a/lib/csapi/joining.h
+++ b/lib/csapi/joining.h
@@ -59,7 +59,7 @@ namespace QMatrixClient
// Result properties
- /// The joined room id
+ /// The joined room ID.
const QString& roomId() const;
protected:
@@ -138,7 +138,7 @@ namespace QMatrixClient
// Result properties
- /// The joined room id
+ /// The joined room ID.
const QString& roomId() const;
protected:
diff --git a/lib/csapi/keys.cpp b/lib/csapi/keys.cpp
index c7492411..6c16a8a3 100644
--- a/lib/csapi/keys.cpp
+++ b/lib/csapi/keys.cpp
@@ -44,7 +44,7 @@ BaseJob::Status UploadKeysJob::parseJson(const QJsonDocument& data)
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"_ls));
+ fromJson(json.value("one_time_key_counts"_ls), d->oneTimeKeyCounts);
return Success;
}
@@ -52,27 +52,20 @@ namespace QMatrixClient
{
// Converters
- template <> struct FromJsonObject<QueryKeysJob::UnsignedDeviceInfo>
+ template <> struct JsonObjectConverter<QueryKeysJob::UnsignedDeviceInfo>
{
- QueryKeysJob::UnsignedDeviceInfo operator()(const QJsonObject& jo) const
+ static void fillFrom(const QJsonObject& jo, QueryKeysJob::UnsignedDeviceInfo& result)
{
- QueryKeysJob::UnsignedDeviceInfo result;
- result.deviceDisplayName =
- fromJson<QString>(jo.value("device_display_name"_ls));
-
- return result;
+ fromJson(jo.value("device_display_name"_ls), result.deviceDisplayName);
}
};
- template <> struct FromJsonObject<QueryKeysJob::DeviceInformation>
+ template <> struct JsonObjectConverter<QueryKeysJob::DeviceInformation>
{
- QueryKeysJob::DeviceInformation operator()(const QJsonObject& jo) const
+ static void fillFrom(const QJsonObject& jo, QueryKeysJob::DeviceInformation& result)
{
- QueryKeysJob::DeviceInformation result;
- result.unsignedData =
- fromJson<QueryKeysJob::UnsignedDeviceInfo>(jo.value("unsigned"_ls));
-
- return result;
+ fillFromJson<DeviceKeys>(jo, result);
+ fromJson(jo.value("unsigned"_ls), result.unsignedData);
}
};
} // namespace QMatrixClient
@@ -113,8 +106,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"_ls));
- d->deviceKeys = fromJson<QHash<QString, QHash<QString, DeviceInformation>>>(json.value("device_keys"_ls));
+ fromJson(json.value("failures"_ls), d->failures);
+ fromJson(json.value("device_keys"_ls), d->deviceKeys);
return Success;
}
@@ -153,8 +146,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"_ls));
- d->oneTimeKeys = fromJson<QHash<QString, QHash<QString, QVariant>>>(json.value("one_time_keys"_ls));
+ fromJson(json.value("failures"_ls), d->failures);
+ fromJson(json.value("one_time_keys"_ls), d->oneTimeKeys);
return Success;
}
@@ -205,8 +198,8 @@ const QStringList& GetKeysChangesJob::left() const
BaseJob::Status GetKeysChangesJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
- d->changed = fromJson<QStringList>(json.value("changed"_ls));
- d->left = fromJson<QStringList>(json.value("left"_ls));
+ fromJson(json.value("changed"_ls), d->changed);
+ fromJson(json.value("left"_ls), d->left);
return Success;
}
diff --git a/lib/csapi/list_joined_rooms.cpp b/lib/csapi/list_joined_rooms.cpp
index a745dba1..85a9cae4 100644
--- a/lib/csapi/list_joined_rooms.cpp
+++ b/lib/csapi/list_joined_rooms.cpp
@@ -46,7 +46,7 @@ BaseJob::Status GetJoinedRoomsJob::parseJson(const QJsonDocument& data)
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"_ls));
+ fromJson(json.value("joined_rooms"_ls), d->joinedRooms);
return Success;
}
diff --git a/lib/csapi/list_public_rooms.cpp b/lib/csapi/list_public_rooms.cpp
index 2fdb2005..71b3c541 100644
--- a/lib/csapi/list_public_rooms.cpp
+++ b/lib/csapi/list_public_rooms.cpp
@@ -43,7 +43,7 @@ const QString& GetRoomVisibilityOnDirectoryJob::visibility() const
BaseJob::Status GetRoomVisibilityOnDirectoryJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
- d->visibility = fromJson<QString>(json.value("visibility"_ls));
+ fromJson(json.value("visibility"_ls), d->visibility);
return Success;
}
@@ -100,7 +100,7 @@ const PublicRoomsResponse& GetPublicRoomsJob::data() const
BaseJob::Status GetPublicRoomsJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<PublicRoomsResponse>(data);
+ fromJson(data, d->data);
return Success;
}
@@ -108,12 +108,13 @@ namespace QMatrixClient
{
// Converters
- QJsonObject toJson(const QueryPublicRoomsJob::Filter& pod)
+ template <> struct JsonObjectConverter<QueryPublicRoomsJob::Filter>
{
- QJsonObject jo;
- addParam<IfNotEmpty>(jo, QStringLiteral("generic_search_term"), pod.genericSearchTerm);
- return jo;
- }
+ static void dumpTo(QJsonObject& jo, const QueryPublicRoomsJob::Filter& pod)
+ {
+ addParam<IfNotEmpty>(jo, QStringLiteral("generic_search_term"), pod.genericSearchTerm);
+ }
+ };
} // namespace QMatrixClient
class QueryPublicRoomsJob::Private
@@ -131,7 +132,7 @@ BaseJob::Query queryToQueryPublicRooms(const QString& server)
static const auto QueryPublicRoomsJobName = QStringLiteral("QueryPublicRoomsJob");
-QueryPublicRoomsJob::QueryPublicRoomsJob(const QString& server, Omittable<int> limit, const QString& since, const Omittable<Filter>& filter, bool includeAllNetworks, const QString& thirdPartyInstanceId)
+QueryPublicRoomsJob::QueryPublicRoomsJob(const QString& server, Omittable<int> limit, const QString& since, const Omittable<Filter>& filter, Omittable<bool> includeAllNetworks, const QString& thirdPartyInstanceId)
: BaseJob(HttpVerb::Post, QueryPublicRoomsJobName,
basePath % "/publicRooms",
queryToQueryPublicRooms(server))
@@ -155,7 +156,7 @@ const PublicRoomsResponse& QueryPublicRoomsJob::data() const
BaseJob::Status QueryPublicRoomsJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<PublicRoomsResponse>(data);
+ fromJson(data, d->data);
return Success;
}
diff --git a/lib/csapi/list_public_rooms.h b/lib/csapi/list_public_rooms.h
index 8401c134..a6498745 100644
--- a/lib/csapi/list_public_rooms.h
+++ b/lib/csapi/list_public_rooms.h
@@ -156,7 +156,7 @@ namespace QMatrixClient
* The specific third party network/protocol to request from the
* homeserver. Can only be used if ``include_all_networks`` is false.
*/
- explicit QueryPublicRoomsJob(const QString& server = {}, Omittable<int> limit = none, const QString& since = {}, const Omittable<Filter>& filter = none, bool includeAllNetworks = false, const QString& thirdPartyInstanceId = {});
+ explicit QueryPublicRoomsJob(const QString& server = {}, Omittable<int> limit = none, const QString& since = {}, const Omittable<Filter>& filter = none, Omittable<bool> includeAllNetworks = none, const QString& thirdPartyInstanceId = {});
~QueryPublicRoomsJob() override;
// Result properties
diff --git a/lib/csapi/login.cpp b/lib/csapi/login.cpp
index 4d15a30b..ee33dac2 100644
--- a/lib/csapi/login.cpp
+++ b/lib/csapi/login.cpp
@@ -16,15 +16,11 @@ namespace QMatrixClient
{
// Converters
- template <> struct FromJsonObject<GetLoginFlowsJob::LoginFlow>
+ template <> struct JsonObjectConverter<GetLoginFlowsJob::LoginFlow>
{
- GetLoginFlowsJob::LoginFlow operator()(const QJsonObject& jo) const
+ static void fillFrom(const QJsonObject& jo, GetLoginFlowsJob::LoginFlow& result)
{
- GetLoginFlowsJob::LoginFlow result;
- result.type =
- fromJson<QString>(jo.value("type"_ls));
-
- return result;
+ fromJson(jo.value("type"_ls), result.type);
}
};
} // namespace QMatrixClient
@@ -60,7 +56,7 @@ const QVector<GetLoginFlowsJob::LoginFlow>& GetLoginFlowsJob::flows() const
BaseJob::Status GetLoginFlowsJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
- d->flows = fromJson<QVector<LoginFlow>>(json.value("flows"_ls));
+ fromJson(json.value("flows"_ls), d->flows);
return Success;
}
@@ -118,10 +114,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"_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));
+ fromJson(json.value("user_id"_ls), d->userId);
+ fromJson(json.value("access_token"_ls), d->accessToken);
+ fromJson(json.value("home_server"_ls), d->homeServer);
+ fromJson(json.value("device_id"_ls), d->deviceId);
return Success;
}
diff --git a/lib/csapi/message_pagination.cpp b/lib/csapi/message_pagination.cpp
index c59a51ab..9aca7ec9 100644
--- a/lib/csapi/message_pagination.cpp
+++ b/lib/csapi/message_pagination.cpp
@@ -68,9 +68,9 @@ RoomEvents&& GetRoomEventsJob::chunk()
BaseJob::Status GetRoomEventsJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
- d->begin = fromJson<QString>(json.value("start"_ls));
- d->end = fromJson<QString>(json.value("end"_ls));
- d->chunk = fromJson<RoomEvents>(json.value("chunk"_ls));
+ fromJson(json.value("start"_ls), d->begin);
+ fromJson(json.value("end"_ls), d->end);
+ fromJson(json.value("chunk"_ls), d->chunk);
return Success;
}
diff --git a/lib/csapi/notifications.cpp b/lib/csapi/notifications.cpp
index 785a0a8a..c00b7cb0 100644
--- a/lib/csapi/notifications.cpp
+++ b/lib/csapi/notifications.cpp
@@ -16,25 +16,16 @@ namespace QMatrixClient
{
// Converters
- template <> struct FromJsonObject<GetNotificationsJob::Notification>
+ template <> struct JsonObjectConverter<GetNotificationsJob::Notification>
{
- GetNotificationsJob::Notification operator()(const QJsonObject& jo) const
+ static void fillFrom(const QJsonObject& jo, GetNotificationsJob::Notification& result)
{
- GetNotificationsJob::Notification result;
- result.actions =
- fromJson<QVector<QVariant>>(jo.value("actions"_ls));
- result.event =
- fromJson<EventPtr>(jo.value("event"_ls));
- result.profileTag =
- fromJson<QString>(jo.value("profile_tag"_ls));
- result.read =
- fromJson<bool>(jo.value("read"_ls));
- result.roomId =
- fromJson<QString>(jo.value("room_id"_ls));
- result.ts =
- fromJson<int>(jo.value("ts"_ls));
-
- return result;
+ fromJson(jo.value("actions"_ls), result.actions);
+ fromJson(jo.value("event"_ls), result.event);
+ fromJson(jo.value("profile_tag"_ls), result.profileTag);
+ fromJson(jo.value("read"_ls), result.read);
+ fromJson(jo.value("room_id"_ls), result.roomId);
+ fromJson(jo.value("ts"_ls), result.ts);
}
};
} // namespace QMatrixClient
@@ -87,11 +78,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"_ls));
+ fromJson(json.value("next_token"_ls), d->nextToken);
if (!json.contains("notifications"_ls))
return { JsonParseError,
"The key 'notifications' not found in the response" };
- d->notifications = fromJson<std::vector<Notification>>(json.value("notifications"_ls));
+ fromJson(json.value("notifications"_ls), d->notifications);
return Success;
}
diff --git a/lib/csapi/openid.cpp b/lib/csapi/openid.cpp
index 2547f0c8..b27fe0b8 100644
--- a/lib/csapi/openid.cpp
+++ b/lib/csapi/openid.cpp
@@ -59,19 +59,19 @@ BaseJob::Status RequestOpenIdTokenJob::parseJson(const QJsonDocument& data)
if (!json.contains("access_token"_ls))
return { JsonParseError,
"The key 'access_token' not found in the response" };
- d->accessToken = fromJson<QString>(json.value("access_token"_ls));
+ fromJson(json.value("access_token"_ls), d->accessToken);
if (!json.contains("token_type"_ls))
return { JsonParseError,
"The key 'token_type' not found in the response" };
- d->tokenType = fromJson<QString>(json.value("token_type"_ls));
+ fromJson(json.value("token_type"_ls), d->tokenType);
if (!json.contains("matrix_server_name"_ls))
return { JsonParseError,
"The key 'matrix_server_name' not found in the response" };
- d->matrixServerName = fromJson<QString>(json.value("matrix_server_name"_ls));
+ fromJson(json.value("matrix_server_name"_ls), d->matrixServerName);
if (!json.contains("expires_in"_ls))
return { JsonParseError,
"The key 'expires_in' not found in the response" };
- d->expiresIn = fromJson<int>(json.value("expires_in"_ls));
+ fromJson(json.value("expires_in"_ls), d->expiresIn);
return Success;
}
diff --git a/lib/csapi/peeking_events.cpp b/lib/csapi/peeking_events.cpp
index e046a62e..3208d48d 100644
--- a/lib/csapi/peeking_events.cpp
+++ b/lib/csapi/peeking_events.cpp
@@ -66,9 +66,9 @@ RoomEvents&& PeekEventsJob::chunk()
BaseJob::Status PeekEventsJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
- d->begin = fromJson<QString>(json.value("start"_ls));
- d->end = fromJson<QString>(json.value("end"_ls));
- d->chunk = fromJson<RoomEvents>(json.value("chunk"_ls));
+ fromJson(json.value("start"_ls), d->begin);
+ fromJson(json.value("end"_ls), d->end);
+ fromJson(json.value("chunk"_ls), d->chunk);
return Success;
}
diff --git a/lib/csapi/presence.cpp b/lib/csapi/presence.cpp
index 7aba8b61..8a5510b8 100644
--- a/lib/csapi/presence.cpp
+++ b/lib/csapi/presence.cpp
@@ -30,7 +30,7 @@ class GetPresenceJob::Private
QString presence;
Omittable<int> lastActiveAgo;
QString statusMsg;
- bool currentlyActive;
+ Omittable<bool> currentlyActive;
};
QUrl GetPresenceJob::makeRequestUrl(QUrl baseUrl, const QString& userId)
@@ -65,7 +65,7 @@ const QString& GetPresenceJob::statusMsg() const
return d->statusMsg;
}
-bool GetPresenceJob::currentlyActive() const
+Omittable<bool> GetPresenceJob::currentlyActive() const
{
return d->currentlyActive;
}
@@ -76,10 +76,10 @@ BaseJob::Status GetPresenceJob::parseJson(const QJsonDocument& data)
if (!json.contains("presence"_ls))
return { JsonParseError,
"The key 'presence' not found in the response" };
- 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));
+ fromJson(json.value("presence"_ls), d->presence);
+ fromJson(json.value("last_active_ago"_ls), d->lastActiveAgo);
+ fromJson(json.value("status_msg"_ls), d->statusMsg);
+ fromJson(json.value("currently_active"_ls), d->currentlyActive);
return Success;
}
@@ -125,7 +125,7 @@ Events&& GetPresenceForListJob::data()
BaseJob::Status GetPresenceForListJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<Events>(data);
+ fromJson(data, d->data);
return Success;
}
diff --git a/lib/csapi/presence.h b/lib/csapi/presence.h
index 86b9d395..c8f80357 100644
--- a/lib/csapi/presence.h
+++ b/lib/csapi/presence.h
@@ -65,7 +65,7 @@ namespace QMatrixClient
/// The state message for this user if one was set.
const QString& statusMsg() const;
/// Whether the user is currently active
- bool currentlyActive() const;
+ Omittable<bool> currentlyActive() const;
protected:
Status parseJson(const QJsonDocument& data) override;
diff --git a/lib/csapi/profile.cpp b/lib/csapi/profile.cpp
index bb053062..4ed3ad9b 100644
--- a/lib/csapi/profile.cpp
+++ b/lib/csapi/profile.cpp
@@ -54,7 +54,7 @@ const QString& GetDisplayNameJob::displayname() const
BaseJob::Status GetDisplayNameJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
- d->displayname = fromJson<QString>(json.value("displayname"_ls));
+ fromJson(json.value("displayname"_ls), d->displayname);
return Success;
}
@@ -100,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"_ls));
+ fromJson(json.value("avatar_url"_ls), d->avatarUrl);
return Success;
}
@@ -141,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"_ls));
- d->displayname = fromJson<QString>(json.value("displayname"_ls));
+ fromJson(json.value("avatar_url"_ls), d->avatarUrl);
+ fromJson(json.value("displayname"_ls), d->displayname);
return Success;
}
diff --git a/lib/csapi/pusher.cpp b/lib/csapi/pusher.cpp
index d20db88a..664959f4 100644
--- a/lib/csapi/pusher.cpp
+++ b/lib/csapi/pusher.cpp
@@ -16,43 +16,27 @@ namespace QMatrixClient
{
// Converters
- template <> struct FromJsonObject<GetPushersJob::PusherData>
+ template <> struct JsonObjectConverter<GetPushersJob::PusherData>
{
- GetPushersJob::PusherData operator()(const QJsonObject& jo) const
+ static void fillFrom(const QJsonObject& jo, GetPushersJob::PusherData& result)
{
- GetPushersJob::PusherData result;
- result.url =
- fromJson<QString>(jo.value("url"_ls));
- result.format =
- fromJson<QString>(jo.value("format"_ls));
-
- return result;
+ fromJson(jo.value("url"_ls), result.url);
+ fromJson(jo.value("format"_ls), result.format);
}
};
- template <> struct FromJsonObject<GetPushersJob::Pusher>
+ template <> struct JsonObjectConverter<GetPushersJob::Pusher>
{
- GetPushersJob::Pusher operator()(const QJsonObject& jo) const
+ static void fillFrom(const QJsonObject& jo, GetPushersJob::Pusher& result)
{
- GetPushersJob::Pusher result;
- result.pushkey =
- fromJson<QString>(jo.value("pushkey"_ls));
- result.kind =
- fromJson<QString>(jo.value("kind"_ls));
- result.appId =
- fromJson<QString>(jo.value("app_id"_ls));
- result.appDisplayName =
- fromJson<QString>(jo.value("app_display_name"_ls));
- result.deviceDisplayName =
- fromJson<QString>(jo.value("device_display_name"_ls));
- result.profileTag =
- fromJson<QString>(jo.value("profile_tag"_ls));
- result.lang =
- fromJson<QString>(jo.value("lang"_ls));
- result.data =
- fromJson<GetPushersJob::PusherData>(jo.value("data"_ls));
-
- return result;
+ fromJson(jo.value("pushkey"_ls), result.pushkey);
+ fromJson(jo.value("kind"_ls), result.kind);
+ fromJson(jo.value("app_id"_ls), result.appId);
+ fromJson(jo.value("app_display_name"_ls), result.appDisplayName);
+ fromJson(jo.value("device_display_name"_ls), result.deviceDisplayName);
+ fromJson(jo.value("profile_tag"_ls), result.profileTag);
+ fromJson(jo.value("lang"_ls), result.lang);
+ fromJson(jo.value("data"_ls), result.data);
}
};
} // namespace QMatrixClient
@@ -88,7 +72,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"_ls));
+ fromJson(json.value("pushers"_ls), d->pushers);
return Success;
}
@@ -96,18 +80,19 @@ namespace QMatrixClient
{
// Converters
- QJsonObject toJson(const PostPusherJob::PusherData& pod)
+ template <> struct JsonObjectConverter<PostPusherJob::PusherData>
{
- QJsonObject jo;
- addParam<IfNotEmpty>(jo, QStringLiteral("url"), pod.url);
- addParam<IfNotEmpty>(jo, QStringLiteral("format"), pod.format);
- return jo;
- }
+ static void dumpTo(QJsonObject& jo, const PostPusherJob::PusherData& pod)
+ {
+ addParam<IfNotEmpty>(jo, QStringLiteral("url"), pod.url);
+ addParam<IfNotEmpty>(jo, QStringLiteral("format"), pod.format);
+ }
+ };
} // 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)
+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, Omittable<bool> append)
: BaseJob(HttpVerb::Post, PostPusherJobName,
basePath % "/pushers/set")
{
diff --git a/lib/csapi/pusher.h b/lib/csapi/pusher.h
index 2b506183..da3303fe 100644
--- a/lib/csapi/pusher.h
+++ b/lib/csapi/pusher.h
@@ -164,6 +164,6 @@ namespace QMatrixClient
* other pushers with the same App ID and pushkey for different
* users. The default is ``false``.
*/
- explicit 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 = false);
+ explicit 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 = {}, Omittable<bool> append = none);
};
} // namespace QMatrixClient
diff --git a/lib/csapi/pushrules.cpp b/lib/csapi/pushrules.cpp
index ea8ad02a..b91d18f7 100644
--- a/lib/csapi/pushrules.cpp
+++ b/lib/csapi/pushrules.cpp
@@ -46,7 +46,7 @@ BaseJob::Status GetPushRulesJob::parseJson(const QJsonDocument& data)
if (!json.contains("global"_ls))
return { JsonParseError,
"The key 'global' not found in the response" };
- d->global = fromJson<PushRuleset>(json.value("global"_ls));
+ fromJson(json.value("global"_ls), d->global);
return Success;
}
@@ -80,7 +80,7 @@ const PushRule& GetPushRuleJob::data() const
BaseJob::Status GetPushRuleJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<PushRule>(data);
+ fromJson(data, d->data);
return Success;
}
@@ -154,7 +154,7 @@ BaseJob::Status IsPushRuleEnabledJob::parseJson(const QJsonDocument& data)
if (!json.contains("enabled"_ls))
return { JsonParseError,
"The key 'enabled' not found in the response" };
- d->enabled = fromJson<bool>(json.value("enabled"_ls));
+ fromJson(json.value("enabled"_ls), d->enabled);
return Success;
}
@@ -203,7 +203,7 @@ BaseJob::Status GetPushRuleActionsJob::parseJson(const QJsonDocument& data)
if (!json.contains("actions"_ls))
return { JsonParseError,
"The key 'actions' not found in the response" };
- d->actions = fromJson<QStringList>(json.value("actions"_ls));
+ fromJson(json.value("actions"_ls), d->actions);
return Success;
}
diff --git a/lib/csapi/redaction.cpp b/lib/csapi/redaction.cpp
index 64098670..1d54e36d 100644
--- a/lib/csapi/redaction.cpp
+++ b/lib/csapi/redaction.cpp
@@ -40,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"_ls));
+ fromJson(json.value("event_id"_ls), d->eventId);
return Success;
}
diff --git a/lib/csapi/registration.cpp b/lib/csapi/registration.cpp
index 320ec796..5dc9c1e5 100644
--- a/lib/csapi/registration.cpp
+++ b/lib/csapi/registration.cpp
@@ -30,7 +30,7 @@ BaseJob::Query queryToRegister(const QString& kind)
static const auto RegisterJobName = QStringLiteral("RegisterJob");
-RegisterJob::RegisterJob(const QString& kind, const Omittable<AuthenticationData>& auth, bool bindEmail, const QString& username, const QString& password, const QString& deviceId, const QString& initialDeviceDisplayName, bool inhibitLogin)
+RegisterJob::RegisterJob(const QString& kind, const Omittable<AuthenticationData>& auth, Omittable<bool> bindEmail, const QString& username, const QString& password, const QString& deviceId, const QString& initialDeviceDisplayName, Omittable<bool> inhibitLogin)
: BaseJob(HttpVerb::Post, RegisterJobName,
basePath % "/register",
queryToRegister(kind),
@@ -76,10 +76,10 @@ BaseJob::Status RegisterJob::parseJson(const QJsonDocument& data)
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"_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));
+ fromJson(json.value("user_id"_ls), d->userId);
+ fromJson(json.value("access_token"_ls), d->accessToken);
+ fromJson(json.value("home_server"_ls), d->homeServer);
+ fromJson(json.value("device_id"_ls), d->deviceId);
return Success;
}
@@ -114,7 +114,7 @@ const Sid& RequestTokenToRegisterEmailJob::data() const
BaseJob::Status RequestTokenToRegisterEmailJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<Sid>(data);
+ fromJson(data, d->data);
return Success;
}
@@ -150,7 +150,7 @@ const Sid& RequestTokenToRegisterMSISDNJob::data() const
BaseJob::Status RequestTokenToRegisterMSISDNJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<Sid>(data);
+ fromJson(data, d->data);
return Success;
}
@@ -197,7 +197,7 @@ const Sid& RequestTokenToResetPasswordEmailJob::data() const
BaseJob::Status RequestTokenToResetPasswordEmailJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<Sid>(data);
+ fromJson(data, d->data);
return Success;
}
@@ -233,7 +233,7 @@ const Sid& RequestTokenToResetPasswordMSISDNJob::data() const
BaseJob::Status RequestTokenToResetPasswordMSISDNJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<Sid>(data);
+ fromJson(data, d->data);
return Success;
}
@@ -251,7 +251,7 @@ DeactivateAccountJob::DeactivateAccountJob(const Omittable<AuthenticationData>&
class CheckUsernameAvailabilityJob::Private
{
public:
- bool available;
+ Omittable<bool> available;
};
BaseJob::Query queryToCheckUsernameAvailability(const QString& username)
@@ -281,7 +281,7 @@ CheckUsernameAvailabilityJob::CheckUsernameAvailabilityJob(const QString& userna
CheckUsernameAvailabilityJob::~CheckUsernameAvailabilityJob() = default;
-bool CheckUsernameAvailabilityJob::available() const
+Omittable<bool> CheckUsernameAvailabilityJob::available() const
{
return d->available;
}
@@ -289,7 +289,7 @@ bool CheckUsernameAvailabilityJob::available() const
BaseJob::Status CheckUsernameAvailabilityJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
- d->available = fromJson<bool>(json.value("available"_ls));
+ fromJson(json.value("available"_ls), d->available);
return Success;
}
diff --git a/lib/csapi/registration.h b/lib/csapi/registration.h
index 9002b5c8..ca1a1c21 100644
--- a/lib/csapi/registration.h
+++ b/lib/csapi/registration.h
@@ -80,7 +80,7 @@ namespace QMatrixClient
* returned from this call, therefore preventing an automatic
* login. Defaults to false.
*/
- explicit RegisterJob(const QString& kind = QStringLiteral("user"), const Omittable<AuthenticationData>& auth = none, bool bindEmail = false, const QString& username = {}, const QString& password = {}, const QString& deviceId = {}, const QString& initialDeviceDisplayName = {}, bool inhibitLogin = false);
+ explicit RegisterJob(const QString& kind = QStringLiteral("user"), const Omittable<AuthenticationData>& auth = none, Omittable<bool> bindEmail = none, const QString& username = {}, const QString& password = {}, const QString& deviceId = {}, const QString& initialDeviceDisplayName = {}, Omittable<bool> inhibitLogin = none);
~RegisterJob() override;
// Result properties
@@ -418,7 +418,7 @@ namespace QMatrixClient
/// A flag to indicate that the username is available. This should always
/// be ``true`` when the server replies with 200 OK.
- bool available() const;
+ Omittable<bool> available() const;
protected:
Status parseJson(const QJsonDocument& data) override;
diff --git a/lib/csapi/room_send.cpp b/lib/csapi/room_send.cpp
index 2b39ede2..0d25eb69 100644
--- a/lib/csapi/room_send.cpp
+++ b/lib/csapi/room_send.cpp
@@ -38,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"_ls));
+ fromJson(json.value("event_id"_ls), d->eventId);
return Success;
}
diff --git a/lib/csapi/room_state.cpp b/lib/csapi/room_state.cpp
index 8f87979d..3aa7d736 100644
--- a/lib/csapi/room_state.cpp
+++ b/lib/csapi/room_state.cpp
@@ -38,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"_ls));
+ fromJson(json.value("event_id"_ls), d->eventId);
return Success;
}
@@ -68,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"_ls));
+ fromJson(json.value("event_id"_ls), d->eventId);
return Success;
}
diff --git a/lib/csapi/rooms.cpp b/lib/csapi/rooms.cpp
index cebb295a..0b08ccec 100644
--- a/lib/csapi/rooms.cpp
+++ b/lib/csapi/rooms.cpp
@@ -42,7 +42,7 @@ EventPtr&& GetOneRoomEventJob::data()
BaseJob::Status GetOneRoomEventJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<EventPtr>(data);
+ fromJson(data, d->data);
return Success;
}
@@ -104,7 +104,7 @@ StateEvents&& GetRoomStateJob::data()
BaseJob::Status GetRoomStateJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<StateEvents>(data);
+ fromJson(data, d->data);
return Success;
}
@@ -114,17 +114,28 @@ class GetMembersByRoomJob::Private
EventsArray<RoomMemberEvent> chunk;
};
-QUrl GetMembersByRoomJob::makeRequestUrl(QUrl baseUrl, const QString& roomId)
+BaseJob::Query queryToGetMembersByRoom(const QString& at, const QString& membership, const QString& notMembership)
+{
+ BaseJob::Query _q;
+ addParam<IfNotEmpty>(_q, QStringLiteral("at"), at);
+ addParam<IfNotEmpty>(_q, QStringLiteral("membership"), membership);
+ addParam<IfNotEmpty>(_q, QStringLiteral("not_membership"), notMembership);
+ return _q;
+}
+
+QUrl GetMembersByRoomJob::makeRequestUrl(QUrl baseUrl, const QString& roomId, const QString& at, const QString& membership, const QString& notMembership)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/rooms/" % roomId % "/members");
+ basePath % "/rooms/" % roomId % "/members",
+ queryToGetMembersByRoom(at, membership, notMembership));
}
static const auto GetMembersByRoomJobName = QStringLiteral("GetMembersByRoomJob");
-GetMembersByRoomJob::GetMembersByRoomJob(const QString& roomId)
+GetMembersByRoomJob::GetMembersByRoomJob(const QString& roomId, const QString& at, const QString& membership, const QString& notMembership)
: BaseJob(HttpVerb::Get, GetMembersByRoomJobName,
- basePath % "/rooms/" % roomId % "/members")
+ basePath % "/rooms/" % roomId % "/members",
+ queryToGetMembersByRoom(at, membership, notMembership))
, d(new Private)
{
}
@@ -139,7 +150,7 @@ EventsArray<RoomMemberEvent>&& GetMembersByRoomJob::chunk()
BaseJob::Status GetMembersByRoomJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
- d->chunk = fromJson<EventsArray<RoomMemberEvent>>(json.value("chunk"_ls));
+ fromJson(json.value("chunk"_ls), d->chunk);
return Success;
}
@@ -147,17 +158,12 @@ namespace QMatrixClient
{
// Converters
- template <> struct FromJsonObject<GetJoinedMembersByRoomJob::RoomMember>
+ template <> struct JsonObjectConverter<GetJoinedMembersByRoomJob::RoomMember>
{
- GetJoinedMembersByRoomJob::RoomMember operator()(const QJsonObject& jo) const
+ static void fillFrom(const QJsonObject& jo, GetJoinedMembersByRoomJob::RoomMember& result)
{
- GetJoinedMembersByRoomJob::RoomMember result;
- result.displayName =
- fromJson<QString>(jo.value("display_name"_ls));
- result.avatarUrl =
- fromJson<QString>(jo.value("avatar_url"_ls));
-
- return result;
+ fromJson(jo.value("display_name"_ls), result.displayName);
+ fromJson(jo.value("avatar_url"_ls), result.avatarUrl);
}
};
} // namespace QMatrixClient
@@ -193,7 +199,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"_ls));
+ fromJson(json.value("joined"_ls), d->joined);
return Success;
}
diff --git a/lib/csapi/rooms.h b/lib/csapi/rooms.h
index 80895b4e..b4d3d9b6 100644
--- a/lib/csapi/rooms.h
+++ b/lib/csapi/rooms.h
@@ -158,8 +158,17 @@ namespace QMatrixClient
/*! Get the m.room.member events for the room.
* \param roomId
* The room to get the member events for.
+ * \param at
+ * The token defining the timeline position as-of which to return
+ * the list of members. This token can be obtained from a batch token
+ * returned for each room by the sync API, or from
+ * a ``start``/``end`` token returned by a ``/messages`` request.
+ * \param membership
+ * Only return users with the specified membership
+ * \param notMembership
+ * Only return users with membership state other than specified
*/
- explicit GetMembersByRoomJob(const QString& roomId);
+ explicit GetMembersByRoomJob(const QString& roomId, const QString& at = {}, const QString& membership = {}, const QString& notMembership = {});
/*! Construct a URL without creating a full-fledged job object
*
@@ -167,7 +176,7 @@ namespace QMatrixClient
* GetMembersByRoomJob is necessary but the job
* itself isn't.
*/
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId);
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId, const QString& at = {}, const QString& membership = {}, const QString& notMembership = {});
~GetMembersByRoomJob() override;
diff --git a/lib/csapi/search.cpp b/lib/csapi/search.cpp
index 9436eb47..a5f83c79 100644
--- a/lib/csapi/search.cpp
+++ b/lib/csapi/search.cpp
@@ -16,146 +16,113 @@ namespace QMatrixClient
{
// Converters
- QJsonObject toJson(const SearchJob::IncludeEventContext& pod)
+ template <> struct JsonObjectConverter<SearchJob::IncludeEventContext>
{
- QJsonObject jo;
- addParam<IfNotEmpty>(jo, QStringLiteral("before_limit"), pod.beforeLimit);
- addParam<IfNotEmpty>(jo, QStringLiteral("after_limit"), pod.afterLimit);
- addParam<IfNotEmpty>(jo, QStringLiteral("include_profile"), pod.includeProfile);
- return jo;
- }
-
- QJsonObject toJson(const SearchJob::Group& pod)
- {
- QJsonObject jo;
- addParam<IfNotEmpty>(jo, QStringLiteral("key"), pod.key);
- return jo;
- }
+ static void dumpTo(QJsonObject& jo, const SearchJob::IncludeEventContext& pod)
+ {
+ addParam<IfNotEmpty>(jo, QStringLiteral("before_limit"), pod.beforeLimit);
+ addParam<IfNotEmpty>(jo, QStringLiteral("after_limit"), pod.afterLimit);
+ addParam<IfNotEmpty>(jo, QStringLiteral("include_profile"), pod.includeProfile);
+ }
+ };
- QJsonObject toJson(const SearchJob::Groupings& pod)
+ template <> struct JsonObjectConverter<SearchJob::Group>
{
- QJsonObject jo;
- addParam<IfNotEmpty>(jo, QStringLiteral("group_by"), pod.groupBy);
- return jo;
- }
+ static void dumpTo(QJsonObject& jo, const SearchJob::Group& pod)
+ {
+ addParam<IfNotEmpty>(jo, QStringLiteral("key"), pod.key);
+ }
+ };
- QJsonObject toJson(const SearchJob::RoomEventsCriteria& pod)
- {
- QJsonObject jo;
- addParam<>(jo, QStringLiteral("search_term"), pod.searchTerm);
- addParam<IfNotEmpty>(jo, QStringLiteral("keys"), pod.keys);
- addParam<IfNotEmpty>(jo, QStringLiteral("filter"), pod.filter);
- addParam<IfNotEmpty>(jo, QStringLiteral("order_by"), pod.orderBy);
- addParam<IfNotEmpty>(jo, QStringLiteral("event_context"), pod.eventContext);
- addParam<IfNotEmpty>(jo, QStringLiteral("include_state"), pod.includeState);
- addParam<IfNotEmpty>(jo, QStringLiteral("groupings"), pod.groupings);
- return jo;
- }
-
- QJsonObject toJson(const SearchJob::Categories& pod)
+ template <> struct JsonObjectConverter<SearchJob::Groupings>
{
- QJsonObject jo;
- addParam<IfNotEmpty>(jo, QStringLiteral("room_events"), pod.roomEvents);
- return jo;
- }
+ static void dumpTo(QJsonObject& jo, const SearchJob::Groupings& pod)
+ {
+ addParam<IfNotEmpty>(jo, QStringLiteral("group_by"), pod.groupBy);
+ }
+ };
- template <> struct FromJsonObject<SearchJob::UserProfile>
+ template <> struct JsonObjectConverter<SearchJob::RoomEventsCriteria>
{
- SearchJob::UserProfile operator()(const QJsonObject& jo) const
+ static void dumpTo(QJsonObject& jo, const SearchJob::RoomEventsCriteria& pod)
{
- SearchJob::UserProfile result;
- result.displayname =
- fromJson<QString>(jo.value("displayname"_ls));
- result.avatarUrl =
- fromJson<QString>(jo.value("avatar_url"_ls));
+ addParam<>(jo, QStringLiteral("search_term"), pod.searchTerm);
+ addParam<IfNotEmpty>(jo, QStringLiteral("keys"), pod.keys);
+ addParam<IfNotEmpty>(jo, QStringLiteral("filter"), pod.filter);
+ addParam<IfNotEmpty>(jo, QStringLiteral("order_by"), pod.orderBy);
+ addParam<IfNotEmpty>(jo, QStringLiteral("event_context"), pod.eventContext);
+ addParam<IfNotEmpty>(jo, QStringLiteral("include_state"), pod.includeState);
+ addParam<IfNotEmpty>(jo, QStringLiteral("groupings"), pod.groupings);
+ }
+ };
- return result;
+ template <> struct JsonObjectConverter<SearchJob::Categories>
+ {
+ static void dumpTo(QJsonObject& jo, const SearchJob::Categories& pod)
+ {
+ addParam<IfNotEmpty>(jo, QStringLiteral("room_events"), pod.roomEvents);
}
};
- template <> struct FromJsonObject<SearchJob::EventContext>
+ template <> struct JsonObjectConverter<SearchJob::UserProfile>
{
- SearchJob::EventContext operator()(const QJsonObject& jo) const
+ static void fillFrom(const QJsonObject& jo, SearchJob::UserProfile& result)
{
- SearchJob::EventContext result;
- result.begin =
- fromJson<QString>(jo.value("start"_ls));
- result.end =
- fromJson<QString>(jo.value("end"_ls));
- result.profileInfo =
- fromJson<QHash<QString, SearchJob::UserProfile>>(jo.value("profile_info"_ls));
- result.eventsBefore =
- fromJson<RoomEvents>(jo.value("events_before"_ls));
- result.eventsAfter =
- fromJson<RoomEvents>(jo.value("events_after"_ls));
-
- return result;
+ fromJson(jo.value("displayname"_ls), result.displayname);
+ fromJson(jo.value("avatar_url"_ls), result.avatarUrl);
}
};
- template <> struct FromJsonObject<SearchJob::Result>
+ template <> struct JsonObjectConverter<SearchJob::EventContext>
{
- SearchJob::Result operator()(const QJsonObject& jo) const
+ static void fillFrom(const QJsonObject& jo, SearchJob::EventContext& result)
{
- SearchJob::Result result;
- result.rank =
- fromJson<double>(jo.value("rank"_ls));
- result.result =
- fromJson<RoomEventPtr>(jo.value("result"_ls));
- result.context =
- fromJson<SearchJob::EventContext>(jo.value("context"_ls));
-
- return result;
+ fromJson(jo.value("start"_ls), result.begin);
+ fromJson(jo.value("end"_ls), result.end);
+ fromJson(jo.value("profile_info"_ls), result.profileInfo);
+ fromJson(jo.value("events_before"_ls), result.eventsBefore);
+ fromJson(jo.value("events_after"_ls), result.eventsAfter);
}
};
- template <> struct FromJsonObject<SearchJob::GroupValue>
+ template <> struct JsonObjectConverter<SearchJob::Result>
{
- SearchJob::GroupValue operator()(const QJsonObject& jo) const
+ static void fillFrom(const QJsonObject& jo, SearchJob::Result& result)
{
- SearchJob::GroupValue result;
- result.nextBatch =
- fromJson<QString>(jo.value("next_batch"_ls));
- result.order =
- fromJson<int>(jo.value("order"_ls));
- result.results =
- fromJson<QStringList>(jo.value("results"_ls));
-
- return result;
+ fromJson(jo.value("rank"_ls), result.rank);
+ fromJson(jo.value("result"_ls), result.result);
+ fromJson(jo.value("context"_ls), result.context);
}
};
- template <> struct FromJsonObject<SearchJob::ResultRoomEvents>
+ template <> struct JsonObjectConverter<SearchJob::GroupValue>
{
- SearchJob::ResultRoomEvents operator()(const QJsonObject& jo) const
+ static void fillFrom(const QJsonObject& jo, SearchJob::GroupValue& result)
{
- SearchJob::ResultRoomEvents result;
- result.count =
- fromJson<int>(jo.value("count"_ls));
- result.highlights =
- fromJson<QStringList>(jo.value("highlights"_ls));
- result.results =
- fromJson<std::vector<SearchJob::Result>>(jo.value("results"_ls));
- result.state =
- fromJson<std::unordered_map<QString, StateEvents>>(jo.value("state"_ls));
- result.groups =
- fromJson<QHash<QString, QHash<QString, SearchJob::GroupValue>>>(jo.value("groups"_ls));
- result.nextBatch =
- fromJson<QString>(jo.value("next_batch"_ls));
-
- return result;
+ fromJson(jo.value("next_batch"_ls), result.nextBatch);
+ fromJson(jo.value("order"_ls), result.order);
+ fromJson(jo.value("results"_ls), result.results);
}
};
- template <> struct FromJsonObject<SearchJob::ResultCategories>
+ template <> struct JsonObjectConverter<SearchJob::ResultRoomEvents>
{
- SearchJob::ResultCategories operator()(const QJsonObject& jo) const
+ static void fillFrom(const QJsonObject& jo, SearchJob::ResultRoomEvents& result)
{
- SearchJob::ResultCategories result;
- result.roomEvents =
- fromJson<SearchJob::ResultRoomEvents>(jo.value("room_events"_ls));
+ fromJson(jo.value("count"_ls), result.count);
+ fromJson(jo.value("highlights"_ls), result.highlights);
+ fromJson(jo.value("results"_ls), result.results);
+ fromJson(jo.value("state"_ls), result.state);
+ fromJson(jo.value("groups"_ls), result.groups);
+ fromJson(jo.value("next_batch"_ls), result.nextBatch);
+ }
+ };
- return result;
+ template <> struct JsonObjectConverter<SearchJob::ResultCategories>
+ {
+ static void fillFrom(const QJsonObject& jo, SearchJob::ResultCategories& result)
+ {
+ fromJson(jo.value("room_events"_ls), result.roomEvents);
}
};
} // namespace QMatrixClient
@@ -199,7 +166,7 @@ BaseJob::Status SearchJob::parseJson(const QJsonDocument& data)
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"_ls));
+ fromJson(json.value("search_categories"_ls), d->searchCategories);
return Success;
}
diff --git a/lib/csapi/search.h b/lib/csapi/search.h
index 85b0886b..86a0ee92 100644
--- a/lib/csapi/search.h
+++ b/lib/csapi/search.h
@@ -39,7 +39,7 @@ namespace QMatrixClient
/// historic profile information for the users
/// that sent the events that were returned.
/// By default, this is ``false``.
- bool includeProfile;
+ Omittable<bool> includeProfile;
};
/// Configuration for group.
@@ -74,7 +74,7 @@ namespace QMatrixClient
Omittable<IncludeEventContext> eventContext;
/// Requests the server return the current state for
/// each room returned.
- bool includeState;
+ Omittable<bool> includeState;
/// Requests that the server partitions the result set
/// based on the provided list of keys.
Omittable<Groupings> groupings;
diff --git a/lib/csapi/tags.cpp b/lib/csapi/tags.cpp
index 808915ac..94026bb9 100644
--- a/lib/csapi/tags.cpp
+++ b/lib/csapi/tags.cpp
@@ -16,16 +16,12 @@ namespace QMatrixClient
{
// Converters
- template <> struct FromJsonObject<GetRoomTagsJob::Tag>
+ template <> struct JsonObjectConverter<GetRoomTagsJob::Tag>
{
- GetRoomTagsJob::Tag operator()(QJsonObject jo) const
+ static void fillFrom(QJsonObject jo, GetRoomTagsJob::Tag& result)
{
- GetRoomTagsJob::Tag result;
- result.order =
- fromJson<float>(jo.take("order"_ls));
-
- result.additionalProperties = fromJson<QVariantHash>(jo);
- return result;
+ fromJson(jo.take("order"_ls), result.order);
+ fromJson(jo, result.additionalProperties);
}
};
} // namespace QMatrixClient
@@ -61,7 +57,7 @@ const QHash<QString, GetRoomTagsJob::Tag>& GetRoomTagsJob::tags() const
BaseJob::Status GetRoomTagsJob::parseJson(const QJsonDocument& data)
{
auto json = data.object();
- d->tags = fromJson<QHash<QString, Tag>>(json.value("tags"_ls));
+ fromJson(json.value("tags"_ls), d->tags);
return Success;
}
diff --git a/lib/csapi/third_party_lookup.cpp b/lib/csapi/third_party_lookup.cpp
index 3ba1a5ad..12cb7c59 100644
--- a/lib/csapi/third_party_lookup.cpp
+++ b/lib/csapi/third_party_lookup.cpp
@@ -42,7 +42,7 @@ const QHash<QString, ThirdPartyProtocol>& GetProtocolsJob::data() const
BaseJob::Status GetProtocolsJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<QHash<QString, ThirdPartyProtocol>>(data);
+ fromJson(data, d->data);
return Success;
}
@@ -76,7 +76,7 @@ const ThirdPartyProtocol& GetProtocolMetadataJob::data() const
BaseJob::Status GetProtocolMetadataJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<ThirdPartyProtocol>(data);
+ fromJson(data, d->data);
return Success;
}
@@ -119,7 +119,7 @@ const QVector<ThirdPartyLocation>& QueryLocationByProtocolJob::data() const
BaseJob::Status QueryLocationByProtocolJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<QVector<ThirdPartyLocation>>(data);
+ fromJson(data, d->data);
return Success;
}
@@ -162,7 +162,7 @@ const QVector<ThirdPartyUser>& QueryUserByProtocolJob::data() const
BaseJob::Status QueryUserByProtocolJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<QVector<ThirdPartyUser>>(data);
+ fromJson(data, d->data);
return Success;
}
@@ -205,7 +205,7 @@ const QVector<ThirdPartyLocation>& QueryLocationByAliasJob::data() const
BaseJob::Status QueryLocationByAliasJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<QVector<ThirdPartyLocation>>(data);
+ fromJson(data, d->data);
return Success;
}
@@ -248,7 +248,7 @@ const QVector<ThirdPartyUser>& QueryUserByIDJob::data() const
BaseJob::Status QueryUserByIDJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<QVector<ThirdPartyUser>>(data);
+ fromJson(data, d->data);
return Success;
}
diff --git a/lib/csapi/users.cpp b/lib/csapi/users.cpp
index deb9cb8a..97d8962d 100644
--- a/lib/csapi/users.cpp
+++ b/lib/csapi/users.cpp
@@ -16,19 +16,13 @@ namespace QMatrixClient
{
// Converters
- template <> struct FromJsonObject<SearchUserDirectoryJob::User>
+ template <> struct JsonObjectConverter<SearchUserDirectoryJob::User>
{
- SearchUserDirectoryJob::User operator()(const QJsonObject& jo) const
+ static void fillFrom(const QJsonObject& jo, SearchUserDirectoryJob::User& result)
{
- SearchUserDirectoryJob::User result;
- result.userId =
- fromJson<QString>(jo.value("user_id"_ls));
- result.displayName =
- fromJson<QString>(jo.value("display_name"_ls));
- result.avatarUrl =
- fromJson<QString>(jo.value("avatar_url"_ls));
-
- return result;
+ fromJson(jo.value("user_id"_ls), result.userId);
+ fromJson(jo.value("display_name"_ls), result.displayName);
+ fromJson(jo.value("avatar_url"_ls), result.avatarUrl);
}
};
} // namespace QMatrixClient
@@ -71,11 +65,11 @@ BaseJob::Status SearchUserDirectoryJob::parseJson(const QJsonDocument& data)
if (!json.contains("results"_ls))
return { JsonParseError,
"The key 'results' not found in the response" };
- d->results = fromJson<QVector<User>>(json.value("results"_ls));
+ fromJson(json.value("results"_ls), d->results);
if (!json.contains("limited"_ls))
return { JsonParseError,
"The key 'limited' not found in the response" };
- d->limited = fromJson<bool>(json.value("limited"_ls));
+ fromJson(json.value("limited"_ls), d->limited);
return Success;
}
diff --git a/lib/csapi/versions.cpp b/lib/csapi/versions.cpp
index 128902e2..c853ec06 100644
--- a/lib/csapi/versions.cpp
+++ b/lib/csapi/versions.cpp
@@ -43,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"_ls));
+ fromJson(json.value("versions"_ls), d->versions);
return Success;
}
diff --git a/lib/csapi/voip.cpp b/lib/csapi/voip.cpp
index 0479b645..e8158723 100644
--- a/lib/csapi/voip.cpp
+++ b/lib/csapi/voip.cpp
@@ -42,7 +42,7 @@ const QJsonObject& GetTurnServerJob::data() const
BaseJob::Status GetTurnServerJob::parseJson(const QJsonDocument& data)
{
- d->data = fromJson<QJsonObject>(data);
+ fromJson(data, d->data);
return Success;
}
diff --git a/lib/csapi/wellknown.cpp b/lib/csapi/wellknown.cpp
index d42534a0..97505830 100644
--- a/lib/csapi/wellknown.cpp
+++ b/lib/csapi/wellknown.cpp
@@ -52,8 +52,8 @@ BaseJob::Status GetWellknownJob::parseJson(const QJsonDocument& data)
if (!json.contains("m.homeserver"_ls))
return { JsonParseError,
"The key 'm.homeserver' not found in the response" };
- d->homeserver = fromJson<HomeserverInformation>(json.value("m.homeserver"_ls));
- d->identityServer = fromJson<IdentityServerInformation>(json.value("m.identity_server"_ls));
+ fromJson(json.value("m.homeserver"_ls), d->homeserver);
+ fromJson(json.value("m.identity_server"_ls), d->identityServer);
return Success;
}
diff --git a/lib/csapi/whoami.cpp b/lib/csapi/whoami.cpp
index cb6439ef..aebdf5d3 100644
--- a/lib/csapi/whoami.cpp
+++ b/lib/csapi/whoami.cpp
@@ -46,7 +46,7 @@ BaseJob::Status GetTokenOwnerJob::parseJson(const QJsonDocument& data)
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"_ls));
+ fromJson(json.value("user_id"_ls), d->userId);
return Success;
}
diff --git a/lib/csapi/{{base}}.cpp.mustache b/lib/csapi/{{base}}.cpp.mustache
index 64fd8bf3..ff888d76 100644
--- a/lib/csapi/{{base}}.cpp.mustache
+++ b/lib/csapi/{{base}}.cpp.mustache
@@ -8,49 +8,52 @@
{{/operations}}
using namespace QMatrixClient;
{{#models.model}}{{#in?}}
-QJsonObject QMatrixClient::toJson(const {{qualifiedName}}& pod)
+void JsonObjectConverter<{{qualifiedName}}>::dumpTo(
+ QJsonObject& jo, const {{qualifiedName}}& pod)
{
- QJsonObject jo{{#propertyMap}} = toJson(pod.{{nameCamelCase}}){{/propertyMap}};{{#vars}}
- addParam<{{^required?}}IfNotEmpty{{/required?}}>(jo, QStringLiteral("{{baseName}}"), pod.{{nameCamelCase}});{{/vars}}
- return jo;
-}
+{{#propertyMap}} fillJson(jo, pod.{{nameCamelCase}});
+{{/propertyMap}}{{#parents}} fillJson<{{name}}>(jo, pod);
+{{/parents}}{{#vars}} addParam<{{^required?}}IfNotEmpty{{/required?}}>(jo, QStringLiteral("{{baseName}}"), pod.{{nameCamelCase}});
+{{/vars}}}{{!<- dumpTo() ends here}}
{{/in?}}{{#out?}}
-{{qualifiedName}} FromJsonObject<{{qualifiedName}}>::operator()({{^propertyMap}}const QJsonObject&{{/propertyMap}}{{#propertyMap}}QJsonObject{{/propertyMap}} jo) const
+void JsonObjectConverter<{{qualifiedName}}>::fillFrom(
+ {{^propertyMap}}const QJsonObject&{{/propertyMap
+ }}{{#propertyMap}}QJsonObject{{/propertyMap}} jo, {{qualifiedName}}& result)
{
- {{qualifiedName}} result;
-{{#vars}} result.{{nameCamelCase}} =
- fromJson<{{dataType.qualifiedName}}>(jo.{{#propertyMap}}take{{/propertyMap}}{{^propertyMap}}value{{/propertyMap}}("{{baseName}}"_ls));
+{{#parents}} fillFromJson<{{qualifiedName}}>(jo, result);
+{{/parents}}{{#vars}} fromJson(jo.{{#propertyMap}}take{{/propertyMap
+ }}{{^propertyMap}}value{{/propertyMap}}("{{baseName}}"_ls), result.{{nameCamelCase}});
{{/vars}}{{#propertyMap}}
- result.{{nameCamelCase}} = fromJson<{{dataType.qualifiedName}}>(jo);{{/propertyMap}}
- return result;
-}
+ fromJson(jo, result.{{nameCamelCase}});
+{{/propertyMap}}}
{{/out?}}{{/models.model}}{{#operations}}
static const auto basePath = QStringLiteral("{{basePathWithoutHost}}");
{{# operation}}{{#models}}
namespace QMatrixClient
{
// Converters
-{{#model}}{{#in?}}
- QJsonObject toJson(const {{qualifiedName}}& pod)
- {
- QJsonObject jo{{#propertyMap}} = toJson(pod.{{nameCamelCase}}){{/propertyMap}};{{#vars}}
- addParam<{{^required?}}IfNotEmpty{{/required?}}>(jo, QStringLiteral("{{baseName}}"), pod.{{nameCamelCase}});{{/vars}}
- return jo;
- }
-{{/in?}}{{#out?}}
- template <> struct FromJsonObject<{{qualifiedName}}>
+{{#model}}
+ template <> struct JsonObjectConverter<{{qualifiedName}}>
{
- {{qualifiedName}} operator()({{^propertyMap}}const QJsonObject&{{/propertyMap}}{{#propertyMap}}QJsonObject{{/propertyMap}} jo) const
+{{#in?}} static void dumpTo(QJsonObject& jo, const {{qualifiedName}}& pod)
{
- {{qualifiedName}} result;
-{{#vars}} result.{{nameCamelCase}} =
- fromJson<{{dataType.qualifiedName}}>(jo.{{#propertyMap}}take{{/propertyMap}}{{^propertyMap}}value{{/propertyMap}}("{{baseName}}"_ls));
-{{/vars}}{{#propertyMap}}
- result.{{nameCamelCase}} = fromJson<{{dataType.qualifiedName}}>(jo);{{/propertyMap}}
- return result;
- }
- };
-{{/out?}}{{/model}}} // namespace QMatrixClient
+{{#propertyMap}} fillJson(jo, pod.{{nameCamelCase}});
+ {{/propertyMap}}{{#parents}}fillJson<{{name}}>(jo, pod);
+ {{/parents}}{{#vars
+}} addParam<{{^required?}}IfNotEmpty{{/required?}}>(jo, QStringLiteral("{{baseName}}"), pod.{{nameCamelCase}});
+{{/vars}} }
+{{/in?}}{{#out?
+}} static void fillFrom({{^propertyMap}}const QJsonObject&{{/propertyMap
+ }}{{#propertyMap}}QJsonObject{{/propertyMap}} jo, {{qualifiedName}}& result)
+ {
+{{#parents}} fillFromJson<{{qualifiedName}}{{!of the parent!}}>(jo, result);
+ {{/parents}}{{#vars
+}} fromJson(jo.{{#propertyMap}}take{{/propertyMap
+ }}{{^propertyMap}}value{{/propertyMap}}("{{baseName}}"_ls), result.{{nameCamelCase}});
+{{/vars}}{{#propertyMap}} fromJson(jo, result.{{nameCamelCase}});
+{{/propertyMap}} }
+{{/out?}} };
+{{/model}}} // namespace QMatrixClient
{{/ models}}{{#responses}}{{#normalResponse?}}{{#allProperties?}}
class {{camelCaseOperationId}}Job::Private
{
@@ -109,12 +112,12 @@ BaseJob::Status {{camelCaseOperationId}}Job::parseReply(QNetworkReply* reply)
}{{/ producesNonJson?}}{{^producesNonJson?}}
BaseJob::Status {{camelCaseOperationId}}Job::parseJson(const QJsonDocument& data)
{
-{{#inlineResponse}} d->{{paramName}} = fromJson<{{dataType.name}}>(data);
+{{#inlineResponse}} fromJson(data, d->{{paramName}});
{{/inlineResponse}}{{^inlineResponse}} auto json = data.object();
{{#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}}"_ls));
+{{/required?}} fromJson(json.value("{{baseName}}"_ls), d->{{paramName}});
{{/properties}}{{/inlineResponse}} return Success;
}{{/ producesNonJson?}}
{{/allProperties?}}{{/normalResponse?}}{{/responses}}{{/operation}}{{/operations}}
diff --git a/lib/csapi/{{base}}.h.mustache b/lib/csapi/{{base}}.h.mustache
index 147c8607..a9c3a63a 100644
--- a/lib/csapi/{{base}}.h.mustache
+++ b/lib/csapi/{{base}}.h.mustache
@@ -18,14 +18,13 @@ namespace QMatrixClient
{{/vars}}{{#propertyMap}}{{#description}} /// {{_}}
{{/description}} {{>maybeOmittableType}} {{nameCamelCase}};
{{/propertyMap}} };
-{{#in?}}
- QJsonObject toJson(const {{name}}& pod);
-{{/in?}}{{#out?}}
- template <> struct FromJsonObject<{{name}}>
+ template <> struct JsonObjectConverter<{{name}}>
{
- {{name}} operator()({{^propertyMap}}const QJsonObject&{{/propertyMap}}{{#propertyMap}}QJsonObject{{/propertyMap}} jo) const;
- };
-{{/ out?}}{{/model}}
+ {{#in?}}static void dumpTo(QJsonObject& jo, const {{name}}& pod);
+ {{/in?}}{{#out?}}static void fillFrom({{^propertyMap}}const QJsonObject&{{/propertyMap
+ }}{{#propertyMap}}QJsonObject{{/propertyMap}} jo, {{name}}& pod);
+{{/out?}} };
+{{/model}}
{{/models}}{{#operations}} // Operations
{{# operation}}{{#summary}}
/// {{summary}}{{#description?}}{{!add a linebreak between summary and description if both exist}}
diff --git a/lib/events/accountdataevents.h b/lib/events/accountdataevents.h
index d1c1abc8..a99d85ac 100644
--- a/lib/events/accountdataevents.h
+++ b/lib/events/accountdataevents.h
@@ -36,37 +36,38 @@ namespace QMatrixClient
order_type order;
TagRecord (order_type order = none) : order(order) { }
- explicit TagRecord(const QJsonObject& jo)
+
+ bool operator<(const TagRecord& other) const
+ {
+ // Per The Spec, rooms with no order should be after those with order
+ return !order.omitted() &&
+ (other.order.omitted() || order.value() < other.order.value());
+ }
+ };
+
+ template <> struct JsonObjectConverter<TagRecord>
+ {
+ static void fillFrom(const QJsonObject& jo, TagRecord& rec)
{
// Parse a float both from JSON double and JSON string because
// libqmatrixclient previously used to use strings to store order.
const auto orderJv = jo.value("order"_ls);
if (orderJv.isDouble())
- order = fromJson<float>(orderJv);
- else if (orderJv.isString())
+ rec.order = fromJson<float>(orderJv);
+ if (orderJv.isString())
{
bool ok;
- order = orderJv.toString().toFloat(&ok);
+ rec.order = orderJv.toString().toFloat(&ok);
if (!ok)
- order = none;
+ rec.order = none;
}
}
-
- bool operator<(const TagRecord& other) const
+ static void dumpTo(QJsonObject& jo, const TagRecord& rec)
{
- // Per The Spec, rooms with no order should be after those with order
- return !order.omitted() &&
- (other.order.omitted() || order.value() < other.order.value());
+ addParam<IfNotEmpty>(jo, QStringLiteral("order"), rec.order);
}
};
- inline QJsonValue toJson(const TagRecord& rec)
- {
- QJsonObject o;
- addParam<IfNotEmpty>(o, QStringLiteral("order"), rec.order);
- return o;
- }
-
using TagsMap = QHash<QString, TagRecord>;
#define DEFINE_SIMPLE_EVENT(_Name, _TypeId, _ContentType, _ContentKey) \
diff --git a/lib/events/eventcontent.h b/lib/events/eventcontent.h
index 91d7a8c8..bedf0078 100644
--- a/lib/events/eventcontent.h
+++ b/lib/events/eventcontent.h
@@ -43,9 +43,10 @@ namespace QMatrixClient
class Base
{
public:
- explicit Base (const QJsonObject& o = {}) : originalJson(o) { }
+ explicit Base (QJsonObject o = {}) : originalJson(std::move(o)) { }
virtual ~Base() = default;
+ // FIXME: make toJson() from converters.* work on base classes
QJsonObject toJson() const;
public:
diff --git a/lib/events/eventloader.h b/lib/events/eventloader.h
index cd2f9149..da663392 100644
--- a/lib/events/eventloader.h
+++ b/lib/events/eventloader.h
@@ -57,11 +57,15 @@ namespace QMatrixClient {
matrixType);
}
- template <typename EventT> struct FromJsonObject<event_ptr_tt<EventT>>
+ template <typename EventT> struct JsonConverter<event_ptr_tt<EventT>>
{
- auto operator()(const QJsonObject& jo) const
+ static auto load(const QJsonValue& jv)
{
- return loadEvent<EventT>(jo);
+ return loadEvent<EventT>(jv.toObject());
+ }
+ static auto load(const QJsonDocument& jd)
+ {
+ return loadEvent<EventT>(jd.object());
}
};
} // namespace QMatrixClient
diff --git a/lib/events/roommemberevent.cpp b/lib/events/roommemberevent.cpp
index eaa3302c..a5ac3c5f 100644
--- a/lib/events/roommemberevent.cpp
+++ b/lib/events/roommemberevent.cpp
@@ -23,20 +23,17 @@
#include <array>
-using namespace QMatrixClient;
-
static const std::array<QString, 5> membershipStrings = { {
QStringLiteral("invite"), QStringLiteral("join"),
QStringLiteral("knock"), QStringLiteral("leave"),
QStringLiteral("ban")
} };
-namespace QMatrixClient
-{
+namespace QMatrixClient {
template <>
- struct FromJson<MembershipType>
+ struct JsonConverter<MembershipType>
{
- MembershipType operator()(const QJsonValue& jv) const
+ static MembershipType load(const QJsonValue& jv)
{
const auto& membershipString = jv.toString();
for (auto it = membershipStrings.begin();
@@ -48,9 +45,10 @@ namespace QMatrixClient
return MembershipType::Undefined;
}
};
-
}
+using namespace QMatrixClient;
+
MemberEventContent::MemberEventContent(const QJsonObject& json)
: membership(fromJson<MembershipType>(json["membership"_ls]))
, isDirect(json["is_direct"_ls].toBool())
diff --git a/lib/events/roommemberevent.h b/lib/events/roommemberevent.h
index 149d74f8..b8224033 100644
--- a/lib/events/roommemberevent.h
+++ b/lib/events/roommemberevent.h
@@ -60,8 +60,16 @@ namespace QMatrixClient
: StateEvent(typeId(), matrixTypeId(), c)
{ }
- // This is a special constructor enabling RoomMemberEvent to be
- // a base class for more specific member events.
+ /// A special constructor to create unknown RoomMemberEvents
+ /**
+ * This is needed in order to use RoomMemberEvent as a "base event
+ * class" in cases like GetMembersByRoomJob when RoomMemberEvents
+ * (rather than RoomEvents or StateEvents) are resolved from JSON.
+ * For such cases loadEvent<> requires an underlying class to be
+ * constructible with unknownTypeId() instead of its genuine id.
+ * Don't use it directly.
+ * \sa GetMembersByRoomJob, loadEvent, unknownTypeId
+ */
RoomMemberEvent(Type type, const QJsonObject& fullJson)
: StateEvent(type, fullJson)
{ }
@@ -81,6 +89,18 @@ namespace QMatrixClient
private:
REGISTER_ENUM(MembershipType)
};
+
+ template <>
+ class EventFactory<RoomMemberEvent>
+ {
+ public:
+ static event_ptr_tt<RoomMemberEvent> make(const QJsonObject& json,
+ const QString&)
+ {
+ return makeEvent<RoomMemberEvent>(json);
+ }
+ };
+
REGISTER_EVENT_TYPE(RoomMemberEvent)
DEFINE_EVENTTYPE_ALIAS(RoomMember, RoomMemberEvent)
} // namespace QMatrixClient
diff --git a/lib/identity/definitions/request_email_validation.cpp b/lib/identity/definitions/request_email_validation.cpp
index 95088bcb..47463a8b 100644
--- a/lib/identity/definitions/request_email_validation.cpp
+++ b/lib/identity/definitions/request_email_validation.cpp
@@ -6,28 +6,21 @@
using namespace QMatrixClient;
-QJsonObject QMatrixClient::toJson(const RequestEmailValidation& pod)
+void JsonObjectConverter<RequestEmailValidation>::dumpTo(
+ QJsonObject& jo, const RequestEmailValidation& pod)
{
- QJsonObject jo;
addParam<>(jo, QStringLiteral("client_secret"), pod.clientSecret);
addParam<>(jo, QStringLiteral("email"), pod.email);
addParam<>(jo, QStringLiteral("send_attempt"), pod.sendAttempt);
addParam<IfNotEmpty>(jo, QStringLiteral("next_link"), pod.nextLink);
- return jo;
}
-RequestEmailValidation FromJsonObject<RequestEmailValidation>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<RequestEmailValidation>::fillFrom(
+ const QJsonObject& jo, RequestEmailValidation& result)
{
- RequestEmailValidation result;
- result.clientSecret =
- fromJson<QString>(jo.value("client_secret"_ls));
- result.email =
- fromJson<QString>(jo.value("email"_ls));
- result.sendAttempt =
- fromJson<int>(jo.value("send_attempt"_ls));
- result.nextLink =
- fromJson<QString>(jo.value("next_link"_ls));
-
- return result;
+ fromJson(jo.value("client_secret"_ls), result.clientSecret);
+ fromJson(jo.value("email"_ls), result.email);
+ fromJson(jo.value("send_attempt"_ls), result.sendAttempt);
+ fromJson(jo.value("next_link"_ls), result.nextLink);
}
diff --git a/lib/identity/definitions/request_email_validation.h b/lib/identity/definitions/request_email_validation.h
index 3e72275f..eb7d8ed6 100644
--- a/lib/identity/definitions/request_email_validation.h
+++ b/lib/identity/definitions/request_email_validation.h
@@ -33,12 +33,10 @@ namespace QMatrixClient
/// server will redirect the user to this URL.
QString nextLink;
};
-
- QJsonObject toJson(const RequestEmailValidation& pod);
-
- template <> struct FromJsonObject<RequestEmailValidation>
+ template <> struct JsonObjectConverter<RequestEmailValidation>
{
- RequestEmailValidation operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const RequestEmailValidation& pod);
+ static void fillFrom(const QJsonObject& jo, RequestEmailValidation& pod);
};
} // namespace QMatrixClient
diff --git a/lib/identity/definitions/request_msisdn_validation.cpp b/lib/identity/definitions/request_msisdn_validation.cpp
index 125baa9c..a123d326 100644
--- a/lib/identity/definitions/request_msisdn_validation.cpp
+++ b/lib/identity/definitions/request_msisdn_validation.cpp
@@ -6,31 +6,23 @@
using namespace QMatrixClient;
-QJsonObject QMatrixClient::toJson(const RequestMsisdnValidation& pod)
+void JsonObjectConverter<RequestMsisdnValidation>::dumpTo(
+ QJsonObject& jo, const RequestMsisdnValidation& pod)
{
- QJsonObject jo;
addParam<>(jo, QStringLiteral("client_secret"), pod.clientSecret);
addParam<>(jo, QStringLiteral("country"), pod.country);
addParam<>(jo, QStringLiteral("phone_number"), pod.phoneNumber);
addParam<>(jo, QStringLiteral("send_attempt"), pod.sendAttempt);
addParam<IfNotEmpty>(jo, QStringLiteral("next_link"), pod.nextLink);
- return jo;
}
-RequestMsisdnValidation FromJsonObject<RequestMsisdnValidation>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<RequestMsisdnValidation>::fillFrom(
+ const QJsonObject& jo, RequestMsisdnValidation& result)
{
- RequestMsisdnValidation result;
- result.clientSecret =
- fromJson<QString>(jo.value("client_secret"_ls));
- result.country =
- fromJson<QString>(jo.value("country"_ls));
- result.phoneNumber =
- fromJson<QString>(jo.value("phone_number"_ls));
- result.sendAttempt =
- fromJson<int>(jo.value("send_attempt"_ls));
- result.nextLink =
- fromJson<QString>(jo.value("next_link"_ls));
-
- return result;
+ fromJson(jo.value("client_secret"_ls), result.clientSecret);
+ fromJson(jo.value("country"_ls), result.country);
+ fromJson(jo.value("phone_number"_ls), result.phoneNumber);
+ fromJson(jo.value("send_attempt"_ls), result.sendAttempt);
+ fromJson(jo.value("next_link"_ls), result.nextLink);
}
diff --git a/lib/identity/definitions/request_msisdn_validation.h b/lib/identity/definitions/request_msisdn_validation.h
index 77bea2bc..b48ed6d5 100644
--- a/lib/identity/definitions/request_msisdn_validation.h
+++ b/lib/identity/definitions/request_msisdn_validation.h
@@ -36,12 +36,10 @@ namespace QMatrixClient
/// server will redirect the user to this URL.
QString nextLink;
};
-
- QJsonObject toJson(const RequestMsisdnValidation& pod);
-
- template <> struct FromJsonObject<RequestMsisdnValidation>
+ template <> struct JsonObjectConverter<RequestMsisdnValidation>
{
- RequestMsisdnValidation operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const RequestMsisdnValidation& pod);
+ static void fillFrom(const QJsonObject& jo, RequestMsisdnValidation& pod);
};
} // namespace QMatrixClient
diff --git a/lib/identity/definitions/sid.cpp b/lib/identity/definitions/sid.cpp
index 443dbedf..1ba4b3b5 100644
--- a/lib/identity/definitions/sid.cpp
+++ b/lib/identity/definitions/sid.cpp
@@ -6,19 +6,15 @@
using namespace QMatrixClient;
-QJsonObject QMatrixClient::toJson(const Sid& pod)
+void JsonObjectConverter<Sid>::dumpTo(
+ QJsonObject& jo, const Sid& pod)
{
- QJsonObject jo;
addParam<>(jo, QStringLiteral("sid"), pod.sid);
- return jo;
}
-Sid FromJsonObject<Sid>::operator()(const QJsonObject& jo) const
+void JsonObjectConverter<Sid>::fillFrom(
+ const QJsonObject& jo, Sid& result)
{
- Sid result;
- result.sid =
- fromJson<QString>(jo.value("sid"_ls));
-
- return result;
+ fromJson(jo.value("sid"_ls), result.sid);
}
diff --git a/lib/identity/definitions/sid.h b/lib/identity/definitions/sid.h
index eae60c47..ac8c4130 100644
--- a/lib/identity/definitions/sid.h
+++ b/lib/identity/definitions/sid.h
@@ -19,12 +19,10 @@ namespace QMatrixClient
/// must not be empty.
QString sid;
};
-
- QJsonObject toJson(const Sid& pod);
-
- template <> struct FromJsonObject<Sid>
+ template <> struct JsonObjectConverter<Sid>
{
- Sid operator()(const QJsonObject& jo) const;
+ static void dumpTo(QJsonObject& jo, const Sid& pod);
+ static void fillFrom(const QJsonObject& jo, Sid& pod);
};
} // namespace QMatrixClient
diff --git a/lib/jobs/syncjob.cpp b/lib/jobs/syncjob.cpp
index ac0f6685..84385b55 100644
--- a/lib/jobs/syncjob.cpp
+++ b/lib/jobs/syncjob.cpp
@@ -42,6 +42,13 @@ SyncJob::SyncJob(const QString& since, const QString& filter, int timeout,
setMaxRetries(std::numeric_limits<int>::max());
}
+SyncJob::SyncJob(const QString& since, const Filter& filter,
+ int timeout, const QString& presence)
+ : SyncJob(since,
+ QJsonDocument(toJson(filter)).toJson(QJsonDocument::Compact),
+ timeout, presence)
+{ }
+
BaseJob::Status SyncJob::parseJson(const QJsonDocument& data)
{
d.parseJson(data.object());
diff --git a/lib/jobs/syncjob.h b/lib/jobs/syncjob.h
index a0a3c026..036b25d0 100644
--- a/lib/jobs/syncjob.h
+++ b/lib/jobs/syncjob.h
@@ -21,6 +21,7 @@
#include "basejob.h"
#include "../syncdata.h"
+#include "../csapi/definitions/sync_filter.h"
namespace QMatrixClient
{
@@ -30,6 +31,8 @@ namespace QMatrixClient
explicit SyncJob(const QString& since = {},
const QString& filter = {},
int timeout = -1, const QString& presence = {});
+ explicit SyncJob(const QString& since, const Filter& filter,
+ int timeout = -1, const QString& presence = {});
SyncData &&takeData() { return std::move(d); }
diff --git a/lib/room.cpp b/lib/room.cpp
index cdc7572a..8f9095dd 100644
--- a/lib/room.cpp
+++ b/lib/room.cpp
@@ -27,6 +27,7 @@
#include "csapi/account-data.h"
#include "csapi/room_state.h"
#include "csapi/room_send.h"
+#include "csapi/rooms.h"
#include "csapi/tags.h"
#include "events/simplestateevents.h"
#include "events/roomavatarevent.h"
@@ -93,6 +94,7 @@ class Room::Private
Connection* connection;
QString id;
JoinState joinState;
+ RoomSummary summary;
/// The state of the room at timeline position before-0
/// \sa timelineBase
std::unordered_map<StateEventKey, StateEventPtr> baseState;
@@ -120,6 +122,7 @@ class Room::Private
std::unordered_map<QString, EventPtr> accountData;
QString prevBatch;
QPointer<GetRoomEventsJob> eventsHistoryJob;
+ QPointer<GetMembersByRoomJob> allMembersJob;
struct FileTransferPrivateInfo
{
@@ -164,6 +167,8 @@ class Room::Private
const RoomMessageEvent* getEventWithFile(const QString& eventId) const;
QString fileNameToDownload(const RoomMessageEvent* event) const;
+ Changes setSummary(RoomSummary&& newSummary);
+
//void inviteUser(User* u); // We might get it at some point in time.
void insertMemberIntoMap(User* u);
void renameMember(User* u, QString oldName);
@@ -219,6 +224,8 @@ class Room::Private
Changes markMessagesAsRead(rev_iter_t upToMarker);
+ void getAllMembers();
+
QString sendEvent(RoomEventPtr&& event);
template <typename EventT, typename... ArgTs>
@@ -260,8 +267,11 @@ class Room::Private
QJsonObject toJson() const;
private:
+ using users_shortlist_t = std::array<User*, 3>;
+ template<typename ContT>
+ users_shortlist_t buildShortlist(const ContT& users) const;
+ users_shortlist_t buildShortlist(const QStringList& userIds) const;
QString calculateDisplayname() const;
- QString roomNameFromMemberNames(const QList<User*>& userlist) const;
bool isLocalUser(const User* u) const
{
@@ -276,9 +286,6 @@ Room::Room(Connection* connection, QString id, JoinState initialJoinState)
// See "Accessing the Public Class" section in
// https://marcmutz.wordpress.com/translated-articles/pimp-my-pimpl-%E2%80%94-reloaded/
d->q = this;
- connect(this, &Room::userAdded, this, &Room::memberListChanged);
- connect(this, &Room::userRemoved, this, &Room::memberListChanged);
- connect(this, &Room::memberRenamed, this, &Room::memberListChanged);
qCDebug(MAIN) << "New" << toCString(initialJoinState) << "Room:" << id;
}
@@ -585,6 +592,37 @@ Room::rev_iter_t Room::findInTimeline(const QString& evtId) const
return timelineEdge();
}
+void Room::Private::getAllMembers()
+{
+ // If already loaded or already loading, there's nothing to do here.
+ if (q->joinedCount() - 1 <= membersMap.size() || isJobRunning(allMembersJob))
+ return;
+
+ allMembersJob = connection->callApi<GetMembersByRoomJob>(
+ id, connection->nextBatchToken(), "join");
+ auto nextIndex = timeline.empty() ? 0 : timeline.back().index() + 1;
+ connect( allMembersJob, &BaseJob::success, q, [=] {
+ Q_ASSERT(timeline.empty() || nextIndex <= q->maxTimelineIndex() + 1);
+ Changes roomChanges = NoChange;
+ for (auto&& e: allMembersJob->chunk())
+ {
+ const auto& evt = *e;
+ baseState[{evt.matrixType(),evt.stateKey()}] = move(e);
+ roomChanges |= q->processStateEvent(evt);
+ }
+ // Replay member events that arrived after the point for which
+ // the full members list was requested.
+ if (!timeline.empty() )
+ for (auto it = q->findInTimeline(nextIndex).base();
+ it != timeline.cend(); ++it)
+ if (is<RoomMemberEvent>(**it))
+ roomChanges |= q->processStateEvent(**it);
+ if (roomChanges&MembersChange)
+ emit q->memberListChanged();
+ emit q->allMembersLoaded();
+ });
+}
+
bool Room::displayed() const
{
return d->displayed;
@@ -601,6 +639,7 @@ void Room::setDisplayed(bool displayed)
{
resetHighlightCount();
resetNotificationCount();
+ d->getAllMembers();
}
}
@@ -981,11 +1020,39 @@ bool Room::usesEncryption() const
return !d->getCurrentState<EncryptionEvent>()->algorithm().isEmpty();
}
+int Room::joinedCount() const
+{
+ return d->summary.joinedMemberCount.omitted()
+ ? d->membersMap.size()
+ : d->summary.joinedMemberCount.value();
+}
+
+int Room::invitedCount() const
+{
+ // TODO: Store invited users in Room too
+ return d->summary.invitedMemberCount;
+}
+
+int Room::totalMemberCount() const
+{
+ return joinedCount() + invitedCount();
+}
+
GetRoomEventsJob* Room::eventsHistoryJob() const
{
return d->eventsHistoryJob;
}
+Room::Changes Room::Private::setSummary(RoomSummary&& newSummary)
+{
+ if (!summary.merge(newSummary))
+ return Change::NoChange;
+ qCDebug(MAIN).nospace().noquote()
+ << "Updated room summary for " << q->objectName() << ": " << summary;
+ emit q->memberListChanged();
+ return Change::SummaryChange;
+}
+
void Room::Private::insertMemberIntoMap(User *u)
{
const auto userName = u->name(q);
@@ -1153,6 +1220,10 @@ void Room::updateData(SyncRoomData&& data, bool fromCache)
if (roomChanges&NameChange)
emit namesChanged(this);
+ if (roomChanges&MembersChange)
+ emit memberListChanged();
+
+ roomChanges |= d->setSummary(move(data.summary));
d->updateDisplayname();
for( auto&& ephemeralEvent: data.ephemeral )
@@ -1358,7 +1429,7 @@ bool isEchoEvent(const RoomEventPtr& le, const PendingEventItem& re)
bool Room::supportsCalls() const
{
- return d->membersMap.size() == 2;
+ return joinedCount() == 2;
}
void Room::inviteCall(const QString& callId, const int lifetime,
@@ -1401,18 +1472,18 @@ void Room::getPreviousContent(int limit)
void Room::Private::getPreviousContent(int limit)
{
- if( !isJobRunning(eventsHistoryJob) )
- {
- eventsHistoryJob =
- connection->callApi<GetRoomEventsJob>(id, prevBatch, "b", "", limit);
- emit q->eventsHistoryJobChanged();
- connect( eventsHistoryJob, &BaseJob::success, q, [=] {
- prevBatch = eventsHistoryJob->end();
- addHistoricalMessageEvents(eventsHistoryJob->chunk());
- });
- connect( eventsHistoryJob, &QObject::destroyed,
- q, &Room::eventsHistoryJobChanged);
- }
+ if (isJobRunning(eventsHistoryJob))
+ return;
+
+ eventsHistoryJob =
+ connection->callApi<GetRoomEventsJob>(id, prevBatch, "b", "", limit);
+ emit q->eventsHistoryJobChanged();
+ connect( eventsHistoryJob, &BaseJob::success, q, [=] {
+ prevBatch = eventsHistoryJob->end();
+ addHistoricalMessageEvents(eventsHistoryJob->chunk());
+ });
+ connect( eventsHistoryJob, &QObject::destroyed,
+ q, &Room::eventsHistoryJobChanged);
}
void Room::inviteToRoom(const QString& memberId)
@@ -2018,49 +2089,35 @@ Room::Changes Room::processAccountDataEvent(EventPtr&& event)
return Change::NoChange;
}
-QString Room::Private::roomNameFromMemberNames(const QList<User *> &userlist) const
+template <typename ContT>
+Room::Private::users_shortlist_t
+Room::Private::buildShortlist(const ContT& users) const
{
- // This is part 3(i,ii,iii) in the room displayname algorithm described
- // in the CS spec (see also Room::Private::updateDisplayname() ).
- // The spec requires to sort users lexicographically by state_key (user id)
- // and use disambiguated display names of two topmost users excluding
- // the current one to render the name of the room.
-
- // std::array is the leanest C++ container
- std::array<User*, 2> first_two = { {nullptr, nullptr} };
+ // To calculate room display name the spec requires to sort users
+ // lexicographically by state_key (user id) and use disambiguated
+ // display names of two topmost users excluding the current one to render
+ // the name of the room. The below code selects 3 topmost users,
+ // slightly extending the spec.
+ users_shortlist_t shortlist { }; // Prefill with nullptrs
std::partial_sort_copy(
- userlist.begin(), userlist.end(),
- first_two.begin(), first_two.end(),
- [this](const User* u1, const User* u2) {
- // Filter out the "me" user so that it never hits the room name
+ users.begin(), users.end(),
+ shortlist.begin(), shortlist.end(),
+ [this] (const User* u1, const User* u2) {
+ // localUser(), if it's in the list, is sorted below all others
return isLocalUser(u2) || (!isLocalUser(u1) && u1->id() < u2->id());
}
);
+ return shortlist;
+}
- // Spec extension. A single person in the chat but not the local user
- // (the local user is invited).
- if (userlist.size() == 1 && !isLocalUser(first_two.front()) &&
- joinState == JoinState::Invite)
- return tr("Invitation from %1")
- .arg(q->roomMembername(first_two.front()));
-
- // i. One-on-one chat. first_two[1] == localUser() in this case.
- if (userlist.size() == 2)
- return q->roomMembername(first_two[0]);
-
- // ii. Two users besides the current one.
- if (userlist.size() == 3)
- return tr("%1 and %2")
- .arg(q->roomMembername(first_two[0]),
- q->roomMembername(first_two[1]));
-
- // iii. More users.
- if (userlist.size() > 3)
- return tr("%1 and %Ln other(s)", "", userlist.size() - 3)
- .arg(q->roomMembername(first_two[0]));
-
- // userlist.size() < 2 - apparently, there's only current user in the room
- return QString();
+Room::Private::users_shortlist_t
+Room::Private::buildShortlist(const QStringList& userIds) const
+{
+ QList<User*> users;
+ users.reserve(userIds.size());
+ for (const auto& h: userIds)
+ users.push_back(q->user(h));
+ return buildShortlist(users);
}
QString Room::Private::calculateDisplayname() const
@@ -2083,15 +2140,42 @@ QString Room::Private::calculateDisplayname() const
//if (!q->aliases().empty() && !q->aliases().at(0).isEmpty())
// return q->aliases().at(0);
+ // Supplementary code for 3 and 4: build the shortlist of users whose names
+ // will be used to construct the room name. Takes into account MSC688's
+ // "heroes" if available.
+
+ const bool emptyRoom = membersMap.isEmpty() ||
+ (membersMap.size() == 1 && isLocalUser(*membersMap.begin()));
+ const auto shortlist =
+ !summary.heroes.omitted() ? buildShortlist(summary.heroes.value()) :
+ !emptyRoom ? buildShortlist(membersMap) :
+ buildShortlist(membersLeft);
+
+ QStringList names;
+ for (auto u: shortlist)
+ {
+ if (u == nullptr || isLocalUser(u))
+ break;
+ names.push_back(q->roomMembername(u));
+ }
+
+ auto usersCountExceptLocal = emptyRoom
+ ? membersLeft.size() - int(joinState == JoinState::Leave)
+ : q->joinedCount() - int(joinState == JoinState::Join);
+ if (usersCountExceptLocal > int(shortlist.size()))
+ names <<
+ tr("%Ln other(s)",
+ "Used to make a room name from user names: A, B and _N others_",
+ usersCountExceptLocal);
+ auto namesList = QLocale().createSeparatedList(names);
+
// 3. Room members
- dispName = roomNameFromMemberNames(membersMap.values());
- if (!dispName.isEmpty())
- return dispName;
+ if (!emptyRoom)
+ return namesList;
// 4. Users that previously left the room
- dispName = roomNameFromMemberNames(membersLeft);
- if (!dispName.isEmpty())
- return tr("Empty room (was: %1)").arg(dispName);
+ if (membersLeft.size() > 0)
+ return tr("Empty room (was: %1)").arg(namesList);
// 5. Fail miserably
return tr("Empty room (%1)").arg(id);
@@ -2114,6 +2198,7 @@ QJsonObject Room::Private::toJson() const
{
QElapsedTimer et; et.start();
QJsonObject result;
+ addParam<IfNotEmpty>(result, QStringLiteral("summary"), summary);
{
QJsonArray stateEvents;
diff --git a/lib/room.h b/lib/room.h
index 7533c599..f7eb224e 100644
--- a/lib/room.h
+++ b/lib/room.h
@@ -84,6 +84,9 @@ namespace QMatrixClient
Q_PROPERTY(int timelineSize READ timelineSize NOTIFY addedMessages)
Q_PROPERTY(QStringList memberNames READ memberNames NOTIFY memberListChanged)
Q_PROPERTY(int memberCount READ memberCount NOTIFY memberListChanged)
+ Q_PROPERTY(int joinedCount READ joinedCount NOTIFY memberListChanged)
+ Q_PROPERTY(int invitedCount READ invitedCount NOTIFY memberListChanged)
+ Q_PROPERTY(int totalMemberCount READ totalMemberCount NOTIFY memberListChanged)
Q_PROPERTY(bool displayed READ displayed WRITE setDisplayed NOTIFY displayedChanged)
Q_PROPERTY(QString firstDisplayedEventId READ firstDisplayedEventId WRITE setFirstDisplayedEventId NOTIFY firstDisplayedEventChanged)
@@ -116,6 +119,7 @@ namespace QMatrixClient
MembersChange = 0x80,
EncryptionOn = 0x100,
AccountDataChange = 0x200,
+ SummaryChange = 0x400,
ReadMarkerChange = 0x800,
OtherChange = 0x8000,
AnyChange = 0xFFFF
@@ -144,9 +148,13 @@ namespace QMatrixClient
Q_INVOKABLE QList<User*> users() const;
QStringList memberNames() const;
+ [[deprecated("Use joinedCount(), invitedCount(), totalMemberCount()")]]
int memberCount() const;
int timelineSize() const;
bool usesEncryption() const;
+ int joinedCount() const;
+ int invitedCount() const;
+ int totalMemberCount() const;
GetRoomEventsJob* eventsHistoryJob() const;
@@ -220,6 +228,13 @@ namespace QMatrixClient
rev_iter_t findInTimeline(const QString& evtId) const;
bool displayed() const;
+ /// Mark the room as currently displayed to the user
+ /**
+ * Marking the room displayed causes the room to obtain the full
+ * list of members if it's been lazy-loaded before; in the future
+ * it may do more things bound to "screen time" of the room, e.g.
+ * measure that "screen time".
+ */
void setDisplayed(bool displayed = true);
QString firstDisplayedEventId() const;
rev_iter_t firstDisplayedMarker() const;
@@ -422,7 +437,17 @@ namespace QMatrixClient
void userRemoved(User* user);
void memberAboutToRename(User* user, QString newName);
void memberRenamed(User* user);
+ /// The list of members has changed
+ /** Emitted no more than once per sync, this is a good signal to
+ * for cases when some action should be done upon any change in
+ * the member list. If you need per-item granularity you should use
+ * userAdded, userRemoved and memberAboutToRename / memberRenamed
+ * instead.
+ */
void memberListChanged();
+ /// The previously lazy-loaded members list is now loaded entirely
+ /// \sa setDisplayed
+ void allMembersLoaded();
void encryption();
void joinStateChanged(JoinState oldState, JoinState newState);
diff --git a/lib/syncdata.cpp b/lib/syncdata.cpp
index 1023ed6a..f55d4396 100644
--- a/lib/syncdata.cpp
+++ b/lib/syncdata.cpp
@@ -28,6 +28,53 @@ using namespace QMatrixClient;
const QString SyncRoomData::UnreadCountKey =
QStringLiteral("x-qmatrixclient.unread_count");
+bool RoomSummary::isEmpty() const
+{
+ return joinedMemberCount.omitted() && invitedMemberCount.omitted() &&
+ heroes.omitted();
+}
+
+bool RoomSummary::merge(const RoomSummary& other)
+{
+ // Using bitwise OR to prevent computation shortcut.
+ return
+ joinedMemberCount.merge(other.joinedMemberCount) |
+ invitedMemberCount.merge(other.invitedMemberCount) |
+ heroes.merge(other.heroes);
+}
+
+QDebug QMatrixClient::operator<<(QDebug dbg, const RoomSummary& rs)
+{
+ QDebugStateSaver _(dbg);
+ QStringList sl;
+ if (!rs.joinedMemberCount.omitted())
+ sl << QStringLiteral("joined: %1").arg(rs.joinedMemberCount.value());
+ if (!rs.invitedMemberCount.omitted())
+ sl << QStringLiteral("invited: %1").arg(rs.invitedMemberCount.value());
+ if (!rs.heroes.omitted())
+ sl << QStringLiteral("heroes: [%1]").arg(rs.heroes.value().join(','));
+ dbg.nospace().noquote() << sl.join(QStringLiteral("; "));
+ return dbg;
+}
+
+void JsonObjectConverter<RoomSummary>::dumpTo(QJsonObject& jo,
+ const RoomSummary& rs)
+{
+ addParam<IfNotEmpty>(jo, QStringLiteral("m.joined_member_count"),
+ rs.joinedMemberCount);
+ addParam<IfNotEmpty>(jo, QStringLiteral("m.invited_member_count"),
+ rs.invitedMemberCount);
+ addParam<IfNotEmpty>(jo, QStringLiteral("m.heroes"), rs.heroes);
+}
+
+void JsonObjectConverter<RoomSummary>::fillFrom(const QJsonObject& jo,
+ RoomSummary& rs)
+{
+ fromJson(jo["m.joined_member_count"_ls], rs.joinedMemberCount);
+ fromJson(jo["m.invited_member_count"_ls], rs.invitedMemberCount);
+ fromJson(jo["m.heroes"], rs.heroes);
+}
+
template <typename EventsArrayT, typename StrT>
inline EventsArrayT load(const QJsonObject& batches, StrT keyName)
{
@@ -38,6 +85,7 @@ SyncRoomData::SyncRoomData(const QString& roomId_, JoinState joinState_,
const QJsonObject& room_)
: roomId(roomId_)
, joinState(joinState_)
+ , summary(fromJson<RoomSummary>(room_["summary"]))
, state(load<StateEvents>(room_, joinState == JoinState::Invite
? "invite_state"_ls : "state"_ls))
{
diff --git a/lib/syncdata.h b/lib/syncdata.h
index aa8948bc..8694626e 100644
--- a/lib/syncdata.h
+++ b/lib/syncdata.h
@@ -22,11 +22,41 @@
#include "events/stateevent.h"
namespace QMatrixClient {
+ /// Room summary, as defined in MSC688
+ /**
+ * Every member of this structure is an Omittable; as per the MSC, only
+ * changed values are sent from the server so if nothing is in the payload
+ * the respective member will be omitted. In particular, `heroes.omitted()`
+ * means that nothing has come from the server; heroes.value().isEmpty()
+ * means a peculiar case of a room with the only member - the current user.
+ */
+ struct RoomSummary
+ {
+ Omittable<int> joinedMemberCount;
+ Omittable<int> invitedMemberCount;
+ Omittable<QStringList> heroes; //< mxids of users to take part in the room name
+
+ bool isEmpty() const;
+ /// Merge the contents of another RoomSummary object into this one
+ /// \return true, if the current object has changed; false otherwise
+ bool merge(const RoomSummary& other);
+
+ friend QDebug operator<<(QDebug dbg, const RoomSummary& rs);
+ };
+
+ template <>
+ struct JsonObjectConverter<RoomSummary>
+ {
+ static void dumpTo(QJsonObject& jo, const RoomSummary& rs);
+ static void fillFrom(const QJsonObject& jo, RoomSummary& rs);
+ };
+
class SyncRoomData
{
public:
QString roomId;
JoinState joinState;
+ RoomSummary summary;
StateEvents state;
RoomEvents timeline;
Events ephemeral;
@@ -70,7 +100,7 @@ namespace QMatrixClient {
QStringList unresolvedRooms() const { return unresolvedRoomIds; }
- static std::pair<int, int> cacheVersion() { return { 9, 0 }; }
+ static std::pair<int, int> cacheVersion() { return { 10, 0 }; }
static QString fileNameForRoom(QString roomId);
private:
diff --git a/lib/util.h b/lib/util.h
index 0066c03d..9c9a37ba 100644
--- a/lib/util.h
+++ b/lib/util.h
@@ -118,6 +118,22 @@ namespace QMatrixClient
_omitted = false;
return _value;
}
+ /// Merge the value from another Omittable
+ /// \return true if \p other is not omitted and the value of
+ /// the current Omittable was different (or omitted);
+ /// in other words, if the current Omittable has changed;
+ /// false otherwise
+ template <typename T1>
+ auto merge(const Omittable<T1>& other)
+ -> std::enable_if_t<std::is_convertible<T1, T>::value, bool>
+ {
+ if (other.omitted() ||
+ (!_omitted && _value == other.value()))
+ return false;
+ _omitted = false;
+ _value = other.value();
+ return true;
+ }
value_type&& release() { _omitted = true; return std::move(_value); }
operator value_type&() & { return editValue(); }