aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml6
-rw-r--r--CMakeLists.txt51
-rw-r--r--gtad/data.h.mustache53
-rw-r--r--gtad/gtad.yaml102
-rw-r--r--gtad/operation.cpp.mustache58
-rw-r--r--gtad/operation.h.mustache128
-rw-r--r--gtad/template.cpp.mustache182
-rw-r--r--gtad/template.h.mustache119
-rw-r--r--lib/application-service/definitions/location.cpp23
-rw-r--r--lib/application-service/definitions/location.h18
-rw-r--r--lib/application-service/definitions/protocol.cpp59
-rw-r--r--lib/application-service/definitions/protocol.h53
-rw-r--r--lib/application-service/definitions/user.cpp23
-rw-r--r--lib/application-service/definitions/user.h18
-rw-r--r--lib/connection.cpp4
-rw-r--r--lib/csapi/account-data.cpp27
-rw-r--r--lib/csapi/account-data.h16
-rw-r--r--lib/csapi/admin.cpp66
-rw-r--r--lib/csapi/admin.h48
-rw-r--r--lib/csapi/administrative_contact.cpp174
-rw-r--r--lib/csapi/administrative_contact.h332
-rw-r--r--lib/csapi/appservice_room_directory.cpp9
-rw-r--r--lib/csapi/appservice_room_directory.h5
-rw-r--r--lib/csapi/banning.cpp13
-rw-r--r--lib/csapi/banning.h7
-rw-r--r--lib/csapi/capabilities.cpp68
-rw-r--r--lib/csapi/capabilities.h46
-rw-r--r--lib/csapi/content-repo.cpp198
-rw-r--r--lib/csapi/content-repo.h166
-rw-r--r--lib/csapi/create_room.cpp55
-rw-r--r--lib/csapi/create_room.h118
-rw-r--r--lib/csapi/definitions/auth_data.cpp23
-rw-r--r--lib/csapi/definitions/auth_data.h20
-rw-r--r--lib/csapi/definitions/client_device.cpp23
-rw-r--r--lib/csapi/definitions/client_device.h20
-rw-r--r--lib/csapi/definitions/device_keys.cpp27
-rw-r--r--lib/csapi/definitions/device_keys.h23
-rw-r--r--lib/csapi/definitions/event_filter.cpp27
-rw-r--r--lib/csapi/definitions/event_filter.h20
-rw-r--r--lib/csapi/definitions/openid_token.h48
-rw-r--r--lib/csapi/definitions/public_rooms_response.cpp56
-rw-r--r--lib/csapi/definitions/public_rooms_response.h51
-rw-r--r--lib/csapi/definitions/push_condition.cpp25
-rw-r--r--lib/csapi/definitions/push_condition.h25
-rw-r--r--lib/csapi/definitions/push_rule.cpp28
-rw-r--r--lib/csapi/definitions/push_rule.h26
-rw-r--r--lib/csapi/definitions/push_ruleset.cpp27
-rw-r--r--lib/csapi/definitions/push_ruleset.h22
-rw-r--r--lib/csapi/definitions/request_email_validation.h48
-rw-r--r--lib/csapi/definitions/request_msisdn_validation.h48
-rw-r--r--lib/csapi/definitions/request_token_response.h45
-rw-r--r--lib/csapi/definitions/room_event_filter.cpp25
-rw-r--r--lib/csapi/definitions/room_event_filter.h38
-rw-r--r--lib/csapi/definitions/sync_filter.cpp68
-rw-r--r--lib/csapi/definitions/sync_filter.h97
-rw-r--r--lib/csapi/definitions/third_party_signed.h44
-rw-r--r--lib/csapi/definitions/user_identifier.cpp21
-rw-r--r--lib/csapi/definitions/user_identifier.h17
-rw-r--r--lib/csapi/definitions/wellknown/full.cpp24
-rw-r--r--lib/csapi/definitions/wellknown/full.h21
-rw-r--r--lib/csapi/definitions/wellknown/homeserver.cpp19
-rw-r--r--lib/csapi/definitions/wellknown/homeserver.h13
-rw-r--r--lib/csapi/definitions/wellknown/identity_server.cpp19
-rw-r--r--lib/csapi/definitions/wellknown/identity_server.h13
-rw-r--r--lib/csapi/device_management.cpp62
-rw-r--r--lib/csapi/device_management.h36
-rw-r--r--lib/csapi/directory.cpp59
-rw-r--r--lib/csapi/directory.h74
-rw-r--r--lib/csapi/event_context.cpp67
-rw-r--r--lib/csapi/event_context.h52
-rw-r--r--lib/csapi/filter.cpp55
-rw-r--r--lib/csapi/filter.h35
-rw-r--r--lib/csapi/inviting.cpp9
-rw-r--r--lib/csapi/inviting.h4
-rw-r--r--lib/csapi/joining.cpp100
-rw-r--r--lib/csapi/joining.h121
-rw-r--r--lib/csapi/keys.cpp153
-rw-r--r--lib/csapi/keys.h112
-rw-r--r--lib/csapi/kicking.cpp8
-rw-r--r--lib/csapi/kicking.h5
-rw-r--r--lib/csapi/leaving.cpp16
-rw-r--r--lib/csapi/leaving.h4
-rw-r--r--lib/csapi/list_joined_rooms.cpp33
-rw-r--r--lib/csapi/list_joined_rooms.h15
-rw-r--r--lib/csapi/list_public_rooms.cpp104
-rw-r--r--lib/csapi/list_public_rooms.h124
-rw-r--r--lib/csapi/login.cpp94
-rw-r--r--lib/csapi/login.h83
-rw-r--r--lib/csapi/logout.cpp17
-rw-r--r--lib/csapi/logout.h9
-rw-r--r--lib/csapi/message_pagination.cpp47
-rw-r--r--lib/csapi/message_pagination.h41
-rw-r--r--lib/csapi/notifications.cpp61
-rw-r--r--lib/csapi/notifications.h38
-rw-r--r--lib/csapi/openid.cpp55
-rw-r--r--lib/csapi/openid.h38
-rw-r--r--lib/csapi/peeking_events.cpp41
-rw-r--r--lib/csapi/peeking_events.h21
-rw-r--r--lib/csapi/presence.cpp54
-rw-r--r--lib/csapi/presence.h30
-rw-r--r--lib/csapi/profile.cpp97
-rw-r--r--lib/csapi/profile.h47
-rw-r--r--lib/csapi/pusher.cpp79
-rw-r--r--lib/csapi/pusher.h58
-rw-r--r--lib/csapi/pushrules.cpp143
-rw-r--r--lib/csapi/pushrules.h90
-rw-r--r--lib/csapi/read_markers.cpp9
-rw-r--r--lib/csapi/read_markers.h5
-rw-r--r--lib/csapi/receipts.cpp8
-rw-r--r--lib/csapi/receipts.h8
-rw-r--r--lib/csapi/redaction.cpp27
-rw-r--r--lib/csapi/redaction.h23
-rw-r--r--lib/csapi/registration.cpp233
-rw-r--r--lib/csapi/registration.h428
-rw-r--r--lib/csapi/report_content.cpp9
-rw-r--r--lib/csapi/report_content.h8
-rw-r--r--lib/csapi/room_send.cpp26
-rw-r--r--lib/csapi/room_send.h19
-rw-r--r--lib/csapi/room_state.cpp53
-rw-r--r--lib/csapi/room_state.h96
-rw-r--r--lib/csapi/room_upgrades.cpp34
-rw-r--r--lib/csapi/room_upgrades.h18
-rw-r--r--lib/csapi/rooms.cpp158
-rw-r--r--lib/csapi/rooms.h129
-rw-r--r--lib/csapi/sso_login_redirect.cpp12
-rw-r--r--lib/csapi/sso_login_redirect.h3
-rw-r--r--lib/csapi/tags.cpp65
-rw-r--r--lib/csapi/tags.h42
-rw-r--r--lib/csapi/third_party_lookup.cpp166
-rw-r--r--lib/csapi/third_party_lookup.h92
-rw-r--r--lib/csapi/third_party_membership.cpp11
-rw-r--r--lib/csapi/third_party_membership.h21
-rw-r--r--lib/csapi/to_device.cpp9
-rw-r--r--lib/csapi/to_device.h8
-rw-r--r--lib/csapi/typing.cpp9
-rw-r--r--lib/csapi/typing.h8
-rw-r--r--lib/csapi/users.cpp57
-rw-r--r--lib/csapi/users.h42
-rw-r--r--lib/csapi/versions.cpp38
-rw-r--r--lib/csapi/versions.h24
-rw-r--r--lib/csapi/voip.cpp26
-rw-r--r--lib/csapi/voip.h14
-rw-r--r--lib/csapi/wellknown.cpp26
-rw-r--r--lib/csapi/wellknown.h17
-rw-r--r--lib/csapi/whoami.cpp30
-rw-r--r--lib/csapi/whoami.h12
-rw-r--r--lib/encryptionmanager.cpp6
-rw-r--r--lib/identity/definitions/request_email_validation.cpp25
-rw-r--r--lib/identity/definitions/request_email_validation.h26
-rw-r--r--lib/identity/definitions/request_msisdn_validation.cpp27
-rw-r--r--lib/identity/definitions/request_msisdn_validation.h29
-rw-r--r--lib/identity/definitions/sid.cpp17
-rw-r--r--lib/identity/definitions/sid.h27
-rw-r--r--lib/jobs/basejob.cpp164
-rw-r--r--lib/jobs/basejob.h134
-rw-r--r--lib/jobs/downloadfilejob.cpp4
-rw-r--r--lib/jobs/downloadfilejob.h4
-rw-r--r--lib/jobs/mediathumbnailjob.cpp6
-rw-r--r--lib/jobs/mediathumbnailjob.h2
-rw-r--r--lib/jobs/syncjob.cpp4
-rw-r--r--lib/jobs/syncjob.h2
-rw-r--r--libquotient.pri6
162 files changed, 3136 insertions, 5057 deletions
diff --git a/.travis.yml b/.travis.yml
index d3f4711f..9eed9949 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -48,7 +48,7 @@ before_install:
- |
if [ -n "$UPDATE_API" ]; then
export CC=gcc-8 CXX=g++-8
- export CMAKE_UPDATE_API_ARGS="-DMATRIX_DOC_PATH=matrix-doc -DGTAD_PATH=gtad/gtad"
+ export CMAKE_UPDATE_API_ARGS="-DMATRIX_DOC_PATH=../matrix-doc -DGTAD_PATH=../gtad/gtad"
fi
# RPM spec-style: swallow a command with default parameters into an alias
# and add/override parameters further in the code if/as necessary
@@ -57,6 +57,7 @@ before_install:
- alias _cmake_build='cmake --build build'
install:
+- pushd .. # Go out of libQuotient source tree
- git clone https://gitlab.matrix.org/matrix-org/olm.git
- pushd olm
- _cmake_config
@@ -65,13 +66,14 @@ install:
- |
if [ -n "$UPDATE_API" ]; then
- git clone https://github.com/quotient-im/matrix-doc.git
+ git clone https://github.com/matrix.org/matrix-doc.git
git clone --recursive https://github.com/KitsuneRal/gtad.git
pushd gtad
cmake $CMAKE_ARGS .
cmake --build .
popd
fi
+- popd # back to libQuotient source tree
before_script:
- _cmake_config $CMAKE_UPDATE_API_ARGS $E2EE
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1e336673..c61c2682 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -184,21 +184,21 @@ set(lib_SRCS
)
set(CSAPI_DIR csapi)
+set(FULL_CSAPI_DIR lib/${CSAPI_DIR})
set(ASAPI_DEF_DIR application-service/definitions)
set(ISAPI_DEF_DIR identity/definitions)
-foreach (D ${CSAPI_DIR} ${CSAPI_DIR}/definitions
- ${CSAPI_DIR}/definitions/wellknown ${ASAPI_DEF_DIR} ${ISAPI_DEF_DIR})
- aux_source_directory(lib/${D} api_SRCS)
-endforeach()
+if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.12.0")
+ set(add_CONFIGURE_DEPENDS "CONFIGURE_DEPENDS")
+endif()
+file(GLOB_RECURSE api_SRCS ${add_CONFIGURE_DEPENDS} ${FULL_CSAPI_DIR}/*.cpp)
# Make no mistake: CMake cannot run gtad first and then populate the list of
-# resulting api_SRCS files. In other words, placing the above foreach after
-# the custom targets definition won't bring the desired result:
+# resulting api_SRCS files. In other words, placing the above statement after
+# the add_custom_target() call below won't bring the desired result:
# CMake will execute it at cmake invocation and gtad will only run later
# when building the update-api target. If you see that gtad has created
-# new files you have to re-run cmake.
-# TODO: check `file(GLOB_RECURSE ... CONFIGURE_DEPENDS)` (from CMake 3.14)
+# new files you have to re-run cmake. CONFIGURE_DEPENDS somewhat helps that.
if (MATRIX_DOC_PATH AND GTAD_PATH)
set(FULL_CSAPI_SRC_DIR ${ABS_API_DEF_PATH}/client-server)
file(GLOB_RECURSE API_DEFS RELATIVE ${PROJECT_SOURCE_DIR}
@@ -206,7 +206,7 @@ if (MATRIX_DOC_PATH AND GTAD_PATH)
${ABS_API_DEF_PATH}/${ASAPI_DEF_DIR}/*.yaml
${ABS_API_DEF_PATH}/${ISAPI_DEF_DIR}/*.yaml
)
- add_custom_target(update-api
+ add_custom_target(generate-unformatted-api
${ABS_GTAD_PATH} --config ../gtad/gtad.yaml --out ${CSAPI_DIR}
${FULL_CSAPI_SRC_DIR}
old_sync.yaml- room_initial_sync.yaml- # deprecated
@@ -214,25 +214,30 @@ if (MATRIX_DOC_PATH AND GTAD_PATH)
sync.yaml- # we have a better handcrafted implementation
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/lib
SOURCES gtad/gtad.yaml
- gtad/template.h.mustache
- gtad/template.cpp.mustache
+ gtad/data.h.mustache
+ gtad/operation.h.mustache
+ gtad/operation.cpp.mustache
${API_DEFS}
VERBATIM
)
if (ABS_CLANG_FORMAT)
- # TODO: list(TRANSFORM) is available from CMake 3.12
- foreach (S ${api_SRCS})
- string (REGEX REPLACE ".cpp$" ".h" H ${S})
- list(APPEND api_HDRS ${H})
- endforeach()
set(CLANG_FORMAT_ARGS -i -sort-includes ${CLANG_FORMAT_ARGS})
- add_custom_command(TARGET update-api POST_BUILD
- COMMAND ${ABS_CLANG_FORMAT} ${CLANG_FORMAT_ARGS} ${api_SRCS}
- COMMAND ${ABS_CLANG_FORMAT} ${CLANG_FORMAT_ARGS} ${api_HDRS}
- WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
- VERBATIM
- COMMENT "Formatting files"
- )
+ # FIXME: the list of files should be produced after GTAD has run.
+ # For now it's produced at CMake invocation; and if file() doesn't file
+ # any files clang-format chokes; also,
+ file(GLOB_RECURSE api_ALL_SRCS ${add_CONFIGURE_DEPENDS}
+ ${FULL_CSAPI_DIR}/*.*
+ lib/${ASAPI_DEF_DIR}/*.*
+ lib/${ISAPI_DEF_DIR}/*.*)
+ if (api_ALL_SRCS)
+ add_custom_target(format-api
+ ${ABS_CLANG_FORMAT} ${CLANG_FORMAT_ARGS} ${api_ALL_SRCS}
+ DEPENDS generate-unformatted-api
+ VERBATIM)
+ add_custom_target(update-api DEPENDS format-api)
+ else()
+ add_custom_target(update-api DEPENDS generate-unformatted-api)
+ endif()
endif()
endif()
diff --git a/gtad/data.h.mustache b/gtad/data.h.mustache
new file mode 100644
index 00000000..32ea85ee
--- /dev/null
+++ b/gtad/data.h.mustache
@@ -0,0 +1,53 @@
+{{>preamble}}
+#pragma once
+
+#include "converters.h"
+{{#imports}}
+#include {{_}}{{/imports}}
+
+namespace Quotient {
+{{#models}}
+ {{#model}}
+{{>docCommentShort}}
+struct {{name}}{{#parents?}} : {{#parents}}{{name}}{{>cjoin}}{{/parents}}{{/parents?}}
+{ {{#vars}}
+
+ {{>docCommentShort}}
+ {{>maybeOmittableType}} {{nameCamelCase}};
+ {{/vars}}{{#propertyMap}}
+
+ {{>docCommentShort}}
+ {{>maybeOmittableType}} {{nameCamelCase}};
+ {{/propertyMap}}
+};
+
+template <> struct JsonObjectConverter<{{name}}>
+{
+ {{#in?}}
+ static void dumpTo(QJsonObject& jo, const {{name}}& pod)
+ { {{#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({{>maybeCrefJsonObject}} jo, {{name}}& pod)
+ { {{#parents}}
+ fillFromJson<{{qualifiedName}}>(jo, pod);
+ {{/parents}}{{#vars}}
+ fromJson(jo.{{>takeOrValue}}("{{baseName}}"_ls), pod.{{nameCamelCase}});
+ {{/vars}}{{#propertyMap}}
+ fromJson(jo, pod.{{nameCamelCase}});
+ {{/propertyMap}}
+ }
+ {{/out?}}
+};
+
+ {{/model}}
+{{/models}}
+} // namespace Quotient
diff --git a/gtad/gtad.yaml b/gtad/gtad.yaml
index 51f9e26b..045f5f35 100644
--- a/gtad/gtad.yaml
+++ b/gtad/gtad.yaml
@@ -15,6 +15,11 @@ analyzer:
m.change_password: changePassword
m.room_versions: roomVersions
AuthenticationData/additionalProperties: authInfo
+ /\b(Location|Protocol|User)$/: 'ThirdParty$&'
+ # These parameters are deprecated and unused in Quotient; so drop them
+ login>/user: ""
+ login>/medium: ""
+ login>/address: ""
# Structure inside `types`:
# - swaggerType: <targetTypeSpec>
@@ -31,8 +36,7 @@ analyzer:
types:
- +set: &UseOmittable
useOmittable:
- imports: [ '"converters.h"' ]
- omittedValue: 'none' # See `none` in converters.h
+ omittedValue: 'none' # Quotient::none in lib/util.h
+on:
- integer:
- int64: qint64
@@ -52,11 +56,9 @@ analyzer:
- date:
type: QDate
initializer: QDate::fromString("{{defaultValue}}")
- imports: <QtCore/QDate>
- dateTime:
type: QDateTime
initializer: QDateTime::fromString("{{defaultValue}}")
- imports: <QtCore/QDateTime>
- //: &QString
type: QString
initializer: QStringLiteral("{{defaultValue}}")
@@ -64,7 +66,7 @@ analyzer:
- file: *ByteStream
- +set: { avoidCopy: }
+on:
- - object: &QJsonObject { type: QJsonObject, imports: <QtCore/QJsonObject> }
+ - object: &QJsonObject { type: QJsonObject }
- $ref:
- +set: { moveOnly: }
+on:
@@ -74,10 +76,16 @@ analyzer:
{ type: RoomEventPtr, imports: '"events/eventloader.h"' }
- /event.yaml$/:
{ type: EventPtr, imports: '"events/eventloader.h"' }
- - /m\.room\.member$/: pass # This $ref is only used in an array, see below
+ - /m\.room\.member$/: void # Skip resolving; see EventsArray<> below
+ - '/^(\./)?definitions/request_email_validation.yaml$/':
+ title: EmailValidationData
+ - '/^(\./)?definitions/request_msisdn_validation.yaml$/':
+ title: MsisdnValidationData
+ - /_filter.yaml$/: # Event/RoomEventFilters do NOT need Omittable<>
- //: *UseOmittable # Also apply "avoidCopy" to all other ref'ed types
- - schema: # Properties of inline structure definitions
- - TurnServerCredentials: *QJsonObject # Because it's used as is
+ - schema:
+ - getTurnServer<: *QJsonObject # It's used as an opaque JSON object
+ - RoomFilter: # A structure inside Filter, same story as with other filters
- //: *UseOmittable
- array:
- string: QStringList
@@ -86,27 +94,23 @@ analyzer:
- /^Notification|Result$/:
type: "std::vector<{{1}}>"
imports: '"events/eventloader.h"'
- - /m\.room\.member$/:
+ - /m\.room\.member$/: # Only used in an array (see also above)
type: "EventsArray<RoomMemberEvent>"
imports: '"events/roommemberevent.h"'
- /state_event.yaml$/: StateEvents
- /room_event.yaml$/: RoomEvents
- /event.yaml$/: Events
- - //: { type: "QVector<{{1}}>", imports: <QtCore/QVector> }
+ - //: "QVector<{{1}}>"
- map: # `additionalProperties` in OpenAPI
- RoomState:
type: "UnorderedMap<QString, {{1}}>"
moveOnly:
- imports: '"util.h"'
- /.+/:
type: "QHash<QString, {{1}}>"
- imports: <QtCore/QHash>
- - //:
- type: QVariantHash
- imports: <QtCore/QVariant>
+ - //: QVariantHash
- variant: # A sequence `type` (multitype) in OpenAPI
- /^string,null|null,string$/: *QString
- - //: { type: QVariant, imports: <QtCore/QVariant> }
+ - //: QVariant
#operations:
@@ -127,43 +131,75 @@ mustache:
initializer: '{{defaultValue}}'
cjoin: '{{#hasMore}}, {{/hasMore}}'
- openOmittable: "{{^required?}}{{#useOmittable}}{{^defaultValue}}Omittable<{{/defaultValue}}{{/useOmittable}}{{/required?}}"
- closeOmittable: "{{^required?}}{{#useOmittable}}{{^defaultValue}}>{{/defaultValue}}{{/useOmittable}}{{/required?}}"
+ openOmittable:
+ "{{^required?}}{{#useOmittable}}\
+ {{^defaultValue}}Omittable<{{/defaultValue}}\
+ {{/useOmittable}}{{/required?}}"
+ closeOmittable:
+ "{{^required?}}{{#useOmittable}}\
+ {{^defaultValue}}>{{/defaultValue}}\
+ {{/useOmittable}}{{/required?}}"
maybeOmittableType: "{{>openOmittable}}{{dataType.name}}{{>closeOmittable}}"
- qualifiedMaybeOmittableType: "{{>openOmittable}}{{dataType.qualifiedName}}{{>closeOmittable}}"
+ qualifiedMaybeOmittableType:
+ "{{>openOmittable}}{{dataType.qualifiedName}}{{>closeOmittable}}"
- maybeCrefType: "{{#avoidCopy}}const {{/avoidCopy}}{{>maybeOmittableType}}{{#avoidCopy}}&{{/avoidCopy}}{{#moveOnly}}&&{{/moveOnly}}"
+ ref: "{{#avoidCopy}}&{{/avoidCopy}}{{#moveOnly}}&&{{/moveOnly}}"
+ maybeCrefType:
+ "{{#avoidCopy}}const {{/avoidCopy}}{{>maybeOmittableType}}{{>ref}}"
qualifiedMaybeCrefType:
- "{{#avoidCopy}}const {{/avoidCopy}}{{>qualifiedMaybeOmittableType}}{{#avoidCopy}}&{{/avoidCopy}}{{#moveOnly}}&&{{/moveOnly}}"
+ "{{#avoidCopy}}const {{/avoidCopy}}{{>qualifiedMaybeOmittableType}}{{>ref}}"
- maybeCrefJsonObject: "{{^propertyMap}}const QJsonObject&{{/propertyMap}}{{#propertyMap}}QJsonObject{{/propertyMap}}"
- takeOrValue: "{{#propertyMap}}take{{/propertyMap}}{{^propertyMap}}value{{/propertyMap}}"
+ maybeCrefJsonObject:
+ "{{^propertyMap}}const QJsonObject&{{/propertyMap}}\
+ {{#propertyMap}}QJsonObject{{/propertyMap}}"
- initializeDefaultValue: "{{#defaultValue}}{{>initializer}}{{/defaultValue}}{{^defaultValue}}{{>omittedValue}}{{/defaultValue}}"
- joinedParamDecl: '{{>maybeCrefType}} {{paramName}}{{^required?}} = {{>initializeDefaultValue}}{{/required?}}{{>cjoin}}'
- joinedParamDef: '{{>maybeCrefType}} {{paramName}}{{>cjoin}}'
- passQueryParams: '{{#queryParams}}{{paramName}}{{>cjoin}}{{/queryParams}}'
+ takeOrValue:
+ "{{#propertyMap}}take{{/propertyMap}}{{^propertyMap}}value{{/propertyMap}}"
+ takeOrLoad: "{{#moveOnly}}take{{/moveOnly}}{{^moveOnly}}load{{/moveOnly}}"
+
+ initializeDefaultValue:
+ "{{#defaultValue}}{{>initializer}}{{/defaultValue}}\
+ {{^defaultValue}}{{>omittedValue}}{{/defaultValue}}"
+
+ # No inner indents in folded values!
+
+ joinedParamDecl: >-
+ {{>maybeCrefType}} {{paramName}}
+ {{^required?}} = {{>initializeDefaultValue}}{{/required?}}{{>cjoin}}
+ joinedParamDef: "{{>maybeCrefType}} {{paramName}}{{>cjoin}}"
+
+ passPathAndMaybeQuery: >-
+ QStringLiteral("{{basePathWithoutHost}}")
+ {{#pathParts}} % {{_}}{{/pathParts}}{{#queryParams?}},
+ queryTo{{camelCaseOperationId}}(
+ {{#queryParams}}{{paramName}}{{>cjoin}}{{/queryParams}}){{/queryParams?}}
+
+ nonInlineResponseSignature: |-
+ {{>docCommentShort}}
+ {{>maybeOmittableType}} {{paramName}}(){{^moveOnly}} const{{/moveOnly}}
# Doc-comment blocks. Comment indent is managed by clang-format
# (without clang-format there'd have to be a separate partial definition
- # for each indent...)
+ # for each indent...) but we take care of line breaks to maintain
+ # some sanity even before clang-format
- # For structures that are not supposed to have a summary (e.g., JSON schema)
+ # This is for structures that don't expect a summary (e.g., JSON schema)
docCommentShort: |-
{{#description}}
/// {{_}}{{/description}}
+ # For structures with the summary, a common partial for summary is here;
+ # the main part is different in different places
docCommentSummary: |-
{{#summary}} \brief {{summary}}
*{{/summary}}
templates:
data:
- .h: "{{>template.h.mustache}}"
- .cpp: "{{>template.cpp.mustache}}"
+ .h: "{{>data.h.mustache}}"
api:
- .h: "{{>template.h.mustache}}"
- .cpp: "{{>template.cpp.mustache}}"
+ .h: "{{>operation.h.mustache}}"
+ .cpp: "{{>operation.cpp.mustache}}"
#outFilesList: apifiles.txt
diff --git a/gtad/operation.cpp.mustache b/gtad/operation.cpp.mustache
new file mode 100644
index 00000000..3c3396e9
--- /dev/null
+++ b/gtad/operation.cpp.mustache
@@ -0,0 +1,58 @@
+{{>preamble}}
+#include "{{filenameBase}}.h"
+
+#include <QtCore/QStringBuilder>
+
+using namespace Quotient;
+{{#operations}}{{#operation}}
+ {{#queryParams?}}
+
+auto queryTo{{camelCaseOperationId}}(
+ {{#queryParams}}{{>joinedParamDef}}{{/queryParams}})
+{
+ BaseJob::Query _q;{{#queryParams}}
+ addParam<{{^required?}}IfNotEmpty{{/required?}}>(_q,
+ QStringLiteral("{{baseName}}"), {{paramName}});{{/queryParams}}
+ return _q;
+}
+ {{/queryParams?}}
+ {{^hasBody?}}
+
+QUrl {{camelCaseOperationId}}Job::makeRequestUrl(QUrl baseUrl{{#allParams?}},
+ {{#allParams}}{{>joinedParamDef}}{{/allParams}}{{/allParams?}})
+{
+ return BaseJob::makeRequestUrl(std::move(baseUrl), {{>passPathAndMaybeQuery}});
+} {{/hasBody?}}
+
+{{camelCaseOperationId}}Job::{{camelCaseOperationId}}Job(
+ {{#allParams}}{{>joinedParamDef}}{{/allParams}})
+ : BaseJob(HttpVerb::{{#_cap}}{{#_tolower}}{{httpMethod}}{{/_tolower}}{{/_cap}},
+ {{!object name}}QStringLiteral("{{camelCaseOperationId}}Job"),
+ {{>passPathAndMaybeQuery}}
+ {{#skipAuth}}{{#queryParams?}}, {}{{/queryParams?}}, false{{/skipAuth}} )
+{ {{#headerParams}}
+ setRequestHeader("{{baseName}}", {{paramName}}.toLatin1());
+ {{/headerParams}}{{#inlineBody}}{{^propertyMap}}{{^bodyParams?}}
+ setRequestData(Data({{#consumesNonJson?}}{{nameCamelCase}}{{/consumesNonJson?
+ }}{{^consumesNonJson?}}toJson({{nameCamelCase}}){{/consumesNonJson?}}));
+ {{/bodyParams?}}{{/propertyMap}}{{/inlineBody
+ }}{{^consumesNonJson?}}{{#bodyParams?}}
+ QJsonObject _data;
+ {{#propertyMap}}
+ fillJson(_data, {{nameCamelCase}});
+ {{/propertyMap}}{{#inlineBody}}
+ fillJson<{{>maybeOmittableType}}>(_data, {{paramName}});
+ {{/inlineBody}}{{#bodyParams}}
+ addParam<{{^required?}}IfNotEmpty{{/required?}}>(_data,
+ QStringLiteral("{{baseName}}"), {{paramName}});
+ {{/bodyParams}}
+ setRequestData(std::move(_data));
+ {{/bodyParams?}}{{/consumesNonJson?}}{{#producesNonJson?}}
+ setExpectedContentTypes({ {{#produces}}"{{_}}"{{>cjoin}}{{/produces}} });
+ {{/producesNonJson?}}{{^producesNonJson?
+ }}{{#responses}}{{#normalResponse?}}{{#properties}}{{#required?}}
+ addExpectedKey("{{baseName}}");
+ {{/required?}}{{/properties}}{{/normalResponse?}}{{/responses
+ }}{{/producesNonJson?}}
+}
+{{/operation}}{{/operations}}
diff --git a/gtad/operation.h.mustache b/gtad/operation.h.mustache
new file mode 100644
index 00000000..34c8a361
--- /dev/null
+++ b/gtad/operation.h.mustache
@@ -0,0 +1,128 @@
+{{>preamble}}
+#pragma once
+
+#include "jobs/basejob.h"
+{{#imports}}
+#include {{_}}{{/imports}}
+{{#operations.producesNonJson?}}
+#include <QtNetwork/QNetworkReply>{{/operations.producesNonJson?}}
+
+namespace Quotient {
+{{#operations.operation}}
+
+/*!{{>docCommentSummary}}{{#description}}
+ * {{_}}{{/description}}
+ */
+class {{camelCaseOperationId}}Job : public BaseJob {
+public:
+ {{#models}}
+ // Inner data structures
+ {{#model}}
+
+ {{>docCommentShort}}
+ struct {{name}}{{#parents?}} :
+ {{!Quotient:: is a workaround for cases when the same name is used for
+ the outer and the inner structure (unfortunately very easy
+ to hit if you don't give a title to the structure that has
+ $ref and other properties)}}
+ {{#parents}}Quotient::{{name}}{{>cjoin}}{{/parents}}{{/parents?}}
+ {
+ {{#vars}}
+ {{>docCommentShort}}
+ {{>maybeOmittableType}} {{nameCamelCase}};
+ {{/vars}}
+ {{#propertyMap}}
+ {{>docCommentShort}}
+ {{>maybeOmittableType}} {{nameCamelCase}};
+ {{/propertyMap}}
+ };
+ {{/model}}
+
+ // Construction/destruction
+
+ {{/models}}
+ {{#allParams?}}
+ /*!{{>docCommentSummary}}
+ {{#allParams}}
+ *
+ * \param {{nameCamelCase}}{{#description}}
+ * {{_}}{{/description}}
+ {{/allParams}}
+ */
+ {{/allParams?}}{{^allParams?}}
+ {{#summary}}
+ /// {{summary}}
+ {{/summary}}
+ {{/allParams?}}
+ explicit {{camelCaseOperationId}}Job({{#allParams}}{{>joinedParamDecl}}{{/allParams}});
+ {{^hasBody?}}
+
+ /*! \brief Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for {{camelCaseOperationId}}Job
+ * is necessary but the job itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl{{#allParams?}},
+ {{#allParams}}{{>joinedParamDecl}}{{/allParams}}{{/allParams?}});
+ {{/hasBody?}}
+ {{#responses}}{{#normalResponse?}}{{#allProperties?}}
+
+ // Result properties
+ {{#headers}}
+
+ {{>nonInlineResponseSignature}}
+ {
+ return reply()->rawHeader("{{baseName}}");
+ }
+ {{/headers}}{{#inlineResponse}}
+
+ {{>docCommentShort}}
+ {{dataType.name}} {{paramName}}(){{^moveOnly}}{{^producesNonJson?}} const{{/producesNonJson?}}{{/moveOnly}}
+ {
+ return {{#producesNonJson?}}reply(){{/producesNonJson?}}
+ {{^producesNonJson?
+ }}fromJson<{{dataType.name}}>(jsonData()){{/producesNonJson?
+ }};
+ }
+ {{/inlineResponse}}{{#properties}}
+
+ {{!there's nothing in #properties if the response is inline}}
+ {{>nonInlineResponseSignature}}
+ {
+ return {{>takeOrLoad}}FromJson<{{>maybeOmittableType}}>("{{baseName}}"_ls);
+ }
+ {{/properties}}
+ {{/allProperties?}}{{/normalResponse?}}{{/responses}}
+};
+ {{#models.model}}
+
+template <> struct JsonObjectConverter<{{qualifiedName}}> {
+ {{#in?}}
+ static void dumpTo(QJsonObject& jo, const {{qualifiedName}}& pod)
+ { {{#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({{>maybeCrefJsonObject}} jo, {{qualifiedName}}& result)
+ { {{#parents}}
+ fillFromJson<{{name}}{{!of the parent!}}>(jo, result);
+ {{/parents}}{{#vars}}
+ fromJson(jo.{{>takeOrValue}}("{{baseName}}"_ls),
+ result.{{nameCamelCase}});
+ {{/vars}}{{#propertyMap}}
+ fromJson(jo, result.{{nameCamelCase}});
+ {{/propertyMap}}
+ }
+ {{/out?}}
+};
+ {{/models.model}}
+{{/operations.operation}}
+
+} // namespace Quotient
diff --git a/gtad/template.cpp.mustache b/gtad/template.cpp.mustache
deleted file mode 100644
index b3bd4de9..00000000
--- a/gtad/template.cpp.mustache
+++ /dev/null
@@ -1,182 +0,0 @@
-{{>preamble}}
-#include "{{filenameBase}}.h"
-{{^models}}
-#include "converters.h"{{/models}}
-{{#operations}}
- {{#producesNonJson?}}
-#include <QtNetwork/QNetworkReply>
- {{/producesNonJson?}}
-#include <QtCore/QStringBuilder>
-{{/operations}}
-
-using namespace Quotient;
-
-{{#models.model}}
- {{#in?}}
-void JsonObjectConverter<{{qualifiedName}}>::dumpTo(
- QJsonObject& jo, const {{qualifiedName}}& pod)
-{ {{#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?}}
-void JsonObjectConverter<{{qualifiedName}}>::fillFrom(
- {{>maybeCrefJsonObject}} jo, {{qualifiedName}}& result)
-{ {{#parents}}
- fillFromJson<{{qualifiedName}}>(jo, result);
- {{/parents}}{{#vars}}
- fromJson(jo.{{>takeOrValue}}("{{baseName}}"_ls), result.{{nameCamelCase}});
- {{/vars}}{{#propertyMap}}
- fromJson(jo, result.{{nameCamelCase}});
- {{/propertyMap}}
-}
- {{/out?}}
-
-{{/models.model}}
-{{#operations}}
-
-static const auto basePath = QStringLiteral("{{basePathWithoutHost}}");
- {{#operation}}{{#models}}
-
-// Converters
-namespace Quotient {
- {{#model}}
-
-template <> struct JsonObjectConverter<{{qualifiedName}}> {
- {{#in?}}
- static void dumpTo(QJsonObject& jo, const {{qualifiedName}}& pod)
- { {{#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({{>maybeCrefJsonObject}} jo, {{qualifiedName}}& result)
- { {{#parents}}
- fillFromJson<{{qualifiedName}}{{!of the parent!}}>(jo, result);
- {{/parents}}{{#vars}}
- fromJson(jo.{{>takeOrValue}}("{{baseName}}"_ls),
- result.{{nameCamelCase}});
- {{/vars}}{{#propertyMap}}
- fromJson(jo, result.{{nameCamelCase}});
- {{/propertyMap}}
- }
- {{/out?}}
-};
- {{/model}}
-
-} // namespace Quotient
- {{/models}}
- {{#responses}}{{#normalResponse?}}{{#allProperties?}}
-
-class {{camelCaseOperationId}}Job::Private
-{
- public:{{#allProperties}}
- {{>maybeOmittableType}} {{paramName}};{{/allProperties}}
-};
- {{/allProperties?}}{{/normalResponse?}}{{/responses}}
- {{#queryParams?}}
-
-BaseJob::Query queryTo{{camelCaseOperationId}}(
- {{#queryParams}}{{>joinedParamDef}}{{/queryParams}})
-{
- BaseJob::Query _q;{{#queryParams}}
- addParam<{{^required?}}IfNotEmpty{{/required?}}>(_q,
- QStringLiteral("{{baseName}}"), {{paramName}});{{/queryParams}}
- return _q;
-}
- {{/queryParams?}}
- {{^bodyParams}}
-
-QUrl {{camelCaseOperationId}}Job::makeRequestUrl(QUrl baseUrl{{#allParams?}},
- {{#allParams}}{{>joinedParamDef}}{{/allParams}}{{/allParams?}})
-{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath{{#pathParts}} % {{_}}{{/pathParts}}{{#queryParams?}},
- queryTo{{camelCaseOperationId}}({{>passQueryParams}}){{/queryParams?}});
-} {{/bodyParams}}
-
-{{camelCaseOperationId}}Job::{{camelCaseOperationId}}Job(
- {{#allParams}}{{>joinedParamDef}}{{/allParams}})
- : BaseJob(HttpVerb::{{#_cap}}{{#_tolower}}{{httpMethod}}{{/_tolower}}{{/_cap}},
- QStringLiteral("{{camelCaseOperationId}}Job"), {{!object name}}
- basePath{{#pathParts}} % {{_}}{{/pathParts}} {{!API endpoint}}
- {{#queryParams?
- }} , queryTo{{camelCaseOperationId}}({{>passQueryParams}})
- {{/queryParams?
- }}{{#skipAuth}}{{#queryParams?}}, {}{{/queryParams?}}, false{{/skipAuth}} )
- {{#responses}}{{#normalResponse?}}{{#allProperties?
- }}, d(new Private){{/allProperties?}}{{/normalResponse?}}{{/responses}}
-{ {{#headerParams}}
- setRequestHeader("{{baseName}}", {{paramName}}.toLatin1());
- {{/headerParams}}{{#bodyParams?}}
- {{#inlineBody}}
- setRequestData(Data({{!avoid extra linebreaks}}{{
- #consumesNonJson?}}{{nameCamelCase}}{{/consumesNonJson?}}{{
- ^consumesNonJson?}}toJson({{nameCamelCase}}){{/consumesNonJson?
- }}));
- {{/inlineBody}}{{^inlineBody}}
- QJsonObject _data;
- {{#bodyParams}}
- addParam<{{^required?}}IfNotEmpty{{/required?}}>(_data,
- QStringLiteral("{{baseName}}"), {{paramName}});
- {{/bodyParams}}
- setRequestData(_data);
- {{/inlineBody}}
- {{/bodyParams?}}{{#producesNonJson?}}
- setExpectedContentTypes({ {{#produces}}"{{_}}"{{>cjoin}}{{/produces}} });
- {{/producesNonJson?}}
-}
- {{#responses}}{{#normalResponse?}}{{#allProperties?}}
-
-{{camelCaseOperationId}}Job::~{{camelCaseOperationId}}Job() = default;
- {{#allProperties}}
-
-{{>qualifiedMaybeCrefType}}
- {{camelCaseOperationId}}Job::{{paramName}}(){{^moveOnly}} const{{/moveOnly}}
-{
- return {{#moveOnly}}std::move({{/moveOnly}}d->{{paramName}}{{#moveOnly}}){{/moveOnly}};
-}
- {{/allProperties}}
-
- {{#producesNonJson?}}
-BaseJob::Status {{camelCaseOperationId}}Job::parseReply(QNetworkReply* reply)
-{
- {{! We don't check for required headers yet }}
- {{#headers}}d->{{paramName}} = reply->rawHeader("{{baseName}}");
- {{/headers}}{{#properties}}d->{{paramName}} = reply;{{/properties}}
- return Success;
-}
- {{/producesNonJson?}}{{^producesNonJson?}}
-BaseJob::Status {{camelCaseOperationId}}Job::parseJson(const QJsonDocument& data)
-{
- {{#inlineResponse}}
- fromJson(data, d->{{paramName}});
- {{/inlineResponse}}{{^inlineResponse}}
- auto json = data.object();
- {{#properties}}{{#required?}}
- if (!json.contains("{{baseName}}"_ls))
- return { IncorrectResponse,
- "The key '{{baseName}}' not found in the response" };
- {{/required?}}
- fromJson(json.value("{{baseName}}"_ls), d->{{paramName}});
- {{/properties}}
- {{/inlineResponse}}
-
- return Success;
-}
- {{/producesNonJson?}}
- {{/allProperties?}}{{/normalResponse?}}{{/responses}}
-{{/operation}}{{/operations}}
diff --git a/gtad/template.h.mustache b/gtad/template.h.mustache
deleted file mode 100644
index 404aafe8..00000000
--- a/gtad/template.h.mustache
+++ /dev/null
@@ -1,119 +0,0 @@
-{{>preamble}}
-#pragma once
-
-{{#operations}}
-#include "jobs/basejob.h"{{/operations}}
-{{#models}}
-#include "converters.h"{{/models}}
-{{#imports}}
-#include {{_}}{{/imports}}
-
-namespace Quotient {
-{{#models}}
-
-// Data structures
-
- {{#model}}
-{{>docCommentShort}}
-struct {{name}}{{#parents?}} : {{#parents}}{{name}}{{>cjoin}}{{/parents}}{{/parents?}}
-{ {{#vars}}
-
- {{>docCommentShort}}
- {{>maybeOmittableType}} {{nameCamelCase}};
- {{/vars}}{{#propertyMap}}
-
- {{>docCommentShort}}
- {{>maybeOmittableType}} {{nameCamelCase}};
- {{/propertyMap}}
-};
-
-template <> struct JsonObjectConverter<{{name}}>
-{
- {{#in?}}
- static void dumpTo(QJsonObject& jo, const {{name}}& pod);
- {{/in?}}
- {{#out?}}
- static void fillFrom({{>maybeCrefJsonObject}} jo, {{name}}& pod);
- {{/out?}}
-};
- {{/model}}
-{{/models}}
-{{#operations}}
-
-// Operations
- {{#operation}}
-
-/*!{{>docCommentSummary}}{{#description}}
- * {{_}}{{/description}}
- */
-class {{camelCaseOperationId}}Job : public BaseJob {
-public: {{#models}}
- // Inner data structures
- {{#model}}
-
- {{>docCommentShort}}
- struct {{name}}{{#parents?}} :
- {{#parents}}{{name}}{{>cjoin}}{{/parents}}{{/parents?}}
- {
- {{#vars}}
- {{>docCommentShort}}
- {{>maybeOmittableType}} {{nameCamelCase}};
- {{/vars}}
- {{#propertyMap}}
- {{>docCommentShort}}
- {{>maybeOmittableType}} {{nameCamelCase}};
- {{/propertyMap}}
- };
- {{/model}}
-
- // Construction/destruction
-
- {{/models}}
- {{^allParams?}}
- {{#summary}}
- /// {{summary}}
- {{/summary}}
- {{/allParams?}}{{#allParams?}}
- /*!{{>docCommentSummary}}
- {{#allParams}}
- * \param {{nameCamelCase}}{{#description}}
- * {{_}}{{/description}}
- {{/allParams}}
- */
- {{/allParams?}}
- explicit {{camelCaseOperationId}}Job({{#allParams}}{{>joinedParamDecl}}{{/allParams}});
- {{^bodyParams}}
-
- /*! \brief Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for {{camelCaseOperationId}}Job
- * is necessary but the job itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl{{#allParams?}},
- {{#allParams}}{{>joinedParamDecl}}{{/allParams}}{{/allParams?}});
- {{/bodyParams}}
- {{#responses}}{{#normalResponse?}}{{#allProperties?}}
- ~{{camelCaseOperationId}}Job() override;
-
- // Result properties
- {{#allProperties}}
-
- {{>docCommentShort}}
- {{>maybeCrefType}} {{paramName}}(){{^moveOnly}} const{{/moveOnly}};
- {{/allProperties}}
-
-protected: {{#producesNonJson?}}
- Status parseReply(QNetworkReply* reply) override;
- {{/producesNonJson?}}{{^producesNonJson?}}
- Status parseJson(const QJsonDocument& data) override;
- {{/producesNonJson?}}
-
-private:
- class Private;
- QScopedPointer<Private> d;
- {{/allProperties?}}{{/normalResponse?}}{{/responses}}
-};
- {{/operation}}
-{{/operations}}
-
-} // namespace Quotient
diff --git a/lib/application-service/definitions/location.cpp b/lib/application-service/definitions/location.cpp
deleted file mode 100644
index 0a054029..00000000
--- a/lib/application-service/definitions/location.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#include "location.h"
-
-using namespace Quotient;
-
-void JsonObjectConverter<ThirdPartyLocation>::dumpTo(
- QJsonObject& jo, const ThirdPartyLocation& pod)
-{
- addParam<>(jo, QStringLiteral("alias"), pod.alias);
- addParam<>(jo, QStringLiteral("protocol"), pod.protocol);
- addParam<>(jo, QStringLiteral("fields"), pod.fields);
-}
-
-void JsonObjectConverter<ThirdPartyLocation>::fillFrom(const QJsonObject& jo,
- ThirdPartyLocation& 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 e4c2d096..6801c99f 100644
--- a/lib/application-service/definitions/location.h
+++ b/lib/application-service/definitions/location.h
@@ -6,12 +6,8 @@
#include "converters.h"
-#include <QtCore/QJsonObject>
-
namespace Quotient {
-// Data structures
-
struct ThirdPartyLocation {
/// An alias for a matrix room.
QString alias;
@@ -25,8 +21,18 @@ struct ThirdPartyLocation {
template <>
struct JsonObjectConverter<ThirdPartyLocation> {
- static void dumpTo(QJsonObject& jo, const ThirdPartyLocation& pod);
- static void fillFrom(const QJsonObject& jo, ThirdPartyLocation& pod);
+ static void dumpTo(QJsonObject& jo, const ThirdPartyLocation& pod)
+ {
+ addParam<>(jo, QStringLiteral("alias"), pod.alias);
+ addParam<>(jo, QStringLiteral("protocol"), pod.protocol);
+ addParam<>(jo, QStringLiteral("fields"), pod.fields);
+ }
+ static void fillFrom(const QJsonObject& jo, ThirdPartyLocation& pod)
+ {
+ fromJson(jo.value("alias"_ls), pod.alias);
+ fromJson(jo.value("protocol"_ls), pod.protocol);
+ fromJson(jo.value("fields"_ls), pod.fields);
+ }
};
} // namespace Quotient
diff --git a/lib/application-service/definitions/protocol.cpp b/lib/application-service/definitions/protocol.cpp
deleted file mode 100644
index 8c66aa4d..00000000
--- a/lib/application-service/definitions/protocol.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#include "protocol.h"
-
-using namespace Quotient;
-
-void JsonObjectConverter<FieldType>::dumpTo(QJsonObject& jo,
- const FieldType& pod)
-{
- addParam<>(jo, QStringLiteral("regexp"), pod.regexp);
- addParam<>(jo, QStringLiteral("placeholder"), pod.placeholder);
-}
-
-void JsonObjectConverter<FieldType>::fillFrom(const QJsonObject& jo,
- FieldType& result)
-{
- fromJson(jo.value("regexp"_ls), result.regexp);
- fromJson(jo.value("placeholder"_ls), result.placeholder);
-}
-
-void JsonObjectConverter<ProtocolInstance>::dumpTo(QJsonObject& jo,
- const ProtocolInstance& pod)
-{
- 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);
-}
-
-void JsonObjectConverter<ProtocolInstance>::fillFrom(const QJsonObject& jo,
- ProtocolInstance& 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);
-}
-
-void JsonObjectConverter<ThirdPartyProtocol>::dumpTo(
- QJsonObject& jo, const ThirdPartyProtocol& pod)
-{
- 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);
-}
-
-void JsonObjectConverter<ThirdPartyProtocol>::fillFrom(const QJsonObject& jo,
- ThirdPartyProtocol& 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 ac1e50e2..6aee9c57 100644
--- a/lib/application-service/definitions/protocol.h
+++ b/lib/application-service/definitions/protocol.h
@@ -6,14 +6,7 @@
#include "converters.h"
-#include <QtCore/QHash>
-#include <QtCore/QJsonObject>
-#include <QtCore/QVector>
-
namespace Quotient {
-
-// Data structures
-
/// Definition of valid values for a field.
struct FieldType {
/// A regular expression for validation of a field's value. This may be
@@ -27,8 +20,16 @@ struct FieldType {
template <>
struct JsonObjectConverter<FieldType> {
- static void dumpTo(QJsonObject& jo, const FieldType& pod);
- static void fillFrom(const QJsonObject& jo, FieldType& pod);
+ static void dumpTo(QJsonObject& jo, const FieldType& pod)
+ {
+ addParam<>(jo, QStringLiteral("regexp"), pod.regexp);
+ addParam<>(jo, QStringLiteral("placeholder"), pod.placeholder);
+ }
+ static void fillFrom(const QJsonObject& jo, FieldType& pod)
+ {
+ fromJson(jo.value("regexp"_ls), pod.regexp);
+ fromJson(jo.value("placeholder"_ls), pod.placeholder);
+ }
};
struct ProtocolInstance {
@@ -48,8 +49,20 @@ struct ProtocolInstance {
template <>
struct JsonObjectConverter<ProtocolInstance> {
- static void dumpTo(QJsonObject& jo, const ProtocolInstance& pod);
- static void fillFrom(const QJsonObject& jo, ProtocolInstance& pod);
+ static void dumpTo(QJsonObject& jo, const ProtocolInstance& pod)
+ {
+ 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);
+ }
+ static void fillFrom(const QJsonObject& jo, ProtocolInstance& pod)
+ {
+ fromJson(jo.value("desc"_ls), pod.desc);
+ fromJson(jo.value("icon"_ls), pod.icon);
+ fromJson(jo.value("fields"_ls), pod.fields);
+ fromJson(jo.value("network_id"_ls), pod.networkId);
+ }
};
struct ThirdPartyProtocol {
@@ -84,8 +97,22 @@ struct ThirdPartyProtocol {
template <>
struct JsonObjectConverter<ThirdPartyProtocol> {
- static void dumpTo(QJsonObject& jo, const ThirdPartyProtocol& pod);
- static void fillFrom(const QJsonObject& jo, ThirdPartyProtocol& pod);
+ static void dumpTo(QJsonObject& jo, const ThirdPartyProtocol& pod)
+ {
+ 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);
+ }
+ static void fillFrom(const QJsonObject& jo, ThirdPartyProtocol& pod)
+ {
+ fromJson(jo.value("user_fields"_ls), pod.userFields);
+ fromJson(jo.value("location_fields"_ls), pod.locationFields);
+ fromJson(jo.value("icon"_ls), pod.icon);
+ fromJson(jo.value("field_types"_ls), pod.fieldTypes);
+ fromJson(jo.value("instances"_ls), pod.instances);
+ }
};
} // namespace Quotient
diff --git a/lib/application-service/definitions/user.cpp b/lib/application-service/definitions/user.cpp
deleted file mode 100644
index 17d15a20..00000000
--- a/lib/application-service/definitions/user.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#include "user.h"
-
-using namespace Quotient;
-
-void JsonObjectConverter<ThirdPartyUser>::dumpTo(QJsonObject& jo,
- const ThirdPartyUser& pod)
-{
- addParam<>(jo, QStringLiteral("userid"), pod.userid);
- addParam<>(jo, QStringLiteral("protocol"), pod.protocol);
- addParam<>(jo, QStringLiteral("fields"), pod.fields);
-}
-
-void JsonObjectConverter<ThirdPartyUser>::fillFrom(const QJsonObject& jo,
- ThirdPartyUser& 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 0d1984b6..3342ef80 100644
--- a/lib/application-service/definitions/user.h
+++ b/lib/application-service/definitions/user.h
@@ -6,12 +6,8 @@
#include "converters.h"
-#include <QtCore/QJsonObject>
-
namespace Quotient {
-// Data structures
-
struct ThirdPartyUser {
/// A Matrix User ID represting a third party user.
QString userid;
@@ -25,8 +21,18 @@ struct ThirdPartyUser {
template <>
struct JsonObjectConverter<ThirdPartyUser> {
- static void dumpTo(QJsonObject& jo, const ThirdPartyUser& pod);
- static void fillFrom(const QJsonObject& jo, ThirdPartyUser& pod);
+ static void dumpTo(QJsonObject& jo, const ThirdPartyUser& pod)
+ {
+ addParam<>(jo, QStringLiteral("userid"), pod.userid);
+ addParam<>(jo, QStringLiteral("protocol"), pod.protocol);
+ addParam<>(jo, QStringLiteral("fields"), pod.fields);
+ }
+ static void fillFrom(const QJsonObject& jo, ThirdPartyUser& pod)
+ {
+ fromJson(jo.value("userid"_ls), pod.userid);
+ fromJson(jo.value("protocol"_ls), pod.protocol);
+ fromJson(jo.value("fields"_ls), pod.fields);
+ }
};
} // namespace Quotient
diff --git a/lib/connection.cpp b/lib/connection.cpp
index 26de0c5f..50e31d52 100644
--- a/lib/connection.cpp
+++ b/lib/connection.cpp
@@ -480,8 +480,8 @@ void Connection::sync(int timeout)
d->syncTimeout = timeout;
Filter filter;
- filter.room.edit().timeline.edit().limit.emplace(100);
- filter.room.edit().state.edit().lazyLoadMembers.emplace(d->lazyLoading);
+ filter.room.timeline.limit.emplace(100);
+ filter.room.state.lazyLoadMembers.emplace(d->lazyLoading);
auto job = d->syncJob =
callApi<SyncJob>(BackgroundRequest, d->data->lastEvent(), filter,
timeout);
diff --git a/lib/csapi/account-data.cpp b/lib/csapi/account-data.cpp
index b7825718..6a40e908 100644
--- a/lib/csapi/account-data.cpp
+++ b/lib/csapi/account-data.cpp
@@ -4,18 +4,15 @@
#include "account-data.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
SetAccountDataJob::SetAccountDataJob(const QString& userId, const QString& type,
const QJsonObject& content)
: BaseJob(HttpVerb::Put, QStringLiteral("SetAccountDataJob"),
- basePath % "/user/" % userId % "/account_data/" % type)
+ QStringLiteral("/_matrix/client/r0") % "/user/" % userId
+ % "/account_data/" % type)
{
setRequestData(Data(toJson(content)));
}
@@ -24,13 +21,14 @@ QUrl GetAccountDataJob::makeRequestUrl(QUrl baseUrl, const QString& userId,
const QString& type)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/user/" % userId
- % "/account_data/" % type);
+ QStringLiteral("/_matrix/client/r0") % "/user/"
+ % userId % "/account_data/" % type);
}
GetAccountDataJob::GetAccountDataJob(const QString& userId, const QString& type)
: BaseJob(HttpVerb::Get, QStringLiteral("GetAccountDataJob"),
- basePath % "/user/" % userId % "/account_data/" % type)
+ QStringLiteral("/_matrix/client/r0") % "/user/" % userId
+ % "/account_data/" % type)
{}
SetAccountDataPerRoomJob::SetAccountDataPerRoomJob(const QString& userId,
@@ -38,8 +36,8 @@ SetAccountDataPerRoomJob::SetAccountDataPerRoomJob(const QString& userId,
const QString& type,
const QJsonObject& content)
: BaseJob(HttpVerb::Put, QStringLiteral("SetAccountDataPerRoomJob"),
- basePath % "/user/" % userId % "/rooms/" % roomId
- % "/account_data/" % type)
+ QStringLiteral("/_matrix/client/r0") % "/user/" % userId
+ % "/rooms/" % roomId % "/account_data/" % type)
{
setRequestData(Data(toJson(content)));
}
@@ -50,14 +48,15 @@ QUrl GetAccountDataPerRoomJob::makeRequestUrl(QUrl baseUrl,
const QString& type)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/user/" % userId % "/rooms/"
- % roomId % "/account_data/" % type);
+ QStringLiteral("/_matrix/client/r0")
+ % "/user/" % userId % "/rooms/" % roomId
+ % "/account_data/" % type);
}
GetAccountDataPerRoomJob::GetAccountDataPerRoomJob(const QString& userId,
const QString& roomId,
const QString& type)
: BaseJob(HttpVerb::Get, QStringLiteral("GetAccountDataPerRoomJob"),
- basePath % "/user/" % userId % "/rooms/" % roomId
- % "/account_data/" % type)
+ QStringLiteral("/_matrix/client/r0") % "/user/" % userId
+ % "/rooms/" % roomId % "/account_data/" % type)
{}
diff --git a/lib/csapi/account-data.h b/lib/csapi/account-data.h
index a8dba5c0..1c7b555b 100644
--- a/lib/csapi/account-data.h
+++ b/lib/csapi/account-data.h
@@ -6,12 +6,8 @@
#include "jobs/basejob.h"
-#include <QtCore/QJsonObject>
-
namespace Quotient {
-// Operations
-
/*! \brief Set some account_data for the user.
*
* Set some account_data for the client. This config is only visible to the user
@@ -22,12 +18,15 @@ class SetAccountDataJob : public BaseJob {
public:
/*! \brief Set some account_data for the user.
*
+ *
* \param userId
* The ID of the user to set account_data for. The access token must be
* authorized to make requests for this user ID.
+ *
* \param type
* The event type of the account_data to set. Custom types should be
* namespaced to avoid clashes.
+ *
* \param content
* The content of the account_data
*/
@@ -44,9 +43,11 @@ class GetAccountDataJob : public BaseJob {
public:
/*! \brief Get some account_data for the user.
*
+ *
* \param userId
* The ID of the user to get account_data for. The access token must be
* authorized to make requests for this user ID.
+ *
* \param type
* The event type of the account_data to get. Custom types should be
* namespaced to avoid clashes.
@@ -72,14 +73,18 @@ class SetAccountDataPerRoomJob : public BaseJob {
public:
/*! \brief Set some account_data for the user.
*
+ *
* \param userId
* The ID of the user to set account_data for. The access token must be
* authorized to make requests for this user ID.
+ *
* \param roomId
* The ID of the room to set account_data on.
+ *
* \param type
* The event type of the account_data to set. Custom types should be
* namespaced to avoid clashes.
+ *
* \param content
* The content of the account_data
*/
@@ -97,11 +102,14 @@ class GetAccountDataPerRoomJob : public BaseJob {
public:
/*! \brief Get some account_data for the user.
*
+ *
* \param userId
* The ID of the user to set account_data for. The access token must be
* authorized to make requests for this user ID.
+ *
* \param roomId
* The ID of the room to get account_data for.
+ *
* \param type
* The event type of the account_data to get. Custom types should be
* namespaced to avoid clashes.
diff --git a/lib/csapi/admin.cpp b/lib/csapi/admin.cpp
index 14173e94..9619c441 100644
--- a/lib/csapi/admin.cpp
+++ b/lib/csapi/admin.cpp
@@ -4,78 +4,18 @@
#include "admin.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-// Converters
-namespace Quotient {
-
-template <>
-struct JsonObjectConverter<GetWhoIsJob::ConnectionInfo> {
- static void fillFrom(const QJsonObject& jo,
- GetWhoIsJob::ConnectionInfo& 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 JsonObjectConverter<GetWhoIsJob::SessionInfo> {
- static void fillFrom(const QJsonObject& jo, GetWhoIsJob::SessionInfo& result)
- {
- fromJson(jo.value("connections"_ls), result.connections);
- }
-};
-
-template <>
-struct JsonObjectConverter<GetWhoIsJob::DeviceInfo> {
- static void fillFrom(const QJsonObject& jo, GetWhoIsJob::DeviceInfo& result)
- {
- fromJson(jo.value("sessions"_ls), result.sessions);
- }
-};
-
-} // namespace Quotient
-
-class GetWhoIsJob::Private {
-public:
- QString userId;
- QHash<QString, DeviceInfo> devices;
-};
-
QUrl GetWhoIsJob::makeRequestUrl(QUrl baseUrl, const QString& userId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/admin/whois/" % userId);
+ QStringLiteral("/_matrix/client/r0")
+ % "/admin/whois/" % userId);
}
GetWhoIsJob::GetWhoIsJob(const QString& userId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetWhoIsJob"),
- basePath % "/admin/whois/" % userId)
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/admin/whois/" % userId)
{}
-
-GetWhoIsJob::~GetWhoIsJob() = default;
-
-const QString& GetWhoIsJob::userId() const { return d->userId; }
-
-const QHash<QString, GetWhoIsJob::DeviceInfo>& GetWhoIsJob::devices() const
-{
- return d->devices;
-}
-
-BaseJob::Status GetWhoIsJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("user_id"_ls), d->userId);
- fromJson(json.value("devices"_ls), d->devices);
-
- return Success;
-}
diff --git a/lib/csapi/admin.h b/lib/csapi/admin.h
index 75ae1eb0..6ad7d08d 100644
--- a/lib/csapi/admin.h
+++ b/lib/csapi/admin.h
@@ -4,17 +4,10 @@
#pragma once
-#include "converters.h"
-
#include "jobs/basejob.h"
-#include <QtCore/QHash>
-#include <QtCore/QVector>
-
namespace Quotient {
-// Operations
-
/*! \brief Gets information about a particular user.
*
* Gets information about a particular user.
@@ -66,6 +59,7 @@ public:
/*! \brief Gets information about a particular user.
*
+ *
* \param userId
* The user to look up.
*/
@@ -77,22 +71,44 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId);
- ~GetWhoIsJob() override;
// Result properties
/// The Matrix user ID of the user.
- const QString& userId() const;
+ QString userId() const { return loadFromJson<QString>("user_id"_ls); }
- /// Each key is an identitfier for one of the user's devices.
- const QHash<QString, DeviceInfo>& devices() const;
+ /// Each key is an identifier for one of the user's devices.
+ QHash<QString, DeviceInfo> devices() const
+ {
+ return loadFromJson<QHash<QString, DeviceInfo>>("devices"_ls);
+ }
+};
+
+template <>
+struct JsonObjectConverter<GetWhoIsJob::ConnectionInfo> {
+ static void fillFrom(const QJsonObject& jo,
+ GetWhoIsJob::ConnectionInfo& result)
+ {
+ fromJson(jo.value("ip"_ls), result.ip);
+ fromJson(jo.value("last_seen"_ls), result.lastSeen);
+ fromJson(jo.value("user_agent"_ls), result.userAgent);
+ }
+};
-protected:
- Status parseJson(const QJsonDocument& data) override;
+template <>
+struct JsonObjectConverter<GetWhoIsJob::SessionInfo> {
+ static void fillFrom(const QJsonObject& jo, GetWhoIsJob::SessionInfo& result)
+ {
+ fromJson(jo.value("connections"_ls), result.connections);
+ }
+};
-private:
- class Private;
- QScopedPointer<Private> d;
+template <>
+struct JsonObjectConverter<GetWhoIsJob::DeviceInfo> {
+ static void fillFrom(const QJsonObject& jo, GetWhoIsJob::DeviceInfo& result)
+ {
+ fromJson(jo.value("sessions"_ls), result.sessions);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/administrative_contact.cpp b/lib/csapi/administrative_contact.cpp
index 36d93e73..fa4f475a 100644
--- a/lib/csapi/administrative_contact.cpp
+++ b/lib/csapi/administrative_contact.cpp
@@ -4,164 +4,100 @@
#include "administrative_contact.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-// Converters
-namespace Quotient {
-
-template <>
-struct JsonObjectConverter<GetAccount3PIDsJob::ThirdPartyIdentifier> {
- static void fillFrom(const QJsonObject& jo,
- GetAccount3PIDsJob::ThirdPartyIdentifier& 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 Quotient
-
-class GetAccount3PIDsJob::Private {
-public:
- QVector<ThirdPartyIdentifier> threepids;
-};
-
QUrl GetAccount3PIDsJob::makeRequestUrl(QUrl baseUrl)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/account/3pid");
+ QStringLiteral("/_matrix/client/r0")
+ % "/account/3pid");
}
GetAccount3PIDsJob::GetAccount3PIDsJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetAccount3PIDsJob"),
- basePath % "/account/3pid")
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/account/3pid")
{}
-GetAccount3PIDsJob::~GetAccount3PIDsJob() = default;
-
-const QVector<GetAccount3PIDsJob::ThirdPartyIdentifier>&
-GetAccount3PIDsJob::threepids() const
+Post3PIDsJob::Post3PIDsJob(const ThreePidCredentials& threePidCreds)
+ : BaseJob(HttpVerb::Post, QStringLiteral("Post3PIDsJob"),
+ QStringLiteral("/_matrix/client/r0") % "/account/3pid")
{
- return d->threepids;
+ QJsonObject _data;
+ addParam<>(_data, QStringLiteral("three_pid_creds"), threePidCreds);
+ setRequestData(std::move(_data));
}
-BaseJob::Status GetAccount3PIDsJob::parseJson(const QJsonDocument& data)
+Add3PIDJob::Add3PIDJob(const QString& clientSecret, const QString& sid,
+ const Omittable<AuthenticationData>& auth)
+ : BaseJob(HttpVerb::Post, QStringLiteral("Add3PIDJob"),
+ QStringLiteral("/_matrix/client/r0") % "/account/3pid/add")
{
- auto json = data.object();
- fromJson(json.value("threepids"_ls), d->threepids);
-
- return Success;
+ QJsonObject _data;
+ addParam<IfNotEmpty>(_data, QStringLiteral("auth"), auth);
+ addParam<>(_data, QStringLiteral("client_secret"), clientSecret);
+ addParam<>(_data, QStringLiteral("sid"), sid);
+ setRequestData(std::move(_data));
}
-// Converters
-namespace Quotient {
-
-template <>
-struct JsonObjectConverter<Post3PIDsJob::ThreePidCredentials> {
- 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 Quotient
-
-Post3PIDsJob::Post3PIDsJob(const ThreePidCredentials& threePidCreds,
- Omittable<bool> bind)
- : BaseJob(HttpVerb::Post, QStringLiteral("Post3PIDsJob"),
- basePath % "/account/3pid")
+Bind3PIDJob::Bind3PIDJob(const QString& clientSecret, const QString& idServer,
+ const QString& idAccessToken, const QString& sid)
+ : BaseJob(HttpVerb::Post, QStringLiteral("Bind3PIDJob"),
+ QStringLiteral("/_matrix/client/r0") % "/account/3pid/bind")
{
QJsonObject _data;
- addParam<>(_data, QStringLiteral("three_pid_creds"), threePidCreds);
- addParam<IfNotEmpty>(_data, QStringLiteral("bind"), bind);
- setRequestData(_data);
+ addParam<>(_data, QStringLiteral("client_secret"), clientSecret);
+ addParam<>(_data, QStringLiteral("id_server"), idServer);
+ addParam<>(_data, QStringLiteral("id_access_token"), idAccessToken);
+ addParam<>(_data, QStringLiteral("sid"), sid);
+ setRequestData(std::move(_data));
}
Delete3pidFromAccountJob::Delete3pidFromAccountJob(const QString& medium,
- const QString& address)
+ const QString& address,
+ const QString& idServer)
: BaseJob(HttpVerb::Post, QStringLiteral("Delete3pidFromAccountJob"),
- basePath % "/account/3pid/delete")
+ QStringLiteral("/_matrix/client/r0") % "/account/3pid/delete")
{
QJsonObject _data;
+ addParam<IfNotEmpty>(_data, QStringLiteral("id_server"), idServer);
addParam<>(_data, QStringLiteral("medium"), medium);
addParam<>(_data, QStringLiteral("address"), address);
- setRequestData(_data);
+ setRequestData(std::move(_data));
+ addExpectedKey("id_server_unbind_result");
}
-class RequestTokenTo3PIDEmailJob::Private {
-public:
- Sid data;
-};
-
-RequestTokenTo3PIDEmailJob::RequestTokenTo3PIDEmailJob(
- const QString& clientSecret, const QString& email, int sendAttempt,
- const QString& idServer, const QString& nextLink)
- : BaseJob(HttpVerb::Post, QStringLiteral("RequestTokenTo3PIDEmailJob"),
- basePath % "/account/3pid/email/requestToken", false)
- , d(new Private)
+Unbind3pidFromAccountJob::Unbind3pidFromAccountJob(const QString& medium,
+ const QString& address,
+ const QString& idServer)
+ : BaseJob(HttpVerb::Post, QStringLiteral("Unbind3pidFromAccountJob"),
+ QStringLiteral("/_matrix/client/r0") % "/account/3pid/unbind")
{
QJsonObject _data;
- addParam<>(_data, QStringLiteral("client_secret"), clientSecret);
- addParam<>(_data, QStringLiteral("email"), email);
- addParam<>(_data, QStringLiteral("send_attempt"), sendAttempt);
- addParam<IfNotEmpty>(_data, QStringLiteral("next_link"), nextLink);
- addParam<>(_data, QStringLiteral("id_server"), idServer);
- setRequestData(_data);
+ addParam<IfNotEmpty>(_data, QStringLiteral("id_server"), idServer);
+ addParam<>(_data, QStringLiteral("medium"), medium);
+ addParam<>(_data, QStringLiteral("address"), address);
+ setRequestData(std::move(_data));
+ addExpectedKey("id_server_unbind_result");
}
-RequestTokenTo3PIDEmailJob::~RequestTokenTo3PIDEmailJob() = default;
-
-const Sid& RequestTokenTo3PIDEmailJob::data() const { return d->data; }
-
-BaseJob::Status RequestTokenTo3PIDEmailJob::parseJson(const QJsonDocument& data)
+RequestTokenTo3PIDEmailJob::RequestTokenTo3PIDEmailJob(
+ const EmailValidationData& body)
+ : BaseJob(HttpVerb::Post, QStringLiteral("RequestTokenTo3PIDEmailJob"),
+ QStringLiteral("/_matrix/client/r0")
+ % "/account/3pid/email/requestToken",
+ false)
{
- fromJson(data, d->data);
-
- return Success;
+ setRequestData(Data(toJson(body)));
}
-class RequestTokenTo3PIDMSISDNJob::Private {
-public:
- Sid data;
-};
-
RequestTokenTo3PIDMSISDNJob::RequestTokenTo3PIDMSISDNJob(
- const QString& clientSecret, const QString& country,
- const QString& phoneNumber, int sendAttempt, const QString& idServer,
- const QString& nextLink)
+ const MsisdnValidationData& body)
: BaseJob(HttpVerb::Post, QStringLiteral("RequestTokenTo3PIDMSISDNJob"),
- basePath % "/account/3pid/msisdn/requestToken", false)
- , d(new Private)
-{
- QJsonObject _data;
- addParam<>(_data, QStringLiteral("client_secret"), clientSecret);
- addParam<>(_data, QStringLiteral("country"), country);
- addParam<>(_data, QStringLiteral("phone_number"), phoneNumber);
- addParam<>(_data, QStringLiteral("send_attempt"), sendAttempt);
- addParam<IfNotEmpty>(_data, QStringLiteral("next_link"), nextLink);
- addParam<>(_data, QStringLiteral("id_server"), idServer);
- setRequestData(_data);
-}
-
-RequestTokenTo3PIDMSISDNJob::~RequestTokenTo3PIDMSISDNJob() = default;
-
-const Sid& RequestTokenTo3PIDMSISDNJob::data() const { return d->data; }
-
-BaseJob::Status RequestTokenTo3PIDMSISDNJob::parseJson(const QJsonDocument& data)
+ QStringLiteral("/_matrix/client/r0")
+ % "/account/3pid/msisdn/requestToken",
+ false)
{
- fromJson(data, d->data);
-
- return Success;
+ setRequestData(Data(toJson(body)));
}
diff --git a/lib/csapi/administrative_contact.h b/lib/csapi/administrative_contact.h
index af98fe9c..53c89272 100644
--- a/lib/csapi/administrative_contact.h
+++ b/lib/csapi/administrative_contact.h
@@ -4,18 +4,15 @@
#pragma once
-#include "converters.h"
-
-#include "csapi/../identity/definitions/sid.h"
+#include "csapi/./definitions/request_email_validation.h"
+#include "csapi/./definitions/request_msisdn_validation.h"
+#include "csapi/definitions/auth_data.h"
+#include "csapi/definitions/request_token_response.h"
#include "jobs/basejob.h"
-#include <QtCore/QVector>
-
namespace Quotient {
-// Operations
-
/*! \brief Gets a list of a user's third party identifiers.
*
* Gets a list of the third party identifiers that the homeserver has
@@ -63,7 +60,6 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl);
- ~GetAccount3PIDsJob() override;
// Result properties
@@ -75,19 +71,36 @@ public:
///
/// Identifiers in this list may be used by the homeserver as, for example,
/// identifiers that it will accept to reset the user's account password.
- const QVector<ThirdPartyIdentifier>& threepids() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
+ QVector<ThirdPartyIdentifier> threepids() const
+ {
+ return loadFromJson<QVector<ThirdPartyIdentifier>>("threepids"_ls);
+ }
+};
-private:
- class Private;
- QScopedPointer<Private> d;
+template <>
+struct JsonObjectConverter<GetAccount3PIDsJob::ThirdPartyIdentifier> {
+ static void fillFrom(const QJsonObject& jo,
+ GetAccount3PIDsJob::ThirdPartyIdentifier& 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);
+ }
};
/*! \brief Adds contact information to the user's account.
*
* Adds contact information to the user's account.
+ *
+ * This endpoint is deprecated in favour of the more specific ``/3pid/add``
+ * and ``/3pid/bind`` endpoints.
+ *
+ * .. Note::
+ * Previously this endpoint supported a ``bind`` parameter. This parameter
+ * has been removed, making this endpoint behave as though it was ``false``.
+ * This results in this endpoint being an equivalent to ``/3pid/bind`` rather
+ * than dual-purpose.
*/
class Post3PIDsJob : public BaseJob {
public:
@@ -99,6 +112,10 @@ public:
QString clientSecret;
/// The identity server to use.
QString idServer;
+ /// An access token previously registered with the identity server.
+ /// Servers can treat this as optional to distinguish between
+ /// r0.5-compatible clients and this specification version.
+ QString idAccessToken;
/// The session identifier given by the identity server.
QString sid;
};
@@ -107,152 +124,247 @@ public:
/*! \brief Adds contact information to the user's account.
*
+ *
* \param threePidCreds
* The third party credentials to associate with the account.
- * \param bind
- * Whether the homeserver should also bind this third party
- * identifier to the account's Matrix ID with the passed identity
- * server. Default: ``false``.
*/
- explicit Post3PIDsJob(const ThreePidCredentials& threePidCreds,
- Omittable<bool> bind = none);
+ explicit Post3PIDsJob(const ThreePidCredentials& threePidCreds);
+};
+
+template <>
+struct JsonObjectConverter<Post3PIDsJob::ThreePidCredentials> {
+ 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("id_access_token"), pod.idAccessToken);
+ addParam<>(jo, QStringLiteral("sid"), pod.sid);
+ }
+};
+
+/*! \brief Adds contact information to the user's account.
+ *
+ * This API endpoint uses the `User-Interactive Authentication API`_.
+ *
+ * Adds contact information to the user's account. Homeservers should use 3PIDs
+ * added through this endpoint for password resets instead of relying on the
+ * identity server.
+ *
+ * Homeservers should prevent the caller from adding a 3PID to their account if
+ * it has already been added to another user's account on the homeserver.
+ */
+class Add3PIDJob : public BaseJob {
+public:
+ /*! \brief Adds contact information to the user's account.
+ *
+ *
+ * \param clientSecret
+ * The client secret used in the session with the homeserver.
+ *
+ * \param sid
+ * The session identifier given by the homeserver.
+ *
+ * \param auth
+ * Additional authentication information for the
+ * user-interactive authentication API.
+ */
+ explicit Add3PIDJob(const QString& clientSecret, const QString& sid,
+ const Omittable<AuthenticationData>& auth = none);
+};
+
+/*! \brief Binds a 3PID to the user's account through an Identity Service.
+ *
+ * Binds a 3PID to the user's account through the specified identity server.
+ *
+ * Homeservers should not prevent this request from succeeding if another user
+ * has bound the 3PID. Homeservers should simply proxy any errors received by
+ * the identity server to the caller.
+ *
+ * Homeservers should track successful binds so they can be unbound later.
+ */
+class Bind3PIDJob : public BaseJob {
+public:
+ /*! \brief Binds a 3PID to the user's account through an Identity Service.
+ *
+ *
+ * \param clientSecret
+ * The client secret used in the session with the identity server.
+ *
+ * \param idServer
+ * The identity server to use.
+ *
+ * \param idAccessToken
+ * An access token previously registered with the identity server.
+ *
+ * \param sid
+ * The session identifier given by the identity server.
+ */
+ explicit Bind3PIDJob(const QString& clientSecret, const QString& idServer,
+ const QString& idAccessToken, const QString& sid);
};
/*! \brief Deletes a third party identifier from the user's account
*
* Removes a third party identifier from the user's account. This might not
* cause an unbind of the identifier from the identity server.
+ *
+ * Unlike other endpoints, this endpoint does not take an ``id_access_token``
+ * parameter because the homeserver is expected to sign the request to the
+ * identity server instead.
*/
class Delete3pidFromAccountJob : public BaseJob {
public:
/*! \brief Deletes a third party identifier from the user's account
*
+ *
* \param medium
* The medium of the third party identifier being removed.
+ *
* \param address
* The third party address being removed.
+ *
+ * \param idServer
+ * The identity server to unbind from. If not provided, the homeserver
+ * MUST use the ``id_server`` the identifier was added through. If the
+ * homeserver does not know the original ``id_server``, it MUST return
+ * a ``id_server_unbind_result`` of ``no-support``.
*/
explicit Delete3pidFromAccountJob(const QString& medium,
- const QString& address);
+ const QString& address,
+ const QString& idServer = {});
+
+ // Result properties
+
+ /// An indicator as to whether or not the homeserver was able to unbind
+ /// the 3PID from the identity server. ``success`` indicates that the
+ /// indentity server has unbound the identifier whereas ``no-support``
+ /// indicates that the identity server refuses to support the request
+ /// or the homeserver was not able to determine an identity server to
+ /// unbind from.
+ QString idServerUnbindResult() const
+ {
+ return loadFromJson<QString>("id_server_unbind_result"_ls);
+ }
+};
+
+/*! \brief Removes a user's third party identifier from an identity server.
+ *
+ * Removes a user's third party identifier from the provided identity server
+ * without removing it from the homeserver.
+ *
+ * Unlike other endpoints, this endpoint does not take an ``id_access_token``
+ * parameter because the homeserver is expected to sign the request to the
+ * identity server instead.
+ */
+class Unbind3pidFromAccountJob : public BaseJob {
+public:
+ /*! \brief Removes a user's third party identifier from an identity server.
+ *
+ *
+ * \param medium
+ * The medium of the third party identifier being removed.
+ *
+ * \param address
+ * The third party address being removed.
+ *
+ * \param idServer
+ * The identity server to unbind from. If not provided, the homeserver
+ * MUST use the ``id_server`` the identifier was added through. If the
+ * homeserver does not know the original ``id_server``, it MUST return
+ * a ``id_server_unbind_result`` of ``no-support``.
+ */
+ explicit Unbind3pidFromAccountJob(const QString& medium,
+ const QString& address,
+ const QString& idServer = {});
+
+ // Result properties
+
+ /// An indicator as to whether or not the identity server was able to unbind
+ /// the 3PID. ``success`` indicates that the identity server has unbound the
+ /// identifier whereas ``no-support`` indicates that the identity server
+ /// refuses to support the request or the homeserver was not able to
+ /// determine an identity server to unbind from.
+ QString idServerUnbindResult() const
+ {
+ return loadFromJson<QString>("id_server_unbind_result"_ls);
+ }
};
/*! \brief Begins the validation process for an email address for association
* with the user's account.
*
- * Proxies the Identity Service API ``validate/email/requestToken``, but
- * first checks that the given email address is **not** already associated
- * with an account on this homeserver. This API should be used to request
- * validation tokens when adding an email address to an account. This API's
- * parameters and response are identical to that of the
- * |/register/email/requestToken|_ endpoint.
+ * The homeserver must check that the given email address is **not**
+ * already associated with an account on this homeserver. This API should
+ * be used to request validation tokens when adding an email address to an
+ * account. This API's parameters and response are identical to that of
+ * the |/register/email/requestToken|_ endpoint. The homeserver should validate
+ * the email itself, either by sending a validation email itself or by using
+ * a service it has control over.
*/
class RequestTokenTo3PIDEmailJob : public BaseJob {
public:
/*! \brief Begins the validation process for an email address for
* association with the user's account.
*
- * \param clientSecret
- * A unique string generated by the client, and used to identify the
- * validation attempt. It must be a string consisting of the characters
- * ``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters and it
- * must not be empty.
- * \param email
- * The email address to validate.
- * \param sendAttempt
- * The server will only send an email if the ``send_attempt``
- * is a number greater than the most recent one which it has seen,
- * scoped to that ``email`` + ``client_secret`` pair. This is to
- * avoid repeatedly sending the same email in the case of request
- * retries between the POSTing user and the identity server.
- * The client should increment this value if they desire a new
- * email (e.g. a reminder) to be sent.
- * \param idServer
- * The hostname of the identity server to communicate with. May
- * optionally include a port.
- * \param nextLink
- * Optional. When the validation is completed, the identity
- * server will redirect the user to this URL.
+ *
+ * \param body
+ * The homeserver must check that the given email address is **not**
+ * already associated with an account on this homeserver. This API should
+ * be used to request validation tokens when adding an email address to an
+ * account. This API's parameters and response are identical to that of
+ * the |/register/email/requestToken|_ endpoint. The homeserver should
+ * validate the email itself, either by sending a validation email itself or
+ * by using a service it has control over.
*/
- explicit RequestTokenTo3PIDEmailJob(const QString& clientSecret,
- const QString& email, int sendAttempt,
- const QString& idServer,
- const QString& nextLink = {});
-
- ~RequestTokenTo3PIDEmailJob() override;
+ explicit RequestTokenTo3PIDEmailJob(const EmailValidationData& body);
// Result properties
- /// An email was sent to the given address.
- const Sid& data() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ /// An email was sent to the given address. Note that this may be an
+ /// email containing the validation token or it may be informing the
+ /// user of an error.
+ RequestTokenResponse data() const
+ {
+ return fromJson<RequestTokenResponse>(jsonData());
+ }
};
/*! \brief Begins the validation process for a phone number for association with
* the user's account.
*
- * Proxies the Identity Service API ``validate/msisdn/requestToken``, but
- * first checks that the given phone number is **not** already associated
- * with an account on this homeserver. This API should be used to request
- * validation tokens when adding a phone number to an account. This API's
- * parameters and response are identical to that of the
- * |/register/msisdn/requestToken|_ endpoint.
+ * The homeserver must check that the given phone number is **not**
+ * already associated with an account on this homeserver. This API should
+ * be used to request validation tokens when adding a phone number to an
+ * account. This API's parameters and response are identical to that of
+ * the |/register/msisdn/requestToken|_ endpoint. The homeserver should validate
+ * the phone number itself, either by sending a validation message itself or by
+ * using a service it has control over.
*/
class RequestTokenTo3PIDMSISDNJob : public BaseJob {
public:
/*! \brief Begins the validation process for a phone number for association
* with the user's account.
*
- * \param clientSecret
- * A unique string generated by the client, and used to identify the
- * validation attempt. It must be a string consisting of the characters
- * ``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters and it
- * must not be empty.
- * \param country
- * The two-letter uppercase ISO country code that the number in
- * ``phone_number`` should be parsed as if it were dialled from.
- * \param phoneNumber
- * The phone number to validate.
- * \param sendAttempt
- * The server will only send an SMS if the ``send_attempt`` is a
- * number greater than the most recent one which it has seen,
- * scoped to that ``country`` + ``phone_number`` + ``client_secret``
- * triple. This is to avoid repeatedly sending the same SMS in
- * the case of request retries between the POSTing user and the
- * identity server. The client should increment this value if
- * they desire a new SMS (e.g. a reminder) to be sent.
- * \param idServer
- * The hostname of the identity server to communicate with. May
- * optionally include a port.
- * \param nextLink
- * Optional. When the validation is completed, the identity
- * server will redirect the user to this URL.
+ *
+ * \param body
+ * The homeserver must check that the given phone number is **not**
+ * already associated with an account on this homeserver. This API should
+ * be used to request validation tokens when adding a phone number to an
+ * account. This API's parameters and response are identical to that of
+ * the |/register/msisdn/requestToken|_ endpoint. The homeserver should
+ * validate the phone number itself, either by sending a validation message
+ * itself or by using a service it has control over.
*/
- explicit RequestTokenTo3PIDMSISDNJob(const QString& clientSecret,
- const QString& country,
- const QString& phoneNumber,
- int sendAttempt,
- const QString& idServer,
- const QString& nextLink = {});
-
- ~RequestTokenTo3PIDMSISDNJob() override;
+ explicit RequestTokenTo3PIDMSISDNJob(const MsisdnValidationData& body);
// Result properties
/// An SMS message was sent to the given phone number.
- const Sid& data() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ RequestTokenResponse data() const
+ {
+ return fromJson<RequestTokenResponse>(jsonData());
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/appservice_room_directory.cpp b/lib/csapi/appservice_room_directory.cpp
index bfcab2a7..e8ec55bf 100644
--- a/lib/csapi/appservice_room_directory.cpp
+++ b/lib/csapi/appservice_room_directory.cpp
@@ -4,21 +4,18 @@
#include "appservice_room_directory.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
UpdateAppserviceRoomDirectoryVsibilityJob::UpdateAppserviceRoomDirectoryVsibilityJob(
const QString& networkId, const QString& roomId, const QString& visibility)
: BaseJob(HttpVerb::Put,
QStringLiteral("UpdateAppserviceRoomDirectoryVsibilityJob"),
- basePath % "/directory/list/appservice/" % networkId % "/" % roomId)
+ QStringLiteral("/_matrix/client/r0")
+ % "/directory/list/appservice/" % networkId % "/" % roomId)
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("visibility"), visibility);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
diff --git a/lib/csapi/appservice_room_directory.h b/lib/csapi/appservice_room_directory.h
index f0ad78b0..d103177c 100644
--- a/lib/csapi/appservice_room_directory.h
+++ b/lib/csapi/appservice_room_directory.h
@@ -8,8 +8,6 @@
namespace Quotient {
-// Operations
-
/*! \brief Updates a room's visibility in the application service's room
* directory.
*
@@ -28,12 +26,15 @@ public:
/*! \brief Updates a room's visibility in the application service's room
* directory.
*
+ *
* \param networkId
* The protocol (network) ID to update the room list for. This would
* have been provided by the application service as being listed as
* a supported protocol.
+ *
* \param roomId
* The room ID to add to the directory.
+ *
* \param visibility
* Whether the room should be visible (public) in the directory
* or not (private).
diff --git a/lib/csapi/banning.cpp b/lib/csapi/banning.cpp
index 6ac9b3ba..8a8ec664 100644
--- a/lib/csapi/banning.cpp
+++ b/lib/csapi/banning.cpp
@@ -4,30 +4,27 @@
#include "banning.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
BanJob::BanJob(const QString& roomId, const QString& userId,
const QString& reason)
: BaseJob(HttpVerb::Post, QStringLiteral("BanJob"),
- basePath % "/rooms/" % roomId % "/ban")
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId % "/ban")
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("user_id"), userId);
addParam<IfNotEmpty>(_data, QStringLiteral("reason"), reason);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
UnbanJob::UnbanJob(const QString& roomId, const QString& userId)
: BaseJob(HttpVerb::Post, QStringLiteral("UnbanJob"),
- basePath % "/rooms/" % roomId % "/unban")
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/unban")
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("user_id"), userId);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
diff --git a/lib/csapi/banning.h b/lib/csapi/banning.h
index 6bf782e7..4faaaa81 100644
--- a/lib/csapi/banning.h
+++ b/lib/csapi/banning.h
@@ -8,8 +8,6 @@
namespace Quotient {
-// Operations
-
/*! \brief Ban a user in the room.
*
* Ban a user in the room. If the user is currently in the room, also kick them.
@@ -24,10 +22,13 @@ class BanJob : public BaseJob {
public:
/*! \brief Ban a user in the room.
*
+ *
* \param roomId
* The room identifier (not alias) from which the user should be banned.
+ *
* \param userId
* The fully qualified user ID of the user being banned.
+ *
* \param reason
* The reason the user has been banned. This will be supplied as the
* ``reason`` on the target's updated `m.room.member`_ event.
@@ -49,8 +50,10 @@ class UnbanJob : public BaseJob {
public:
/*! \brief Unban a user from the room.
*
+ *
* \param roomId
* The room identifier (not alias) from which the user should be unbanned.
+ *
* \param userId
* The fully qualified user ID of the user being unbanned.
*/
diff --git a/lib/csapi/capabilities.cpp b/lib/csapi/capabilities.cpp
index 8c7ed141..33a53cad 100644
--- a/lib/csapi/capabilities.cpp
+++ b/lib/csapi/capabilities.cpp
@@ -4,80 +4,20 @@
#include "capabilities.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-// Converters
-namespace Quotient {
-
-template <>
-struct JsonObjectConverter<GetCapabilitiesJob::ChangePasswordCapability> {
- static void fillFrom(const QJsonObject& jo,
- GetCapabilitiesJob::ChangePasswordCapability& result)
- {
- fromJson(jo.value("enabled"_ls), result.enabled);
- }
-};
-
-template <>
-struct JsonObjectConverter<GetCapabilitiesJob::RoomVersionsCapability> {
- static void fillFrom(const QJsonObject& jo,
- GetCapabilitiesJob::RoomVersionsCapability& result)
- {
- fromJson(jo.value("default"_ls), result.defaultVersion);
- fromJson(jo.value("available"_ls), result.available);
- }
-};
-
-template <>
-struct JsonObjectConverter<GetCapabilitiesJob::Capabilities> {
- static void fillFrom(QJsonObject jo,
- GetCapabilitiesJob::Capabilities& result)
- {
- fromJson(jo.take("m.change_password"_ls), result.changePassword);
- fromJson(jo.take("m.room_versions"_ls), result.roomVersions);
- fromJson(jo, result.additionalProperties);
- }
-};
-
-} // namespace Quotient
-
-class GetCapabilitiesJob::Private {
-public:
- Capabilities capabilities;
-};
-
QUrl GetCapabilitiesJob::makeRequestUrl(QUrl baseUrl)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/capabilities");
+ QStringLiteral("/_matrix/client/r0")
+ % "/capabilities");
}
GetCapabilitiesJob::GetCapabilitiesJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetCapabilitiesJob"),
- basePath % "/capabilities")
- , d(new Private)
-{}
-
-GetCapabilitiesJob::~GetCapabilitiesJob() = default;
-
-const GetCapabilitiesJob::Capabilities& GetCapabilitiesJob::capabilities() const
+ QStringLiteral("/_matrix/client/r0") % "/capabilities")
{
- return d->capabilities;
-}
-
-BaseJob::Status GetCapabilitiesJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- if (!json.contains("capabilities"_ls))
- return { IncorrectResponse,
- "The key 'capabilities' not found in the response" };
- fromJson(json.value("capabilities"_ls), d->capabilities);
-
- return Success;
+ addExpectedKey("capabilities");
}
diff --git a/lib/csapi/capabilities.h b/lib/csapi/capabilities.h
index 9f46ab2e..da50c8c1 100644
--- a/lib/csapi/capabilities.h
+++ b/lib/csapi/capabilities.h
@@ -4,17 +4,10 @@
#pragma once
-#include "converters.h"
-
#include "jobs/basejob.h"
-#include <QtCore/QHash>
-#include <QtCore/QJsonObject>
-
namespace Quotient {
-// Operations
-
/*! \brief Gets information about the server's capabilities.
*
* Gets information about the server's supported feature set
@@ -61,20 +54,45 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl);
- ~GetCapabilitiesJob() override;
// Result properties
/// The custom capabilities the server supports, using the
/// Java package naming convention.
- const Capabilities& capabilities() const;
+ Capabilities capabilities() const
+ {
+ return loadFromJson<Capabilities>("capabilities"_ls);
+ }
+};
-protected:
- Status parseJson(const QJsonDocument& data) override;
+template <>
+struct JsonObjectConverter<GetCapabilitiesJob::ChangePasswordCapability> {
+ static void fillFrom(const QJsonObject& jo,
+ GetCapabilitiesJob::ChangePasswordCapability& result)
+ {
+ fromJson(jo.value("enabled"_ls), result.enabled);
+ }
+};
+
+template <>
+struct JsonObjectConverter<GetCapabilitiesJob::RoomVersionsCapability> {
+ static void fillFrom(const QJsonObject& jo,
+ GetCapabilitiesJob::RoomVersionsCapability& result)
+ {
+ fromJson(jo.value("default"_ls), result.defaultVersion);
+ fromJson(jo.value("available"_ls), result.available);
+ }
+};
-private:
- class Private;
- QScopedPointer<Private> d;
+template <>
+struct JsonObjectConverter<GetCapabilitiesJob::Capabilities> {
+ static void fillFrom(QJsonObject jo,
+ GetCapabilitiesJob::Capabilities& result)
+ {
+ fromJson(jo.take("m.change_password"_ls), result.changePassword);
+ fromJson(jo.take("m.room_versions"_ls), result.roomVersions);
+ fromJson(jo, result.additionalProperties);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/content-repo.cpp b/lib/csapi/content-repo.cpp
index d811426d..7ae89739 100644
--- a/lib/csapi/content-repo.cpp
+++ b/lib/csapi/content-repo.cpp
@@ -4,21 +4,11 @@
#include "content-repo.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
-#include <QtNetwork/QNetworkReply>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/media/r0");
-
-class UploadContentJob::Private {
-public:
- QString contentUri;
-};
-
-BaseJob::Query queryToUploadContent(const QString& filename)
+auto queryToUploadContent(const QString& filename)
{
BaseJob::Query _q;
addParam<IfNotEmpty>(_q, QStringLiteral("filename"), filename);
@@ -28,36 +18,15 @@ BaseJob::Query queryToUploadContent(const QString& filename)
UploadContentJob::UploadContentJob(QIODevice* content, const QString& filename,
const QString& contentType)
: BaseJob(HttpVerb::Post, QStringLiteral("UploadContentJob"),
- basePath % "/upload", queryToUploadContent(filename))
- , d(new Private)
+ QStringLiteral("/_matrix/media/r0") % "/upload",
+ queryToUploadContent(filename))
{
setRequestHeader("Content-Type", contentType.toLatin1());
setRequestData(Data(content));
+ addExpectedKey("content_uri");
}
-UploadContentJob::~UploadContentJob() = default;
-
-const QString& UploadContentJob::contentUri() const { return d->contentUri; }
-
-BaseJob::Status UploadContentJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- if (!json.contains("content_uri"_ls))
- return { IncorrectResponse,
- "The key 'content_uri' not found in the response" };
- fromJson(json.value("content_uri"_ls), d->contentUri);
-
- return Success;
-}
-
-class GetContentJob::Private {
-public:
- QString contentType;
- QString contentDisposition;
- QIODevice* data;
-};
-
-BaseJob::Query queryToGetContent(bool allowRemote)
+auto queryToGetContent(bool allowRemote)
{
BaseJob::Query _q;
addParam<IfNotEmpty>(_q, QStringLiteral("allow_remote"), allowRemote);
@@ -68,7 +37,8 @@ QUrl GetContentJob::makeRequestUrl(QUrl baseUrl, const QString& serverName,
const QString& mediaId, bool allowRemote)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/download/" % serverName % "/"
+ QStringLiteral("/_matrix/media/r0")
+ % "/download/" % serverName % "/"
% mediaId,
queryToGetContent(allowRemote));
}
@@ -76,40 +46,14 @@ QUrl GetContentJob::makeRequestUrl(QUrl baseUrl, const QString& serverName,
GetContentJob::GetContentJob(const QString& serverName, const QString& mediaId,
bool allowRemote)
: BaseJob(HttpVerb::Get, QStringLiteral("GetContentJob"),
- basePath % "/download/" % serverName % "/" % mediaId,
+ QStringLiteral("/_matrix/media/r0") % "/download/" % serverName
+ % "/" % mediaId,
queryToGetContent(allowRemote), {}, false)
- , d(new Private)
{
setExpectedContentTypes({ "*/*" });
}
-GetContentJob::~GetContentJob() = default;
-
-const QString& GetContentJob::contentType() const { return d->contentType; }
-
-const QString& GetContentJob::contentDisposition() const
-{
- return d->contentDisposition;
-}
-
-QIODevice* GetContentJob::data() const { return d->data; }
-
-BaseJob::Status GetContentJob::parseReply(QNetworkReply* reply)
-{
- d->contentType = reply->rawHeader("Content-Type");
- d->contentDisposition = reply->rawHeader("Content-Disposition");
- d->data = reply;
- return Success;
-}
-
-class GetContentOverrideNameJob::Private {
-public:
- QString contentType;
- QString contentDisposition;
- QIODevice* data;
-};
-
-BaseJob::Query queryToGetContentOverrideName(bool allowRemote)
+auto queryToGetContentOverrideName(bool allowRemote)
{
BaseJob::Query _q;
addParam<IfNotEmpty>(_q, QStringLiteral("allow_remote"), allowRemote);
@@ -123,7 +67,8 @@ QUrl GetContentOverrideNameJob::makeRequestUrl(QUrl baseUrl,
bool allowRemote)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/download/" % serverName % "/"
+ QStringLiteral("/_matrix/media/r0")
+ % "/download/" % serverName % "/"
% mediaId % "/" % fileName,
queryToGetContentOverrideName(allowRemote));
}
@@ -133,45 +78,15 @@ GetContentOverrideNameJob::GetContentOverrideNameJob(const QString& serverName,
const QString& fileName,
bool allowRemote)
: BaseJob(HttpVerb::Get, QStringLiteral("GetContentOverrideNameJob"),
- basePath % "/download/" % serverName % "/" % mediaId % "/"
- % fileName,
+ QStringLiteral("/_matrix/media/r0") % "/download/" % serverName
+ % "/" % mediaId % "/" % fileName,
queryToGetContentOverrideName(allowRemote), {}, false)
- , d(new Private)
{
setExpectedContentTypes({ "*/*" });
}
-GetContentOverrideNameJob::~GetContentOverrideNameJob() = default;
-
-const QString& GetContentOverrideNameJob::contentType() const
-{
- return d->contentType;
-}
-
-const QString& GetContentOverrideNameJob::contentDisposition() const
-{
- return d->contentDisposition;
-}
-
-QIODevice* GetContentOverrideNameJob::data() const { return d->data; }
-
-BaseJob::Status GetContentOverrideNameJob::parseReply(QNetworkReply* reply)
-{
- d->contentType = reply->rawHeader("Content-Type");
- d->contentDisposition = reply->rawHeader("Content-Disposition");
- d->data = reply;
- return Success;
-}
-
-class GetContentThumbnailJob::Private {
-public:
- QString contentType;
- QIODevice* data;
-};
-
-BaseJob::Query queryToGetContentThumbnail(int width, int height,
- const QString& method,
- bool allowRemote)
+auto queryToGetContentThumbnail(int width, int height, const QString& method,
+ bool allowRemote)
{
BaseJob::Query _q;
addParam<>(_q, QStringLiteral("width"), width);
@@ -189,7 +104,8 @@ QUrl GetContentThumbnailJob::makeRequestUrl(QUrl baseUrl,
{
return BaseJob::makeRequestUrl(
std::move(baseUrl),
- basePath % "/thumbnail/" % serverName % "/" % mediaId,
+ QStringLiteral("/_matrix/media/r0") % "/thumbnail/" % serverName % "/"
+ % mediaId,
queryToGetContentThumbnail(width, height, method, allowRemote));
}
@@ -198,37 +114,15 @@ GetContentThumbnailJob::GetContentThumbnailJob(const QString& serverName,
int height, const QString& method,
bool allowRemote)
: BaseJob(HttpVerb::Get, QStringLiteral("GetContentThumbnailJob"),
- basePath % "/thumbnail/" % serverName % "/" % mediaId,
+ QStringLiteral("/_matrix/media/r0") % "/thumbnail/" % serverName
+ % "/" % mediaId,
queryToGetContentThumbnail(width, height, method, allowRemote),
{}, false)
- , d(new Private)
{
setExpectedContentTypes({ "image/jpeg", "image/png" });
}
-GetContentThumbnailJob::~GetContentThumbnailJob() = default;
-
-const QString& GetContentThumbnailJob::contentType() const
-{
- return d->contentType;
-}
-
-QIODevice* GetContentThumbnailJob::data() const { return d->data; }
-
-BaseJob::Status GetContentThumbnailJob::parseReply(QNetworkReply* reply)
-{
- d->contentType = reply->rawHeader("Content-Type");
- d->data = reply;
- return Success;
-}
-
-class GetUrlPreviewJob::Private {
-public:
- Omittable<qint64> matrixImageSize;
- QString ogImage;
-};
-
-BaseJob::Query queryToGetUrlPreview(const QString& url, Omittable<qint64> ts)
+auto queryToGetUrlPreview(const QString& url, Omittable<qint64> ts)
{
BaseJob::Query _q;
addParam<>(_q, QStringLiteral("url"), url);
@@ -239,58 +133,26 @@ BaseJob::Query queryToGetUrlPreview(const QString& url, Omittable<qint64> ts)
QUrl GetUrlPreviewJob::makeRequestUrl(QUrl baseUrl, const QString& url,
Omittable<qint64> ts)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/preview_url",
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ QStringLiteral("/_matrix/media/r0")
+ % "/preview_url",
queryToGetUrlPreview(url, ts));
}
GetUrlPreviewJob::GetUrlPreviewJob(const QString& url, Omittable<qint64> ts)
: BaseJob(HttpVerb::Get, QStringLiteral("GetUrlPreviewJob"),
- basePath % "/preview_url", queryToGetUrlPreview(url, ts))
- , d(new Private)
+ QStringLiteral("/_matrix/media/r0") % "/preview_url",
+ queryToGetUrlPreview(url, ts))
{}
-GetUrlPreviewJob::~GetUrlPreviewJob() = default;
-
-Omittable<qint64> GetUrlPreviewJob::matrixImageSize() const
-{
- return d->matrixImageSize;
-}
-
-const QString& GetUrlPreviewJob::ogImage() const { return d->ogImage; }
-
-BaseJob::Status GetUrlPreviewJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("matrix:image:size"_ls), d->matrixImageSize);
- fromJson(json.value("og:image"_ls), d->ogImage);
-
- return Success;
-}
-
-class GetConfigJob::Private {
-public:
- Omittable<qint64> uploadSize;
-};
-
QUrl GetConfigJob::makeRequestUrl(QUrl baseUrl)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/config");
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ QStringLiteral("/_matrix/media/r0")
+ % "/config");
}
GetConfigJob::GetConfigJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetConfigJob"),
- basePath % "/config")
- , d(new Private)
+ QStringLiteral("/_matrix/media/r0") % "/config")
{}
-
-GetConfigJob::~GetConfigJob() = default;
-
-Omittable<qint64> GetConfigJob::uploadSize() const { return d->uploadSize; }
-
-BaseJob::Status GetConfigJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("m.upload.size"_ls), d->uploadSize);
-
- return Success;
-}
diff --git a/lib/csapi/content-repo.h b/lib/csapi/content-repo.h
index 6263ef0b..0eb273bc 100644
--- a/lib/csapi/content-repo.h
+++ b/lib/csapi/content-repo.h
@@ -4,16 +4,13 @@
#pragma once
-#include "converters.h"
-
#include "jobs/basejob.h"
#include <QtCore/QIODevice>
+#include <QtNetwork/QNetworkReply>
namespace Quotient {
-// Operations
-
/*! \brief Upload some content to the content repository.
*
*/
@@ -21,28 +18,26 @@ class UploadContentJob : public BaseJob {
public:
/*! \brief Upload some content to the content repository.
*
+ *
* \param content
+ * The content to be uploaded.
+ *
* \param filename
* The name of the file being uploaded
+ *
* \param contentType
* The content type of the file being uploaded
*/
explicit UploadContentJob(QIODevice* content, const QString& filename = {},
const QString& contentType = {});
- ~UploadContentJob() override;
-
// Result properties
- /// The MXC URI to the uploaded content.
- const QString& contentUri() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ /// The `MXC URI`_ to the uploaded content.
+ QString contentUri() const
+ {
+ return loadFromJson<QString>("content_uri"_ls);
+ }
};
/*! \brief Download content from the content repository.
@@ -52,10 +47,13 @@ class GetContentJob : public BaseJob {
public:
/*! \brief Download content from the content repository.
*
+ *
* \param serverName
* The server name from the ``mxc://`` URI (the authoritory component)
+ *
* \param mediaId
* The media ID from the ``mxc://`` URI (the path component)
+ *
* \param allowRemote
* Indicates to the server that it should not attempt to fetch the media
* if it is deemed remote. This is to prevent routing loops where the server
@@ -71,44 +69,47 @@ public:
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& serverName,
const QString& mediaId, bool allowRemote = true);
- ~GetContentJob() override;
// Result properties
/// The content type of the file that was previously uploaded.
- const QString& contentType() const;
+ QString contentType() const { return reply()->rawHeader("Content-Type"); }
/// The name of the file that was previously uploaded, if set.
- const QString& contentDisposition() const;
+ QString contentDisposition() const
+ {
+ return reply()->rawHeader("Content-Disposition");
+ }
/// The content that was previously uploaded.
- QIODevice* data() const;
-
-protected:
- Status parseReply(QNetworkReply* reply) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QIODevice* data() { return reply(); }
};
-/*! \brief Download content from the content repository as a given filename.
+/*! \brief Download content from the content repository. This is the same as
+the download endpoint above, except permitting a desired file name.
*
*/
class GetContentOverrideNameJob : public BaseJob {
public:
- /*! \brief Download content from the content repository as a given filename.
+ /*! \brief Download content from the content repository. This is the same as
+the download endpoint above, except permitting a desired file name.
+ *
*
* \param serverName
* The server name from the ``mxc://`` URI (the authoritory component)
+ *
* \param mediaId
* The media ID from the ``mxc://`` URI (the path component)
+ *
* \param fileName
- * The filename to give in the Content-Disposition
+ * A filename to give in the ``Content-Disposition`` header.
+ *
* \param allowRemote
* Indicates to the server that it should not attempt to fetch the media
- * if it is deemed remote. This is to prevent routing loops where the server
- * contacts itself. Defaults to true if not provided.
+if it is deemed
+ * remote. This is to prevent routing loops where the server contacts
+itself. Defaults to
+ * true if not provided.
*/
explicit GetContentOverrideNameJob(const QString& serverName,
const QString& mediaId,
@@ -123,50 +124,57 @@ public:
static QUrl makeRequestUrl(QUrl baseUrl, const QString& serverName,
const QString& mediaId, const QString& fileName,
bool allowRemote = true);
- ~GetContentOverrideNameJob() override;
// Result properties
/// The content type of the file that was previously uploaded.
- const QString& contentType() const;
+ QString contentType() const { return reply()->rawHeader("Content-Type"); }
- /// The name of file given in the request
- const QString& contentDisposition() const;
+ /// The ``fileName`` requested or the name of the file that was previously
+ /// uploaded, if set.
+ QString contentDisposition() const
+ {
+ return reply()->rawHeader("Content-Disposition");
+ }
/// The content that was previously uploaded.
- QIODevice* data() const;
-
-protected:
- Status parseReply(QNetworkReply* reply) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QIODevice* data() { return reply(); }
};
-/*! \brief Download a thumbnail of the content from the content repository.
+/*! \brief Download a thumbnail of content from the content repository. See the
+`thumbnailing <#thumbnails>`_ section for more information.
*
*/
class GetContentThumbnailJob : public BaseJob {
public:
- /*! \brief Download a thumbnail of the content from the content repository.
+ /*! \brief Download a thumbnail of content from the content repository. See
+the `thumbnailing <#thumbnails>`_ section for more information.
+ *
*
* \param serverName
* The server name from the ``mxc://`` URI (the authoritory component)
+ *
* \param mediaId
* The media ID from the ``mxc://`` URI (the path component)
+ *
* \param width
- * The *desired* width of the thumbnail. The actual thumbnail may not
- * match the size specified.
+ * The *desired* width of the thumbnail. The actual thumbnail may be
+ * larger than the size specified.
+ *
* \param height
- * The *desired* height of the thumbnail. The actual thumbnail may not
- * match the size specified.
+ * The *desired* height of the thumbnail. The actual thumbnail may be
+ * larger than the size specified.
+ *
* \param method
- * The desired resizing method.
+ * The desired resizing method. See the `thumbnailing <#thumbnails>`_
+ * section for more information.
+ *
* \param allowRemote
* Indicates to the server that it should not attempt to fetch the media
- * if it is deemed remote. This is to prevent routing loops where the server
- * contacts itself. Defaults to true if not provided.
+if it is deemed
+ * remote. This is to prevent routing loops where the server contacts
+itself. Defaults to
+ * true if not provided.
*/
explicit GetContentThumbnailJob(const QString& serverName,
const QString& mediaId, int width,
@@ -182,33 +190,35 @@ public:
const QString& mediaId, int width, int height,
const QString& method = {},
bool allowRemote = true);
- ~GetContentThumbnailJob() override;
// Result properties
/// The content type of the thumbnail.
- const QString& contentType() const;
+ QString contentType() const { return reply()->rawHeader("Content-Type"); }
/// A thumbnail of the requested content.
- QIODevice* data() const;
-
-protected:
- Status parseReply(QNetworkReply* reply) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QIODevice* data() { return reply(); }
};
/*! \brief Get information about a URL for a client
*
+ * Get information about a URL for the client. Typically this is called when a
+ * client sees a URL in a message and wants to render a preview for the user.
+ *
+ * .. Note::
+ * Clients should consider avoiding this endpoint for URLs posted in encrypted
+ * rooms. Encrypted rooms often contain more sensitive information the users
+ * do not want to share with the homeserver, and this can mean that the URLs
+ * being shared should also not be shared with the homeserver.
*/
class GetUrlPreviewJob : public BaseJob {
public:
/*! \brief Get information about a URL for a client
*
+ *
* \param url
- * The URL to get a preview of
+ * The URL to get a preview of.
+ *
* \param ts
* The preferred point in time to return a preview for. The server may
* return a newer version if it does not have the requested version
@@ -223,22 +233,17 @@ public:
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& url,
Omittable<qint64> ts = none);
- ~GetUrlPreviewJob() override;
// Result properties
/// The byte-size of the image. Omitted if there is no image attached.
- Omittable<qint64> matrixImageSize() const;
+ Omittable<qint64> matrixImageSize() const
+ {
+ return loadFromJson<Omittable<qint64>>("matrix:image:size"_ls);
+ }
- /// An MXC URI to the image. Omitted if there is no image.
- const QString& ogImage() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ /// An `MXC URI`_ to the image. Omitted if there is no image.
+ QString ogImage() const { return loadFromJson<QString>("og:image"_ls); }
};
/*! \brief Get the configuration for the content repository.
@@ -265,21 +270,16 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl);
- ~GetConfigJob() override;
// Result properties
/// The maximum size an upload can be in bytes.
/// Clients SHOULD use this as a guide when uploading content.
/// If not listed or null, the size limit should be treated as unknown.
- Omittable<qint64> uploadSize() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ Omittable<qint64> uploadSize() const
+ {
+ return loadFromJson<Omittable<qint64>>("m.upload.size"_ls);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/create_room.cpp b/lib/csapi/create_room.cpp
index ec2a1855..a94f9951 100644
--- a/lib/csapi/create_room.cpp
+++ b/lib/csapi/create_room.cpp
@@ -4,44 +4,10 @@
#include "create_room.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-// Converters
-namespace Quotient {
-
-template <>
-struct JsonObjectConverter<CreateRoomJob::Invite3pid> {
- 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);
- }
-};
-
-template <>
-struct JsonObjectConverter<CreateRoomJob::StateEvent> {
- 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 Quotient
-
-class CreateRoomJob::Private {
-public:
- QString roomId;
-};
-
CreateRoomJob::CreateRoomJob(const QString& visibility,
const QString& roomAliasName, const QString& name,
const QString& topic, const QStringList& invite,
@@ -52,8 +18,7 @@ CreateRoomJob::CreateRoomJob(const QString& visibility,
const QString& preset, Omittable<bool> isDirect,
const QJsonObject& powerLevelContentOverride)
: BaseJob(HttpVerb::Post, QStringLiteral("CreateRoomJob"),
- basePath % "/createRoom")
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/createRoom")
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("visibility"), visibility);
@@ -71,20 +36,6 @@ CreateRoomJob::CreateRoomJob(const QString& visibility,
addParam<IfNotEmpty>(_data, QStringLiteral("is_direct"), isDirect);
addParam<IfNotEmpty>(_data, QStringLiteral("power_level_content_override"),
powerLevelContentOverride);
- setRequestData(_data);
-}
-
-CreateRoomJob::~CreateRoomJob() = default;
-
-const QString& CreateRoomJob::roomId() const { return d->roomId; }
-
-BaseJob::Status CreateRoomJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- if (!json.contains("room_id"_ls))
- return { IncorrectResponse,
- "The key 'room_id' not found in the response" };
- fromJson(json.value("room_id"_ls), d->roomId);
-
- return Success;
+ setRequestData(std::move(_data));
+ addExpectedKey("room_id");
}
diff --git a/lib/csapi/create_room.h b/lib/csapi/create_room.h
index f2bd9333..82db9e59 100644
--- a/lib/csapi/create_room.h
+++ b/lib/csapi/create_room.h
@@ -4,17 +4,10 @@
#pragma once
-#include "converters.h"
-
#include "jobs/basejob.h"
-#include <QtCore/QJsonObject>
-#include <QtCore/QVector>
-
namespace Quotient {
-// Operations
-
/*! \brief Create a new room
*
* Create a new room with various configuration options.
@@ -23,21 +16,27 @@ namespace Quotient {
* the new room, including checking power levels for each event. It MUST
* apply the events implied by the request in the following order:
*
- * 0. A default ``m.room.power_levels`` event, giving the room creator
+ * 1. The ``m.room.create`` event itself. Must be the first event in the
+ * room.
+ *
+ * 2. An ``m.room.member`` event for the creator to join the room. This is
+ * needed so the remaining events can be sent.
+ *
+ * 3. A default ``m.room.power_levels`` event, giving the room creator
* (and not other members) permission to send state events. Overridden
* by the ``power_level_content_override`` parameter.
*
- * 1. Events set by the ``preset``. Currently these are the
+ * 4. Events set by the ``preset``. Currently these are the
* ``m.room.join_rules``,
* ``m.room.history_visibility``, and ``m.room.guest_access`` state events.
*
- * 2. Events listed in ``initial_state``, in the order that they are
+ * 5. Events listed in ``initial_state``, in the order that they are
* listed.
*
- * 3. Events implied by ``name`` and ``topic`` (``m.room.name`` and
+ * 6. Events implied by ``name`` and ``topic`` (``m.room.name`` and
* ``m.room.topic`` state events).
*
- * 4. Invite events implied by ``invite`` and ``invite_3pid`` (``m.room.member``
+ * 7. Invite events implied by ``invite`` and ``invite_3pid`` (``m.room.member``
* with
* ``membership: invite`` and ``m.room.third_party_invite``).
*
@@ -69,23 +68,29 @@ public:
/// the new room, including checking power levels for each event. It MUST
/// apply the events implied by the request in the following order:
///
- /// 0. A default ``m.room.power_levels`` event, giving the room creator
+ /// 1. The ``m.room.create`` event itself. Must be the first event in the
+ /// room.
+ ///
+ /// 2. An ``m.room.member`` event for the creator to join the room. This is
+ /// needed so the remaining events can be sent.
+ ///
+ /// 3. A default ``m.room.power_levels`` event, giving the room creator
/// (and not other members) permission to send state events. Overridden
/// by the ``power_level_content_override`` parameter.
///
- /// 1. Events set by the ``preset``. Currently these are the
+ /// 4. Events set by the ``preset``. Currently these are the
/// ``m.room.join_rules``,
/// ``m.room.history_visibility``, and ``m.room.guest_access`` state
/// events.
///
- /// 2. Events listed in ``initial_state``, in the order that they are
+ /// 5. Events listed in ``initial_state``, in the order that they are
/// listed.
///
- /// 3. Events implied by ``name`` and ``topic`` (``m.room.name`` and
+ /// 6. Events implied by ``name`` and ``topic`` (``m.room.name`` and
/// ``m.room.topic``
/// state events).
///
- /// 4. Invite events implied by ``invite`` and ``invite_3pid``
+ /// 7. Invite events implied by ``invite`` and ``invite_3pid``
/// (``m.room.member`` with
/// ``membership: invite`` and ``m.room.third_party_invite``).
///
@@ -111,6 +116,10 @@ public:
/// The hostname+port of the identity server which should be used for
/// third party identifier lookups.
QString idServer;
+ /// An access token previously registered with the identity server.
+ /// Servers can treat this as optional to distinguish between
+ /// r0.5-compatible clients and this specification version.
+ QString idAccessToken;
/// The kind of address being passed in the address field, for example
/// ``email``.
QString medium;
@@ -124,23 +133,29 @@ public:
/// the new room, including checking power levels for each event. It MUST
/// apply the events implied by the request in the following order:
///
- /// 0. A default ``m.room.power_levels`` event, giving the room creator
+ /// 1. The ``m.room.create`` event itself. Must be the first event in the
+ /// room.
+ ///
+ /// 2. An ``m.room.member`` event for the creator to join the room. This is
+ /// needed so the remaining events can be sent.
+ ///
+ /// 3. A default ``m.room.power_levels`` event, giving the room creator
/// (and not other members) permission to send state events. Overridden
/// by the ``power_level_content_override`` parameter.
///
- /// 1. Events set by the ``preset``. Currently these are the
+ /// 4. Events set by the ``preset``. Currently these are the
/// ``m.room.join_rules``,
/// ``m.room.history_visibility``, and ``m.room.guest_access`` state
/// events.
///
- /// 2. Events listed in ``initial_state``, in the order that they are
+ /// 5. Events listed in ``initial_state``, in the order that they are
/// listed.
///
- /// 3. Events implied by ``name`` and ``topic`` (``m.room.name`` and
+ /// 6. Events implied by ``name`` and ``topic`` (``m.room.name`` and
/// ``m.room.topic``
/// state events).
///
- /// 4. Invite events implied by ``invite`` and ``invite_3pid``
+ /// 7. Invite events implied by ``invite`` and ``invite_3pid``
/// (``m.room.member`` with
/// ``membership: invite`` and ``m.room.third_party_invite``).
///
@@ -175,6 +190,7 @@ public:
/*! \brief Create a new room
*
+ *
* \param visibility
* A ``public`` visibility indicates that the room will be shown
* in the published room list. A ``private`` visibility will hide
@@ -182,6 +198,7 @@ public:
* ``private`` visibility if this key is not included. NB: This
* should not be confused with ``join_rules`` which also uses the
* word ``public``.
+ *
* \param roomAliasName
* The desired room alias **local part**. If this is included, a
* room alias will be created and mapped to the newly created
@@ -192,35 +209,46 @@ public:
*
* The complete room alias will become the canonical alias for
* the room.
+ *
* \param name
* If this is included, an ``m.room.name`` event will be sent
* into the room to indicate the name of the room. See Room
* Events for more information on ``m.room.name``.
+ *
* \param topic
* If this is included, an ``m.room.topic`` event will be sent
* into the room to indicate the topic for the room. See Room
* Events for more information on ``m.room.topic``.
+ *
* \param invite
* A list of user IDs to invite to the room. This will tell the
* server to invite everyone in the list to the newly created room.
+ *
* \param invite3pid
* A list of objects representing third party IDs to invite into
* the room.
+ *
* \param roomVersion
* The room version to set for the room. If not provided, the homeserver
* is to use its configured default. If provided, the homeserver will return
* a 400 error with the errcode ``M_UNSUPPORTED_ROOM_VERSION`` if it does
- * not support the room version. \param creationContent Extra keys, such as
- * ``m.federate``, to be added to the content of the `m.room.create`_ event.
- * The server will clobber the following keys: ``creator``,
- * ``room_version``. Future versions of the specification may allow the
- * server to clobber other keys. \param initialState A list of state events
- * to set in the new room. This allows the user to override the default
- * state events set in the new room. The expected format of the state events
- * are an object with type, state_key and content keys set.
+ * not support the room version.
+ *
+ * \param creationContent
+ * Extra keys, such as ``m.federate``, to be added to the content
+ * of the `m.room.create`_ event. The server will clobber the following
+ * keys: ``creator``, ``room_version``. Future versions of the
+ * specification may allow the server to clobber other keys.
+ *
+ * \param initialState
+ * A list of state events to set in the new room. This allows
+ * the user to override the default state events set in the new
+ * room. The expected format of the state events are an object
+ * with type, state_key and content keys set.
*
* Takes precedence over events set by ``preset``, but gets
* overriden by ``name`` and ``topic`` keys.
+ *
* \param preset
* Convenience parameter for setting various default state events
* based on a preset.
@@ -229,10 +257,12 @@ public:
* which preset to use. A visbility of ``public`` equates to a preset of
* ``public_chat`` and ``private`` visibility equates to a preset of
* ``private_chat``.
+ *
* \param isDirect
* This flag makes the server set the ``is_direct`` flag on the
* ``m.room.member`` events sent to the users in ``invite`` and
* ``invite_3pid``. See `Direct Messaging`_ for more information.
+ *
* \param powerLevelContentOverride
* The power level content to override in the default power level
* event. This object is applied on top of the generated
@@ -251,19 +281,31 @@ public:
Omittable<bool> isDirect = none,
const QJsonObject& powerLevelContentOverride = {});
- ~CreateRoomJob() override;
-
// Result properties
/// The created room's ID.
- const QString& roomId() const;
+ QString roomId() const { return loadFromJson<QString>("room_id"_ls); }
+};
-protected:
- Status parseJson(const QJsonDocument& data) override;
+template <>
+struct JsonObjectConverter<CreateRoomJob::Invite3pid> {
+ static void dumpTo(QJsonObject& jo, const CreateRoomJob::Invite3pid& pod)
+ {
+ addParam<>(jo, QStringLiteral("id_server"), pod.idServer);
+ addParam<>(jo, QStringLiteral("id_access_token"), pod.idAccessToken);
+ addParam<>(jo, QStringLiteral("medium"), pod.medium);
+ addParam<>(jo, QStringLiteral("address"), pod.address);
+ }
+};
-private:
- class Private;
- QScopedPointer<Private> d;
+template <>
+struct JsonObjectConverter<CreateRoomJob::StateEvent> {
+ 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 Quotient
diff --git a/lib/csapi/definitions/auth_data.cpp b/lib/csapi/definitions/auth_data.cpp
deleted file mode 100644
index edeb7111..00000000
--- a/lib/csapi/definitions/auth_data.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#include "auth_data.h"
-
-using namespace Quotient;
-
-void JsonObjectConverter<AuthenticationData>::dumpTo(
- QJsonObject& jo, const AuthenticationData& pod)
-{
- fillJson(jo, pod.authInfo);
- addParam<>(jo, QStringLiteral("type"), pod.type);
- addParam<IfNotEmpty>(jo, QStringLiteral("session"), pod.session);
-}
-
-void JsonObjectConverter<AuthenticationData>::fillFrom(QJsonObject jo,
- AuthenticationData& result)
-{
- fromJson(jo.take("type"_ls), result.type);
- fromJson(jo.take("session"_ls), result.session);
- fromJson(jo, result.authInfo);
-}
diff --git a/lib/csapi/definitions/auth_data.h b/lib/csapi/definitions/auth_data.h
index e564f7f3..e92596d0 100644
--- a/lib/csapi/definitions/auth_data.h
+++ b/lib/csapi/definitions/auth_data.h
@@ -6,13 +6,7 @@
#include "converters.h"
-#include <QtCore/QHash>
-#include <QtCore/QJsonObject>
-
namespace Quotient {
-
-// Data structures
-
/// Used by clients to submit authentication information to the
/// interactive-authentication API
struct AuthenticationData {
@@ -28,8 +22,18 @@ struct AuthenticationData {
template <>
struct JsonObjectConverter<AuthenticationData> {
- static void dumpTo(QJsonObject& jo, const AuthenticationData& pod);
- static void fillFrom(QJsonObject jo, AuthenticationData& pod);
+ static void dumpTo(QJsonObject& jo, const AuthenticationData& pod)
+ {
+ fillJson(jo, pod.authInfo);
+ addParam<>(jo, QStringLiteral("type"), pod.type);
+ addParam<IfNotEmpty>(jo, QStringLiteral("session"), pod.session);
+ }
+ static void fillFrom(QJsonObject jo, AuthenticationData& pod)
+ {
+ fromJson(jo.take("type"_ls), pod.type);
+ fromJson(jo.take("session"_ls), pod.session);
+ fromJson(jo, pod.authInfo);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/definitions/client_device.cpp b/lib/csapi/definitions/client_device.cpp
deleted file mode 100644
index 09544138..00000000
--- a/lib/csapi/definitions/client_device.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#include "client_device.h"
-
-using namespace Quotient;
-
-void JsonObjectConverter<Device>::dumpTo(QJsonObject& jo, const Device& pod)
-{
- 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);
-}
-
-void JsonObjectConverter<Device>::fillFrom(const QJsonObject& jo, Device& 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 2cf75950..a5ab1bfc 100644
--- a/lib/csapi/definitions/client_device.h
+++ b/lib/csapi/definitions/client_device.h
@@ -7,9 +7,6 @@
#include "converters.h"
namespace Quotient {
-
-// Data structures
-
/// A client device
struct Device {
/// Identifier of this device.
@@ -31,8 +28,21 @@ struct Device {
template <>
struct JsonObjectConverter<Device> {
- static void dumpTo(QJsonObject& jo, const Device& pod);
- static void fillFrom(const QJsonObject& jo, Device& pod);
+ static void dumpTo(QJsonObject& jo, const Device& pod)
+ {
+ 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);
+ }
+ static void fillFrom(const QJsonObject& jo, Device& pod)
+ {
+ fromJson(jo.value("device_id"_ls), pod.deviceId);
+ fromJson(jo.value("display_name"_ls), pod.displayName);
+ fromJson(jo.value("last_seen_ip"_ls), pod.lastSeenIp);
+ fromJson(jo.value("last_seen_ts"_ls), pod.lastSeenTs);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/definitions/device_keys.cpp b/lib/csapi/definitions/device_keys.cpp
deleted file mode 100644
index 0583840d..00000000
--- a/lib/csapi/definitions/device_keys.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#include "device_keys.h"
-
-using namespace Quotient;
-
-void JsonObjectConverter<DeviceKeys>::dumpTo(QJsonObject& jo,
- const DeviceKeys& pod)
-{
- 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);
-}
-
-void JsonObjectConverter<DeviceKeys>::fillFrom(const QJsonObject& jo,
- DeviceKeys& 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 a067b4f3..3065f218 100644
--- a/lib/csapi/definitions/device_keys.h
+++ b/lib/csapi/definitions/device_keys.h
@@ -6,12 +6,7 @@
#include "converters.h"
-#include <QtCore/QHash>
-
namespace Quotient {
-
-// Data structures
-
/// Device identity keys
struct DeviceKeys {
/// The ID of the user the device belongs to. Must match the user ID used
@@ -40,8 +35,22 @@ struct DeviceKeys {
template <>
struct JsonObjectConverter<DeviceKeys> {
- static void dumpTo(QJsonObject& jo, const DeviceKeys& pod);
- static void fillFrom(const QJsonObject& jo, DeviceKeys& pod);
+ static void dumpTo(QJsonObject& jo, const DeviceKeys& pod)
+ {
+ 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);
+ }
+ static void fillFrom(const QJsonObject& jo, DeviceKeys& pod)
+ {
+ fromJson(jo.value("user_id"_ls), pod.userId);
+ fromJson(jo.value("device_id"_ls), pod.deviceId);
+ fromJson(jo.value("algorithms"_ls), pod.algorithms);
+ fromJson(jo.value("keys"_ls), pod.keys);
+ fromJson(jo.value("signatures"_ls), pod.signatures);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/definitions/event_filter.cpp b/lib/csapi/definitions/event_filter.cpp
deleted file mode 100644
index b21e08b5..00000000
--- a/lib/csapi/definitions/event_filter.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#include "event_filter.h"
-
-using namespace Quotient;
-
-void JsonObjectConverter<EventFilter>::dumpTo(QJsonObject& jo,
- const EventFilter& pod)
-{
- 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);
-}
-
-void JsonObjectConverter<EventFilter>::fillFrom(const QJsonObject& jo,
- EventFilter& 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 3958b125..67497412 100644
--- a/lib/csapi/definitions/event_filter.h
+++ b/lib/csapi/definitions/event_filter.h
@@ -8,8 +8,6 @@
namespace Quotient {
-// Data structures
-
struct EventFilter {
/// The maximum number of events to return.
Omittable<int> limit;
@@ -37,8 +35,22 @@ struct EventFilter {
template <>
struct JsonObjectConverter<EventFilter> {
- static void dumpTo(QJsonObject& jo, const EventFilter& pod);
- static void fillFrom(const QJsonObject& jo, EventFilter& pod);
+ static void dumpTo(QJsonObject& jo, const EventFilter& pod)
+ {
+ 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);
+ }
+ static void fillFrom(const QJsonObject& jo, EventFilter& pod)
+ {
+ fromJson(jo.value("limit"_ls), pod.limit);
+ fromJson(jo.value("not_senders"_ls), pod.notSenders);
+ fromJson(jo.value("not_types"_ls), pod.notTypes);
+ fromJson(jo.value("senders"_ls), pod.senders);
+ fromJson(jo.value("types"_ls), pod.types);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/definitions/openid_token.h b/lib/csapi/definitions/openid_token.h
new file mode 100644
index 00000000..5e68c376
--- /dev/null
+++ b/lib/csapi/definitions/openid_token.h
@@ -0,0 +1,48 @@
+/******************************************************************************
+ * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
+ */
+
+#pragma once
+
+#include "converters.h"
+
+namespace Quotient {
+
+struct OpenidToken {
+ /// An access token the consumer may use to verify the identity of
+ /// the person who generated the token. This is given to the federation
+ /// API ``GET /openid/userinfo`` to verify the user's identity.
+ QString accessToken;
+
+ /// The string ``Bearer``.
+ QString tokenType;
+
+ /// The homeserver domain the consumer should use when attempting to
+ /// verify the user's identity.
+ QString matrixServerName;
+
+ /// The number of seconds before this token expires and a new one must
+ /// be generated.
+ int expiresIn;
+};
+
+template <>
+struct JsonObjectConverter<OpenidToken> {
+ static void dumpTo(QJsonObject& jo, const OpenidToken& pod)
+ {
+ addParam<>(jo, QStringLiteral("access_token"), pod.accessToken);
+ addParam<>(jo, QStringLiteral("token_type"), pod.tokenType);
+ addParam<>(jo, QStringLiteral("matrix_server_name"),
+ pod.matrixServerName);
+ addParam<>(jo, QStringLiteral("expires_in"), pod.expiresIn);
+ }
+ static void fillFrom(const QJsonObject& jo, OpenidToken& pod)
+ {
+ fromJson(jo.value("access_token"_ls), pod.accessToken);
+ fromJson(jo.value("token_type"_ls), pod.tokenType);
+ fromJson(jo.value("matrix_server_name"_ls), pod.matrixServerName);
+ fromJson(jo.value("expires_in"_ls), pod.expiresIn);
+ }
+};
+
+} // namespace Quotient
diff --git a/lib/csapi/definitions/public_rooms_response.cpp b/lib/csapi/definitions/public_rooms_response.cpp
deleted file mode 100644
index b6009718..00000000
--- a/lib/csapi/definitions/public_rooms_response.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#include "public_rooms_response.h"
-
-using namespace Quotient;
-
-void JsonObjectConverter<PublicRoomsChunk>::dumpTo(QJsonObject& jo,
- const PublicRoomsChunk& pod)
-{
- addParam<IfNotEmpty>(jo, QStringLiteral("aliases"), pod.aliases);
- addParam<IfNotEmpty>(jo, QStringLiteral("canonical_alias"),
- pod.canonicalAlias);
- addParam<IfNotEmpty>(jo, QStringLiteral("name"), pod.name);
- addParam<>(jo, QStringLiteral("num_joined_members"), pod.numJoinedMembers);
- addParam<>(jo, QStringLiteral("room_id"), pod.roomId);
- addParam<IfNotEmpty>(jo, QStringLiteral("topic"), pod.topic);
- addParam<>(jo, QStringLiteral("world_readable"), pod.worldReadable);
- addParam<>(jo, QStringLiteral("guest_can_join"), pod.guestCanJoin);
- addParam<IfNotEmpty>(jo, QStringLiteral("avatar_url"), pod.avatarUrl);
-}
-
-void JsonObjectConverter<PublicRoomsChunk>::fillFrom(const QJsonObject& jo,
- PublicRoomsChunk& 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);
-}
-
-void JsonObjectConverter<PublicRoomsResponse>::dumpTo(
- QJsonObject& jo, const PublicRoomsResponse& pod)
-{
- 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);
-}
-
-void JsonObjectConverter<PublicRoomsResponse>::fillFrom(
- const QJsonObject& jo, PublicRoomsResponse& 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 36aa52b9..8f30e607 100644
--- a/lib/csapi/definitions/public_rooms_response.h
+++ b/lib/csapi/definitions/public_rooms_response.h
@@ -6,12 +6,8 @@
#include "converters.h"
-#include <QtCore/QVector>
-
namespace Quotient {
-// Data structures
-
struct PublicRoomsChunk {
/// Aliases of the room. May be empty.
QStringList aliases;
@@ -45,9 +41,34 @@ struct PublicRoomsChunk {
template <>
struct JsonObjectConverter<PublicRoomsChunk> {
- static void dumpTo(QJsonObject& jo, const PublicRoomsChunk& pod);
- static void fillFrom(const QJsonObject& jo, PublicRoomsChunk& pod);
+ static void dumpTo(QJsonObject& jo, const PublicRoomsChunk& pod)
+ {
+ addParam<IfNotEmpty>(jo, QStringLiteral("aliases"), pod.aliases);
+ addParam<IfNotEmpty>(jo, QStringLiteral("canonical_alias"),
+ pod.canonicalAlias);
+ addParam<IfNotEmpty>(jo, QStringLiteral("name"), pod.name);
+ addParam<>(jo, QStringLiteral("num_joined_members"),
+ pod.numJoinedMembers);
+ addParam<>(jo, QStringLiteral("room_id"), pod.roomId);
+ addParam<IfNotEmpty>(jo, QStringLiteral("topic"), pod.topic);
+ addParam<>(jo, QStringLiteral("world_readable"), pod.worldReadable);
+ addParam<>(jo, QStringLiteral("guest_can_join"), pod.guestCanJoin);
+ addParam<IfNotEmpty>(jo, QStringLiteral("avatar_url"), pod.avatarUrl);
+ }
+ static void fillFrom(const QJsonObject& jo, PublicRoomsChunk& pod)
+ {
+ fromJson(jo.value("aliases"_ls), pod.aliases);
+ fromJson(jo.value("canonical_alias"_ls), pod.canonicalAlias);
+ fromJson(jo.value("name"_ls), pod.name);
+ fromJson(jo.value("num_joined_members"_ls), pod.numJoinedMembers);
+ fromJson(jo.value("room_id"_ls), pod.roomId);
+ fromJson(jo.value("topic"_ls), pod.topic);
+ fromJson(jo.value("world_readable"_ls), pod.worldReadable);
+ fromJson(jo.value("guest_can_join"_ls), pod.guestCanJoin);
+ fromJson(jo.value("avatar_url"_ls), pod.avatarUrl);
+ }
};
+
/// A list of the rooms on the server.
struct PublicRoomsResponse {
/// A paginated chunk of public rooms.
@@ -70,8 +91,22 @@ struct PublicRoomsResponse {
template <>
struct JsonObjectConverter<PublicRoomsResponse> {
- static void dumpTo(QJsonObject& jo, const PublicRoomsResponse& pod);
- static void fillFrom(const QJsonObject& jo, PublicRoomsResponse& pod);
+ static void dumpTo(QJsonObject& jo, const PublicRoomsResponse& pod)
+ {
+ 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);
+ }
+ static void fillFrom(const QJsonObject& jo, PublicRoomsResponse& pod)
+ {
+ fromJson(jo.value("chunk"_ls), pod.chunk);
+ fromJson(jo.value("next_batch"_ls), pod.nextBatch);
+ fromJson(jo.value("prev_batch"_ls), pod.prevBatch);
+ fromJson(jo.value("total_room_count_estimate"_ls),
+ pod.totalRoomCountEstimate);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/definitions/push_condition.cpp b/lib/csapi/definitions/push_condition.cpp
deleted file mode 100644
index 343b4f1a..00000000
--- a/lib/csapi/definitions/push_condition.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#include "push_condition.h"
-
-using namespace Quotient;
-
-void JsonObjectConverter<PushCondition>::dumpTo(QJsonObject& jo,
- const PushCondition& pod)
-{
- 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);
-}
-
-void JsonObjectConverter<PushCondition>::fillFrom(const QJsonObject& jo,
- PushCondition& 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 189153b3..a6decf1b 100644
--- a/lib/csapi/definitions/push_condition.h
+++ b/lib/csapi/definitions/push_condition.h
@@ -8,13 +8,18 @@
namespace Quotient {
-// Data structures
-
struct PushCondition {
+ /// The kind of condition to apply. See `conditions <#conditions>`_ for
+ /// more information on the allowed kinds and how they work.
QString kind;
/// Required for ``event_match`` conditions. The dot-separated field of the
/// event to match.
+ ///
+ /// Required for ``sender_notification_permission`` conditions. The field in
+ /// the power level event the user needs a minimum power level for. Fields
+ /// must be specified under the ``notifications`` property in the power
+ /// level event's ``content``.
QString key;
/// Required for ``event_match`` conditions. The glob-style pattern to
@@ -32,8 +37,20 @@ struct PushCondition {
template <>
struct JsonObjectConverter<PushCondition> {
- static void dumpTo(QJsonObject& jo, const PushCondition& pod);
- static void fillFrom(const QJsonObject& jo, PushCondition& pod);
+ static void dumpTo(QJsonObject& jo, const PushCondition& pod)
+ {
+ 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);
+ }
+ static void fillFrom(const QJsonObject& jo, PushCondition& pod)
+ {
+ fromJson(jo.value("kind"_ls), pod.kind);
+ fromJson(jo.value("key"_ls), pod.key);
+ fromJson(jo.value("pattern"_ls), pod.pattern);
+ fromJson(jo.value("is"_ls), pod.is);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/definitions/push_rule.cpp b/lib/csapi/definitions/push_rule.cpp
deleted file mode 100644
index eae7e446..00000000
--- a/lib/csapi/definitions/push_rule.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#include "push_rule.h"
-
-using namespace Quotient;
-
-void JsonObjectConverter<PushRule>::dumpTo(QJsonObject& jo, const PushRule& pod)
-{
- 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);
-}
-
-void JsonObjectConverter<PushRule>::fillFrom(const QJsonObject& jo,
- PushRule& 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 c09d063f..43749bae 100644
--- a/lib/csapi/definitions/push_rule.h
+++ b/lib/csapi/definitions/push_rule.h
@@ -8,14 +8,8 @@
#include "csapi/definitions/push_condition.h"
-#include <QtCore/QJsonObject>
-#include <QtCore/QVariant>
-#include <QtCore/QVector>
-
namespace Quotient {
-// Data structures
-
struct PushRule {
/// The actions to perform when this rule is matched.
QVector<QVariant> actions;
@@ -41,8 +35,24 @@ struct PushRule {
template <>
struct JsonObjectConverter<PushRule> {
- static void dumpTo(QJsonObject& jo, const PushRule& pod);
- static void fillFrom(const QJsonObject& jo, PushRule& pod);
+ static void dumpTo(QJsonObject& jo, const PushRule& pod)
+ {
+ 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);
+ }
+ static void fillFrom(const QJsonObject& jo, PushRule& pod)
+ {
+ fromJson(jo.value("actions"_ls), pod.actions);
+ fromJson(jo.value("default"_ls), pod.isDefault);
+ fromJson(jo.value("enabled"_ls), pod.enabled);
+ fromJson(jo.value("rule_id"_ls), pod.ruleId);
+ fromJson(jo.value("conditions"_ls), pod.conditions);
+ fromJson(jo.value("pattern"_ls), pod.pattern);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/definitions/push_ruleset.cpp b/lib/csapi/definitions/push_ruleset.cpp
deleted file mode 100644
index a2db35d9..00000000
--- a/lib/csapi/definitions/push_ruleset.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#include "push_ruleset.h"
-
-using namespace Quotient;
-
-void JsonObjectConverter<PushRuleset>::dumpTo(QJsonObject& jo,
- const PushRuleset& pod)
-{
- 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);
-}
-
-void JsonObjectConverter<PushRuleset>::fillFrom(const QJsonObject& jo,
- PushRuleset& 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 98a21408..ba780a33 100644
--- a/lib/csapi/definitions/push_ruleset.h
+++ b/lib/csapi/definitions/push_ruleset.h
@@ -8,12 +8,8 @@
#include "csapi/definitions/push_rule.h"
-#include <QtCore/QVector>
-
namespace Quotient {
-// Data structures
-
struct PushRuleset {
QVector<PushRule> content;
@@ -28,8 +24,22 @@ struct PushRuleset {
template <>
struct JsonObjectConverter<PushRuleset> {
- static void dumpTo(QJsonObject& jo, const PushRuleset& pod);
- static void fillFrom(const QJsonObject& jo, PushRuleset& pod);
+ static void dumpTo(QJsonObject& jo, const PushRuleset& pod)
+ {
+ 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);
+ }
+ static void fillFrom(const QJsonObject& jo, PushRuleset& pod)
+ {
+ fromJson(jo.value("content"_ls), pod.content);
+ fromJson(jo.value("override"_ls), pod.override);
+ fromJson(jo.value("room"_ls), pod.room);
+ fromJson(jo.value("sender"_ls), pod.sender);
+ fromJson(jo.value("underride"_ls), pod.underride);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/definitions/request_email_validation.h b/lib/csapi/definitions/request_email_validation.h
new file mode 100644
index 00000000..e6ab261d
--- /dev/null
+++ b/lib/csapi/definitions/request_email_validation.h
@@ -0,0 +1,48 @@
+/******************************************************************************
+ * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
+ */
+
+#pragma once
+
+#include "converters.h"
+
+#include "csapi/./definitions/../../identity/definitions/request_email_validation.h"
+
+namespace Quotient {
+
+struct EmailValidationData : RequestEmailValidation {
+ /// The hostname of the identity server to communicate with. May optionally
+ /// include a port. This parameter is ignored when the homeserver handles
+ /// 3PID verification.
+ ///
+ /// This parameter is deprecated with a plan to be removed in a future
+ /// specification version for ``/account/password`` and ``/register``
+ /// requests.
+ QString idServer;
+
+ /// An access token previously registered with the identity server. Servers
+ /// can treat this as optional to distinguish between r0.5-compatible
+ /// clients and this specification version.
+ ///
+ /// Required if an ``id_server`` is supplied.
+ QString idAccessToken;
+};
+
+template <>
+struct JsonObjectConverter<EmailValidationData> {
+ static void dumpTo(QJsonObject& jo, const EmailValidationData& pod)
+ {
+ fillJson<RequestEmailValidation>(jo, pod);
+ addParam<IfNotEmpty>(jo, QStringLiteral("id_server"), pod.idServer);
+ addParam<IfNotEmpty>(jo, QStringLiteral("id_access_token"),
+ pod.idAccessToken);
+ }
+ static void fillFrom(const QJsonObject& jo, EmailValidationData& pod)
+ {
+ fillFromJson<RequestEmailValidation>(jo, pod);
+ fromJson(jo.value("id_server"_ls), pod.idServer);
+ fromJson(jo.value("id_access_token"_ls), pod.idAccessToken);
+ }
+};
+
+} // namespace Quotient
diff --git a/lib/csapi/definitions/request_msisdn_validation.h b/lib/csapi/definitions/request_msisdn_validation.h
new file mode 100644
index 00000000..6f161f00
--- /dev/null
+++ b/lib/csapi/definitions/request_msisdn_validation.h
@@ -0,0 +1,48 @@
+/******************************************************************************
+ * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
+ */
+
+#pragma once
+
+#include "converters.h"
+
+#include "csapi/./definitions/../../identity/definitions/request_msisdn_validation.h"
+
+namespace Quotient {
+
+struct MsisdnValidationData : RequestMsisdnValidation {
+ /// The hostname of the identity server to communicate with. May optionally
+ /// include a port. This parameter is ignored when the homeserver handles
+ /// 3PID verification.
+ ///
+ /// This parameter is deprecated with a plan to be removed in a future
+ /// specification version for ``/account/password`` and ``/register``
+ /// requests.
+ QString idServer;
+
+ /// An access token previously registered with the identity server. Servers
+ /// can treat this as optional to distinguish between r0.5-compatible
+ /// clients and this specification version.
+ ///
+ /// Required if an ``id_server`` is supplied.
+ QString idAccessToken;
+};
+
+template <>
+struct JsonObjectConverter<MsisdnValidationData> {
+ static void dumpTo(QJsonObject& jo, const MsisdnValidationData& pod)
+ {
+ fillJson<RequestMsisdnValidation>(jo, pod);
+ addParam<IfNotEmpty>(jo, QStringLiteral("id_server"), pod.idServer);
+ addParam<IfNotEmpty>(jo, QStringLiteral("id_access_token"),
+ pod.idAccessToken);
+ }
+ static void fillFrom(const QJsonObject& jo, MsisdnValidationData& pod)
+ {
+ fillFromJson<RequestMsisdnValidation>(jo, pod);
+ fromJson(jo.value("id_server"_ls), pod.idServer);
+ fromJson(jo.value("id_access_token"_ls), pod.idAccessToken);
+ }
+};
+
+} // namespace Quotient
diff --git a/lib/csapi/definitions/request_token_response.h b/lib/csapi/definitions/request_token_response.h
new file mode 100644
index 00000000..00222839
--- /dev/null
+++ b/lib/csapi/definitions/request_token_response.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
+ */
+
+#pragma once
+
+#include "converters.h"
+
+namespace Quotient {
+
+struct RequestTokenResponse {
+ /// The session ID. Session IDs are opaque strings that must consist
+ /// entirely of the characters ``[0-9a-zA-Z.=_-]``. Their length must not
+ /// exceed 255 characters and they must not be empty.
+ QString sid;
+
+ /// An optional field containing a URL where the client must submit the
+ /// validation token to, with identical parameters to the Identity Service
+ /// API's ``POST /validate/email/submitToken`` endpoint (without the
+ /// requirement for an access token). The homeserver must send this token to
+ /// the user (if applicable), who should then be prompted to provide it to
+ /// the client.
+ ///
+ /// If this field is not present, the client can assume that verification
+ /// will happen without the client's involvement provided the homeserver
+ /// advertises this specification version in the ``/versions`` response
+ /// (ie: r0.5.0).
+ QString submitUrl;
+};
+
+template <>
+struct JsonObjectConverter<RequestTokenResponse> {
+ static void dumpTo(QJsonObject& jo, const RequestTokenResponse& pod)
+ {
+ addParam<>(jo, QStringLiteral("sid"), pod.sid);
+ addParam<IfNotEmpty>(jo, QStringLiteral("submit_url"), pod.submitUrl);
+ }
+ static void fillFrom(const QJsonObject& jo, RequestTokenResponse& pod)
+ {
+ fromJson(jo.value("sid"_ls), pod.sid);
+ fromJson(jo.value("submit_url"_ls), pod.submitUrl);
+ }
+};
+
+} // namespace Quotient
diff --git a/lib/csapi/definitions/room_event_filter.cpp b/lib/csapi/definitions/room_event_filter.cpp
deleted file mode 100644
index 5613d8d2..00000000
--- a/lib/csapi/definitions/room_event_filter.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#include "room_event_filter.h"
-
-using namespace Quotient;
-
-void JsonObjectConverter<RoomEventFilter>::dumpTo(QJsonObject& jo,
- const RoomEventFilter& pod)
-{
- 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);
-}
-
-void JsonObjectConverter<RoomEventFilter>::fillFrom(const QJsonObject& jo,
- RoomEventFilter& 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 756f9ada..11e87fde 100644
--- a/lib/csapi/definitions/room_event_filter.h
+++ b/lib/csapi/definitions/room_event_filter.h
@@ -10,9 +10,19 @@
namespace Quotient {
-// Data structures
-
struct RoomEventFilter : EventFilter {
+ /// If ``true``, enables lazy-loading of membership events. See
+ /// `Lazy-loading room members <#lazy-loading-room-members>`_
+ /// for more information. Defaults to ``false``.
+ Omittable<bool> lazyLoadMembers;
+
+ /// If ``true``, sends all membership events for all events, even if they
+ /// have already been sent to the client. Does not apply unless
+ /// ``lazy_load_members`` is ``true``. See `Lazy-loading room members
+ /// <#lazy-loading-room-members>`_ for more information. Defaults to
+ /// ``false``.
+ Omittable<bool> includeRedundantMembers;
+
/// A list of room IDs to exclude. If this list is absent then no rooms are
/// excluded. A matching room will be excluded even if it is listed in the
/// ``'rooms'`` filter.
@@ -30,8 +40,28 @@ struct RoomEventFilter : EventFilter {
template <>
struct JsonObjectConverter<RoomEventFilter> {
- static void dumpTo(QJsonObject& jo, const RoomEventFilter& pod);
- static void fillFrom(const QJsonObject& jo, RoomEventFilter& pod);
+ static void dumpTo(QJsonObject& jo, const RoomEventFilter& pod)
+ {
+ fillJson<EventFilter>(jo, pod);
+ addParam<IfNotEmpty>(jo, QStringLiteral("lazy_load_members"),
+ pod.lazyLoadMembers);
+ addParam<IfNotEmpty>(jo, QStringLiteral("include_redundant_members"),
+ pod.includeRedundantMembers);
+ addParam<IfNotEmpty>(jo, QStringLiteral("not_rooms"), pod.notRooms);
+ addParam<IfNotEmpty>(jo, QStringLiteral("rooms"), pod.rooms);
+ addParam<IfNotEmpty>(jo, QStringLiteral("contains_url"),
+ pod.containsUrl);
+ }
+ static void fillFrom(const QJsonObject& jo, RoomEventFilter& pod)
+ {
+ fillFromJson<EventFilter>(jo, pod);
+ fromJson(jo.value("lazy_load_members"_ls), pod.lazyLoadMembers);
+ fromJson(jo.value("include_redundant_members"_ls),
+ pod.includeRedundantMembers);
+ fromJson(jo.value("not_rooms"_ls), pod.notRooms);
+ fromJson(jo.value("rooms"_ls), pod.rooms);
+ fromJson(jo.value("contains_url"_ls), pod.containsUrl);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/definitions/sync_filter.cpp b/lib/csapi/definitions/sync_filter.cpp
deleted file mode 100644
index 15c4bdc1..00000000
--- a/lib/csapi/definitions/sync_filter.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#include "sync_filter.h"
-
-using namespace Quotient;
-
-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)
-{
- addParam<IfNotEmpty>(jo, QStringLiteral("not_rooms"), pod.notRooms);
- addParam<IfNotEmpty>(jo, QStringLiteral("rooms"), pod.rooms);
- addParam<IfNotEmpty>(jo, QStringLiteral("ephemeral"), pod.ephemeral);
- addParam<IfNotEmpty>(jo, QStringLiteral("include_leave"), pod.includeLeave);
- addParam<IfNotEmpty>(jo, QStringLiteral("state"), pod.state);
- addParam<IfNotEmpty>(jo, QStringLiteral("timeline"), pod.timeline);
- addParam<IfNotEmpty>(jo, QStringLiteral("account_data"), pod.accountData);
-}
-
-void JsonObjectConverter<RoomFilter>::fillFrom(const QJsonObject& jo,
- RoomFilter& 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);
-}
-
-void JsonObjectConverter<Filter>::dumpTo(QJsonObject& jo, const Filter& pod)
-{
- 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);
-}
-
-void JsonObjectConverter<Filter>::fillFrom(const QJsonObject& jo, Filter& 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 ad8d055d..9c8f08d5 100644
--- a/lib/csapi/definitions/sync_filter.h
+++ b/lib/csapi/definitions/sync_filter.h
@@ -10,40 +10,6 @@
#include "csapi/definitions/room_event_filter.h"
namespace Quotient {
-
-// 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 {
/// A list of room IDs to exclude. If this list is absent then no rooms are
@@ -59,30 +25,50 @@ struct RoomFilter {
/// The events that aren't recorded in the room history, e.g. typing and
/// receipts, to include for rooms.
- Omittable<RoomEventFilter> ephemeral;
+ RoomEventFilter ephemeral;
/// Include rooms that the user has left in the sync, default false
Omittable<bool> includeLeave;
/// The state events to include for rooms.
- Omittable<StateFilter> state;
+ RoomEventFilter state;
/// The message and state update events to include for rooms.
- Omittable<RoomEventFilter> timeline;
+ RoomEventFilter timeline;
/// The per user account data to include for rooms.
- Omittable<RoomEventFilter> accountData;
+ RoomEventFilter accountData;
};
template <>
struct JsonObjectConverter<RoomFilter> {
- static void dumpTo(QJsonObject& jo, const RoomFilter& pod);
- static void fillFrom(const QJsonObject& jo, RoomFilter& pod);
+ static void dumpTo(QJsonObject& jo, const RoomFilter& pod)
+ {
+ addParam<IfNotEmpty>(jo, QStringLiteral("not_rooms"), pod.notRooms);
+ addParam<IfNotEmpty>(jo, QStringLiteral("rooms"), pod.rooms);
+ addParam<IfNotEmpty>(jo, QStringLiteral("ephemeral"), pod.ephemeral);
+ addParam<IfNotEmpty>(jo, QStringLiteral("include_leave"),
+ pod.includeLeave);
+ addParam<IfNotEmpty>(jo, QStringLiteral("state"), pod.state);
+ addParam<IfNotEmpty>(jo, QStringLiteral("timeline"), pod.timeline);
+ addParam<IfNotEmpty>(jo, QStringLiteral("account_data"),
+ pod.accountData);
+ }
+ static void fillFrom(const QJsonObject& jo, RoomFilter& pod)
+ {
+ fromJson(jo.value("not_rooms"_ls), pod.notRooms);
+ fromJson(jo.value("rooms"_ls), pod.rooms);
+ fromJson(jo.value("ephemeral"_ls), pod.ephemeral);
+ fromJson(jo.value("include_leave"_ls), pod.includeLeave);
+ fromJson(jo.value("state"_ls), pod.state);
+ fromJson(jo.value("timeline"_ls), pod.timeline);
+ fromJson(jo.value("account_data"_ls), pod.accountData);
+ }
};
struct Filter {
/// List of event fields to include. If this list is absent then all fields
- /// are included. The entries may include '.' charaters to indicate
+ /// are included. The entries may include '.' characters to indicate
/// sub-fields. So ['content.body'] will include the 'body' field of the
/// 'content' object. A literal '.' character in a field name may be escaped
/// using a '\\'. A server may include more fields than were requested.
@@ -90,23 +76,40 @@ struct Filter {
/// The format to use for events. 'client' will return the events in a
/// format suitable for clients. 'federation' will return the raw event as
- /// receieved over federation. The default is 'client'.
+ /// received over federation. The default is 'client'.
QString eventFormat;
/// The presence updates to include.
- Omittable<EventFilter> presence;
+ EventFilter presence;
/// The user account data that isn't associated with rooms to include.
- Omittable<EventFilter> accountData;
+ EventFilter accountData;
/// Filters to be applied to room data.
- Omittable<RoomFilter> room;
+ RoomFilter room;
};
template <>
struct JsonObjectConverter<Filter> {
- static void dumpTo(QJsonObject& jo, const Filter& pod);
- static void fillFrom(const QJsonObject& jo, Filter& pod);
+ static void dumpTo(QJsonObject& jo, const Filter& pod)
+ {
+ 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);
+ }
+ static void fillFrom(const QJsonObject& jo, Filter& pod)
+ {
+ fromJson(jo.value("event_fields"_ls), pod.eventFields);
+ fromJson(jo.value("event_format"_ls), pod.eventFormat);
+ fromJson(jo.value("presence"_ls), pod.presence);
+ fromJson(jo.value("account_data"_ls), pod.accountData);
+ fromJson(jo.value("room"_ls), pod.room);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/definitions/third_party_signed.h b/lib/csapi/definitions/third_party_signed.h
new file mode 100644
index 00000000..526545d0
--- /dev/null
+++ b/lib/csapi/definitions/third_party_signed.h
@@ -0,0 +1,44 @@
+/******************************************************************************
+ * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
+ */
+
+#pragma once
+
+#include "converters.h"
+
+namespace Quotient {
+/// A signature of an ``m.third_party_invite`` token to prove that this user
+/// owns a third party identity which has been invited to the room.
+struct ThirdPartySigned {
+ /// The Matrix ID of the user who issued the invite.
+ QString sender;
+
+ /// The Matrix ID of the invitee.
+ QString mxid;
+
+ /// The state key of the m.third_party_invite event.
+ QString token;
+
+ /// A signatures object containing a signature of the entire signed object.
+ QHash<QString, QHash<QString, QString>> signatures;
+};
+
+template <>
+struct JsonObjectConverter<ThirdPartySigned> {
+ static void dumpTo(QJsonObject& jo, const 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);
+ }
+ static void fillFrom(const QJsonObject& jo, ThirdPartySigned& pod)
+ {
+ fromJson(jo.value("sender"_ls), pod.sender);
+ fromJson(jo.value("mxid"_ls), pod.mxid);
+ fromJson(jo.value("token"_ls), pod.token);
+ fromJson(jo.value("signatures"_ls), pod.signatures);
+ }
+};
+
+} // namespace Quotient
diff --git a/lib/csapi/definitions/user_identifier.cpp b/lib/csapi/definitions/user_identifier.cpp
deleted file mode 100644
index 9e9b4fe9..00000000
--- a/lib/csapi/definitions/user_identifier.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#include "user_identifier.h"
-
-using namespace Quotient;
-
-void JsonObjectConverter<UserIdentifier>::dumpTo(QJsonObject& jo,
- const UserIdentifier& pod)
-{
- fillJson(jo, pod.additionalProperties);
- addParam<>(jo, QStringLiteral("type"), pod.type);
-}
-
-void JsonObjectConverter<UserIdentifier>::fillFrom(QJsonObject jo,
- UserIdentifier& result)
-{
- fromJson(jo.take("type"_ls), result.type);
- fromJson(jo, result.additionalProperties);
-}
diff --git a/lib/csapi/definitions/user_identifier.h b/lib/csapi/definitions/user_identifier.h
index 72a81677..dadf6f97 100644
--- a/lib/csapi/definitions/user_identifier.h
+++ b/lib/csapi/definitions/user_identifier.h
@@ -6,12 +6,7 @@
#include "converters.h"
-#include <QtCore/QVariant>
-
namespace Quotient {
-
-// Data structures
-
/// Identification information for a user
struct UserIdentifier {
/// The type of identification. See `Identifier types`_ for supported
@@ -24,8 +19,16 @@ struct UserIdentifier {
template <>
struct JsonObjectConverter<UserIdentifier> {
- static void dumpTo(QJsonObject& jo, const UserIdentifier& pod);
- static void fillFrom(QJsonObject jo, UserIdentifier& pod);
+ static void dumpTo(QJsonObject& jo, const UserIdentifier& pod)
+ {
+ fillJson(jo, pod.additionalProperties);
+ addParam<>(jo, QStringLiteral("type"), pod.type);
+ }
+ static void fillFrom(QJsonObject jo, UserIdentifier& pod)
+ {
+ fromJson(jo.take("type"_ls), pod.type);
+ fromJson(jo, pod.additionalProperties);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/definitions/wellknown/full.cpp b/lib/csapi/definitions/wellknown/full.cpp
deleted file mode 100644
index 595db0e5..00000000
--- a/lib/csapi/definitions/wellknown/full.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#include "full.h"
-
-using namespace Quotient;
-
-void JsonObjectConverter<DiscoveryInformation>::dumpTo(
- QJsonObject& jo, const DiscoveryInformation& pod)
-{
- fillJson(jo, pod.additionalProperties);
- addParam<>(jo, QStringLiteral("m.homeserver"), pod.homeserver);
- addParam<IfNotEmpty>(jo, QStringLiteral("m.identity_server"),
- pod.identityServer);
-}
-
-void JsonObjectConverter<DiscoveryInformation>::fillFrom(
- QJsonObject jo, DiscoveryInformation& result)
-{
- fromJson(jo.take("m.homeserver"_ls), result.homeserver);
- fromJson(jo.take("m.identity_server"_ls), result.identityServer);
- fromJson(jo, result.additionalProperties);
-}
diff --git a/lib/csapi/definitions/wellknown/full.h b/lib/csapi/definitions/wellknown/full.h
index 88d7da79..a0ef2076 100644
--- a/lib/csapi/definitions/wellknown/full.h
+++ b/lib/csapi/definitions/wellknown/full.h
@@ -9,13 +9,7 @@
#include "csapi/definitions/wellknown/homeserver.h"
#include "csapi/definitions/wellknown/identity_server.h"
-#include <QtCore/QHash>
-#include <QtCore/QJsonObject>
-
namespace Quotient {
-
-// Data structures
-
/// Used by clients to determine the homeserver, identity server, and other
/// optional components they should be interacting with.
struct DiscoveryInformation {
@@ -33,8 +27,19 @@ struct DiscoveryInformation {
template <>
struct JsonObjectConverter<DiscoveryInformation> {
- static void dumpTo(QJsonObject& jo, const DiscoveryInformation& pod);
- static void fillFrom(QJsonObject jo, DiscoveryInformation& pod);
+ static void dumpTo(QJsonObject& jo, const DiscoveryInformation& pod)
+ {
+ fillJson(jo, pod.additionalProperties);
+ addParam<>(jo, QStringLiteral("m.homeserver"), pod.homeserver);
+ addParam<IfNotEmpty>(jo, QStringLiteral("m.identity_server"),
+ pod.identityServer);
+ }
+ static void fillFrom(QJsonObject jo, DiscoveryInformation& pod)
+ {
+ fromJson(jo.take("m.homeserver"_ls), pod.homeserver);
+ fromJson(jo.take("m.identity_server"_ls), pod.identityServer);
+ fromJson(jo, pod.additionalProperties);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/definitions/wellknown/homeserver.cpp b/lib/csapi/definitions/wellknown/homeserver.cpp
deleted file mode 100644
index 7b87aa95..00000000
--- a/lib/csapi/definitions/wellknown/homeserver.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#include "homeserver.h"
-
-using namespace Quotient;
-
-void JsonObjectConverter<HomeserverInformation>::dumpTo(
- QJsonObject& jo, const HomeserverInformation& pod)
-{
- addParam<>(jo, QStringLiteral("base_url"), pod.baseUrl);
-}
-
-void JsonObjectConverter<HomeserverInformation>::fillFrom(
- const QJsonObject& jo, HomeserverInformation& 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 7607c8b5..5cfaca24 100644
--- a/lib/csapi/definitions/wellknown/homeserver.h
+++ b/lib/csapi/definitions/wellknown/homeserver.h
@@ -7,9 +7,6 @@
#include "converters.h"
namespace Quotient {
-
-// Data structures
-
/// Used by clients to discover homeserver information.
struct HomeserverInformation {
/// The base URL for the homeserver for client-server connections.
@@ -18,8 +15,14 @@ struct HomeserverInformation {
template <>
struct JsonObjectConverter<HomeserverInformation> {
- static void dumpTo(QJsonObject& jo, const HomeserverInformation& pod);
- static void fillFrom(const QJsonObject& jo, HomeserverInformation& pod);
+ static void dumpTo(QJsonObject& jo, const HomeserverInformation& pod)
+ {
+ addParam<>(jo, QStringLiteral("base_url"), pod.baseUrl);
+ }
+ static void fillFrom(const QJsonObject& jo, HomeserverInformation& pod)
+ {
+ fromJson(jo.value("base_url"_ls), pod.baseUrl);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/definitions/wellknown/identity_server.cpp b/lib/csapi/definitions/wellknown/identity_server.cpp
deleted file mode 100644
index 3b2a5720..00000000
--- a/lib/csapi/definitions/wellknown/identity_server.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#include "identity_server.h"
-
-using namespace Quotient;
-
-void JsonObjectConverter<IdentityServerInformation>::dumpTo(
- QJsonObject& jo, const IdentityServerInformation& pod)
-{
- addParam<>(jo, QStringLiteral("base_url"), pod.baseUrl);
-}
-
-void JsonObjectConverter<IdentityServerInformation>::fillFrom(
- const QJsonObject& jo, IdentityServerInformation& 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 d272e527..3bd07bd1 100644
--- a/lib/csapi/definitions/wellknown/identity_server.h
+++ b/lib/csapi/definitions/wellknown/identity_server.h
@@ -7,9 +7,6 @@
#include "converters.h"
namespace Quotient {
-
-// Data structures
-
/// Used by clients to discover identity server information.
struct IdentityServerInformation {
/// The base URL for the identity server for client-server connections.
@@ -18,8 +15,14 @@ struct IdentityServerInformation {
template <>
struct JsonObjectConverter<IdentityServerInformation> {
- static void dumpTo(QJsonObject& jo, const IdentityServerInformation& pod);
- static void fillFrom(const QJsonObject& jo, IdentityServerInformation& pod);
+ static void dumpTo(QJsonObject& jo, const IdentityServerInformation& pod)
+ {
+ addParam<>(jo, QStringLiteral("base_url"), pod.baseUrl);
+ }
+ static void fillFrom(const QJsonObject& jo, IdentityServerInformation& pod)
+ {
+ fromJson(jo.value("base_url"_ls), pod.baseUrl);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/device_management.cpp b/lib/csapi/device_management.cpp
index ba7570f7..eac9a545 100644
--- a/lib/csapi/device_management.cpp
+++ b/lib/csapi/device_management.cpp
@@ -4,97 +4,61 @@
#include "device_management.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-class GetDevicesJob::Private {
-public:
- QVector<Device> devices;
-};
-
QUrl GetDevicesJob::makeRequestUrl(QUrl baseUrl)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/devices");
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ QStringLiteral("/_matrix/client/r0")
+ % "/devices");
}
GetDevicesJob::GetDevicesJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetDevicesJob"),
- basePath % "/devices")
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/devices")
{}
-GetDevicesJob::~GetDevicesJob() = default;
-
-const QVector<Device>& GetDevicesJob::devices() const { return d->devices; }
-
-BaseJob::Status GetDevicesJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("devices"_ls), d->devices);
-
- return Success;
-}
-
-class GetDeviceJob::Private {
-public:
- Device data;
-};
-
QUrl GetDeviceJob::makeRequestUrl(QUrl baseUrl, const QString& deviceId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/devices/" % deviceId);
+ QStringLiteral("/_matrix/client/r0")
+ % "/devices/" % deviceId);
}
GetDeviceJob::GetDeviceJob(const QString& deviceId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetDeviceJob"),
- basePath % "/devices/" % deviceId)
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/devices/" % deviceId)
{}
-GetDeviceJob::~GetDeviceJob() = default;
-
-const Device& GetDeviceJob::data() const { return d->data; }
-
-BaseJob::Status GetDeviceJob::parseJson(const QJsonDocument& data)
-{
- fromJson(data, d->data);
-
- return Success;
-}
-
UpdateDeviceJob::UpdateDeviceJob(const QString& deviceId,
const QString& displayName)
: BaseJob(HttpVerb::Put, QStringLiteral("UpdateDeviceJob"),
- basePath % "/devices/" % deviceId)
+ QStringLiteral("/_matrix/client/r0") % "/devices/" % deviceId)
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("display_name"), displayName);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
DeleteDeviceJob::DeleteDeviceJob(const QString& deviceId,
const Omittable<AuthenticationData>& auth)
: BaseJob(HttpVerb::Delete, QStringLiteral("DeleteDeviceJob"),
- basePath % "/devices/" % deviceId)
+ QStringLiteral("/_matrix/client/r0") % "/devices/" % deviceId)
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("auth"), auth);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
DeleteDevicesJob::DeleteDevicesJob(const QStringList& devices,
const Omittable<AuthenticationData>& auth)
: BaseJob(HttpVerb::Post, QStringLiteral("DeleteDevicesJob"),
- basePath % "/delete_devices")
+ QStringLiteral("/_matrix/client/r0") % "/delete_devices")
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("devices"), devices);
addParam<IfNotEmpty>(_data, QStringLiteral("auth"), auth);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
diff --git a/lib/csapi/device_management.h b/lib/csapi/device_management.h
index 1c57db84..0abd5b84 100644
--- a/lib/csapi/device_management.h
+++ b/lib/csapi/device_management.h
@@ -4,19 +4,13 @@
#pragma once
-#include "converters.h"
-
#include "csapi/definitions/auth_data.h"
#include "csapi/definitions/client_device.h"
#include "jobs/basejob.h"
-#include <QtCore/QVector>
-
namespace Quotient {
-// Operations
-
/*! \brief List registered devices for the current user
*
* Gets information about all devices for the current user.
@@ -32,19 +26,14 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl);
- ~GetDevicesJob() override;
// Result properties
/// A list of all registered devices for this user.
- const QVector<Device>& devices() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QVector<Device> devices() const
+ {
+ return loadFromJson<QVector<Device>>("devices"_ls);
+ }
};
/*! \brief Get a single device
@@ -55,6 +44,7 @@ class GetDeviceJob : public BaseJob {
public:
/*! \brief Get a single device
*
+ *
* \param deviceId
* The device to retrieve.
*/
@@ -66,19 +56,11 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& deviceId);
- ~GetDeviceJob() override;
// Result properties
/// Device information
- const Device& data() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ Device data() const { return fromJson<Device>(jsonData()); }
};
/*! \brief Update a device
@@ -89,8 +71,10 @@ class UpdateDeviceJob : public BaseJob {
public:
/*! \brief Update a device
*
+ *
* \param deviceId
* The device to update.
+ *
* \param displayName
* The new display name for this device. If not given, the
* display name is unchanged.
@@ -109,8 +93,10 @@ class DeleteDeviceJob : public BaseJob {
public:
/*! \brief Delete a device
*
+ *
* \param deviceId
* The device to delete.
+ *
* \param auth
* Additional authentication information for the
* user-interactive authentication API.
@@ -130,8 +116,10 @@ class DeleteDevicesJob : public BaseJob {
public:
/*! \brief Bulk deletion of devices
*
+ *
* \param devices
* The list of device IDs to delete.
+ *
* \param auth
* Additional authentication information for the
* user-interactive authentication API.
diff --git a/lib/csapi/directory.cpp b/lib/csapi/directory.cpp
index 0d4029bd..25ea82e2 100644
--- a/lib/csapi/directory.cpp
+++ b/lib/csapi/directory.cpp
@@ -4,63 +4,58 @@
#include "directory.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0/directory");
-
SetRoomAliasJob::SetRoomAliasJob(const QString& roomAlias, const QString& roomId)
: BaseJob(HttpVerb::Put, QStringLiteral("SetRoomAliasJob"),
- basePath % "/room/" % roomAlias)
+ QStringLiteral("/_matrix/client/r0") % "/directory/room/"
+ % roomAlias)
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("room_id"), roomId);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
-class GetRoomIdByAliasJob::Private {
-public:
- QString roomId;
- QStringList servers;
-};
-
QUrl GetRoomIdByAliasJob::makeRequestUrl(QUrl baseUrl, const QString& roomAlias)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/room/" % roomAlias);
+ QStringLiteral("/_matrix/client/r0")
+ % "/directory/room/" % roomAlias);
}
GetRoomIdByAliasJob::GetRoomIdByAliasJob(const QString& roomAlias)
: BaseJob(HttpVerb::Get, QStringLiteral("GetRoomIdByAliasJob"),
- basePath % "/room/" % roomAlias, false)
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/directory/room/"
+ % roomAlias,
+ false)
{}
-GetRoomIdByAliasJob::~GetRoomIdByAliasJob() = default;
-
-const QString& GetRoomIdByAliasJob::roomId() const { return d->roomId; }
-
-const QStringList& GetRoomIdByAliasJob::servers() const { return d->servers; }
-
-BaseJob::Status GetRoomIdByAliasJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("room_id"_ls), d->roomId);
- fromJson(json.value("servers"_ls), d->servers);
-
- return Success;
-}
-
QUrl DeleteRoomAliasJob::makeRequestUrl(QUrl baseUrl, const QString& roomAlias)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/room/" % roomAlias);
+ QStringLiteral("/_matrix/client/r0")
+ % "/directory/room/" % roomAlias);
}
DeleteRoomAliasJob::DeleteRoomAliasJob(const QString& roomAlias)
: BaseJob(HttpVerb::Delete, QStringLiteral("DeleteRoomAliasJob"),
- basePath % "/room/" % roomAlias)
+ QStringLiteral("/_matrix/client/r0") % "/directory/room/"
+ % roomAlias)
{}
+
+QUrl GetLocalAliasesJob::makeRequestUrl(QUrl baseUrl, const QString& roomId)
+{
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ QStringLiteral("/_matrix/client/r0")
+ % "/rooms/" % roomId % "/aliases");
+}
+
+GetLocalAliasesJob::GetLocalAliasesJob(const QString& roomId)
+ : BaseJob(HttpVerb::Get, QStringLiteral("GetLocalAliasesJob"),
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/aliases")
+{
+ addExpectedKey("aliases");
+}
diff --git a/lib/csapi/directory.h b/lib/csapi/directory.h
index c13ca20a..7ae44d1d 100644
--- a/lib/csapi/directory.h
+++ b/lib/csapi/directory.h
@@ -8,8 +8,6 @@
namespace Quotient {
-// Operations
-
/*! \brief Create a new mapping from room alias to room ID.
*
*/
@@ -17,8 +15,10 @@ class SetRoomAliasJob : public BaseJob {
public:
/*! \brief Create a new mapping from room alias to room ID.
*
+ *
* \param roomAlias
* The room alias to set.
+ *
* \param roomId
* The room ID to set.
*/
@@ -37,6 +37,7 @@ class GetRoomIdByAliasJob : public BaseJob {
public:
/*! \brief Get the room ID corresponding to this room alias.
*
+ *
* \param roomAlias
* The room alias.
*/
@@ -48,22 +49,17 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomAlias);
- ~GetRoomIdByAliasJob() override;
// Result properties
/// The room ID for this room alias.
- const QString& roomId() const;
+ QString roomId() const { return loadFromJson<QString>("room_id"_ls); }
/// A list of servers that are aware of this room alias.
- const QStringList& servers() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QStringList servers() const
+ {
+ return loadFromJson<QStringList>("servers"_ls);
+ }
};
/*! \brief Remove a mapping of room alias to room ID.
@@ -73,11 +69,20 @@ private:
* Servers may choose to implement additional access control checks here, for
* instance that room aliases can only be deleted by their creator or a server
* administrator.
+ *
+ * .. Note::
+ * Servers may choose to update the ``alt_aliases`` for the
+ * ``m.room.canonical_alias`` state event in the room when an alias is removed.
+ * Servers which choose to update the canonical alias event are recommended to,
+ * in addition to their other relevant permission checks, delete the alias and
+ * return a successful response even if the user does not have permission to
+ * update the ``m.room.canonical_alias`` event.
*/
class DeleteRoomAliasJob : public BaseJob {
public:
/*! \brief Remove a mapping of room alias to room ID.
*
+ *
* \param roomAlias
* The room alias to remove.
*/
@@ -91,4 +96,49 @@ public:
static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomAlias);
};
+/*! \brief Get a list of local aliases on a given room.
+ *
+ * Get a list of aliases maintained by the local server for the
+ * given room.
+ *
+ * This endpoint can be called by users who are in the room (external
+ * users receive an ``M_FORBIDDEN`` error response). If the room's
+ * ``m.room.history_visibility`` maps to ``world_readable``, any
+ * user can call this endpoint.
+ *
+ * Servers may choose to implement additional access control checks here,
+ * such as allowing server administrators to view aliases regardless of
+ * membership.
+ *
+ * .. Note::
+ * Clients are recommended not to display this list of aliases prominently
+ * as they are not curated, unlike those listed in the
+ * ``m.room.canonical_alias`` state event.
+ */
+class GetLocalAliasesJob : public BaseJob {
+public:
+ /*! \brief Get a list of local aliases on a given room.
+ *
+ *
+ * \param roomId
+ * The room ID to find local aliases of.
+ */
+ explicit GetLocalAliasesJob(const QString& roomId);
+
+ /*! \brief Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for GetLocalAliasesJob
+ * is necessary but the job itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId);
+
+ // Result properties
+
+ /// The server's local aliases on the room. Can be empty.
+ QStringList aliases() const
+ {
+ return loadFromJson<QStringList>("aliases"_ls);
+ }
+};
+
} // namespace Quotient
diff --git a/lib/csapi/event_context.cpp b/lib/csapi/event_context.cpp
index 5bb2222e..d2a5f522 100644
--- a/lib/csapi/event_context.cpp
+++ b/lib/csapi/event_context.cpp
@@ -4,79 +4,36 @@
#include "event_context.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-class GetEventContextJob::Private {
-public:
- QString begin;
- QString end;
- RoomEvents eventsBefore;
- RoomEventPtr event;
- RoomEvents eventsAfter;
- StateEvents state;
-};
-
-BaseJob::Query queryToGetEventContext(Omittable<int> limit)
+auto queryToGetEventContext(Omittable<int> limit, const QString& filter)
{
BaseJob::Query _q;
addParam<IfNotEmpty>(_q, QStringLiteral("limit"), limit);
+ addParam<IfNotEmpty>(_q, QStringLiteral("filter"), filter);
return _q;
}
QUrl GetEventContextJob::makeRequestUrl(QUrl baseUrl, const QString& roomId,
const QString& eventId,
- Omittable<int> limit)
+ Omittable<int> limit,
+ const QString& filter)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/rooms/" % roomId % "/context/"
+ QStringLiteral("/_matrix/client/r0")
+ % "/rooms/" % roomId % "/context/"
% eventId,
- queryToGetEventContext(limit));
+ queryToGetEventContext(limit, filter));
}
GetEventContextJob::GetEventContextJob(const QString& roomId,
const QString& eventId,
- Omittable<int> limit)
+ Omittable<int> limit,
+ const QString& filter)
: BaseJob(HttpVerb::Get, QStringLiteral("GetEventContextJob"),
- basePath % "/rooms/" % roomId % "/context/" % eventId,
- queryToGetEventContext(limit))
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/context/" % eventId,
+ queryToGetEventContext(limit, filter))
{}
-
-GetEventContextJob::~GetEventContextJob() = default;
-
-const QString& GetEventContextJob::begin() const { return d->begin; }
-
-const QString& GetEventContextJob::end() const { return d->end; }
-
-RoomEvents&& GetEventContextJob::eventsBefore()
-{
- return std::move(d->eventsBefore);
-}
-
-RoomEventPtr&& GetEventContextJob::event() { return std::move(d->event); }
-
-RoomEvents&& GetEventContextJob::eventsAfter()
-{
- return std::move(d->eventsAfter);
-}
-
-StateEvents&& GetEventContextJob::state() { return std::move(d->state); }
-
-BaseJob::Status GetEventContextJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- 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/event_context.h b/lib/csapi/event_context.h
index 54441617..2f9c66d8 100644
--- a/lib/csapi/event_context.h
+++ b/lib/csapi/event_context.h
@@ -4,34 +4,47 @@
#pragma once
-#include "converters.h"
-
#include "events/eventloader.h"
#include "jobs/basejob.h"
namespace Quotient {
-// Operations
-
/*! \brief Get events and state around the specified event.
*
* This API returns a number of events that happened just before and
* after the specified event. This allows clients to get the context
* surrounding an event.
+ *
+ * *Note*: This endpoint supports lazy-loading of room member events. See
+ * `Lazy-loading room members <#lazy-loading-room-members>`_ for more
+ * information.
*/
class GetEventContextJob : public BaseJob {
public:
/*! \brief Get events and state around the specified event.
*
+ *
* \param roomId
* The room to get events from.
+ *
* \param eventId
* The event to get context around.
+ *
* \param limit
* The maximum number of events to return. Default: 10.
+ *
+ * \param filter
+ * A JSON ``RoomEventFilter`` to filter the returned events with. The
+ * filter is only applied to ``events_before``, ``events_after``, and
+ * ``state``. It is not applied to the ``event`` itself. The filter may
+ * be applied before or/and after the ``limit`` parameter - whichever the
+ * homeserver prefers.
+ *
+ * See `Filtering <#filtering>`_ for more information.
*/
explicit GetEventContextJob(const QString& roomId, const QString& eventId,
- Omittable<int> limit = none);
+ Omittable<int> limit = none,
+ const QString& filter = {});
/*! \brief Construct a URL without creating a full-fledged job object
*
@@ -40,37 +53,36 @@ public:
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId,
const QString& eventId,
- Omittable<int> limit = none);
- ~GetEventContextJob() override;
+ Omittable<int> limit = none,
+ const QString& filter = {});
// Result properties
/// A token that can be used to paginate backwards with.
- const QString& begin() const;
+ QString begin() const { return loadFromJson<QString>("start"_ls); }
/// A token that can be used to paginate forwards with.
- const QString& end() const;
+ QString end() const { return loadFromJson<QString>("end"_ls); }
/// A list of room events that happened just before the
/// requested event, in reverse-chronological order.
- RoomEvents&& eventsBefore();
+ RoomEvents eventsBefore()
+ {
+ return takeFromJson<RoomEvents>("events_before"_ls);
+ }
/// Details of the requested event.
- RoomEventPtr&& event();
+ RoomEventPtr event() { return takeFromJson<RoomEventPtr>("event"_ls); }
/// A list of room events that happened just after the
/// requested event, in chronological order.
- RoomEvents&& eventsAfter();
+ RoomEvents eventsAfter()
+ {
+ return takeFromJson<RoomEvents>("events_after"_ls);
+ }
/// The state of the room at the last event returned.
- StateEvents&& state();
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ StateEvents state() { return takeFromJson<StateEvents>("state"_ls); }
};
} // namespace Quotient
diff --git a/lib/csapi/filter.cpp b/lib/csapi/filter.cpp
index 98b85f83..bb3a893f 100644
--- a/lib/csapi/filter.cpp
+++ b/lib/csapi/filter.cpp
@@ -4,68 +4,29 @@
#include "filter.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-class DefineFilterJob::Private {
-public:
- QString filterId;
-};
-
DefineFilterJob::DefineFilterJob(const QString& userId, const Filter& filter)
: BaseJob(HttpVerb::Post, QStringLiteral("DefineFilterJob"),
- basePath % "/user/" % userId % "/filter")
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/user/" % userId
+ % "/filter")
{
setRequestData(Data(toJson(filter)));
+ addExpectedKey("filter_id");
}
-DefineFilterJob::~DefineFilterJob() = default;
-
-const QString& DefineFilterJob::filterId() const { return d->filterId; }
-
-BaseJob::Status DefineFilterJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- if (!json.contains("filter_id"_ls))
- return { IncorrectResponse,
- "The key 'filter_id' not found in the response" };
- fromJson(json.value("filter_id"_ls), d->filterId);
-
- return Success;
-}
-
-class GetFilterJob::Private {
-public:
- Filter data;
-};
-
QUrl GetFilterJob::makeRequestUrl(QUrl baseUrl, const QString& userId,
const QString& filterId)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/user/"
- % userId % "/filter/"
- % filterId);
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ QStringLiteral("/_matrix/client/r0") % "/user/"
+ % userId % "/filter/" % filterId);
}
GetFilterJob::GetFilterJob(const QString& userId, const QString& filterId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetFilterJob"),
- basePath % "/user/" % userId % "/filter/" % filterId)
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/user/" % userId
+ % "/filter/" % filterId)
{}
-
-GetFilterJob::~GetFilterJob() = default;
-
-const Filter& GetFilterJob::data() const { return d->data; }
-
-BaseJob::Status GetFilterJob::parseJson(const QJsonDocument& data)
-{
- fromJson(data, d->data);
-
- return Success;
-}
diff --git a/lib/csapi/filter.h b/lib/csapi/filter.h
index 7a0f8958..9aa7dc79 100644
--- a/lib/csapi/filter.h
+++ b/lib/csapi/filter.h
@@ -4,16 +4,12 @@
#pragma once
-#include "converters.h"
-
#include "csapi/definitions/sync_filter.h"
#include "jobs/basejob.h"
namespace Quotient {
-// Operations
-
/*! \brief Upload a new filter.
*
* Uploads a new filter definition to the homeserver.
@@ -24,30 +20,23 @@ class DefineFilterJob : public BaseJob {
public:
/*! \brief Upload a new filter.
*
+ *
* \param userId
* The id of the user uploading the filter. The access token must be
- * authorized to make requests for this user id. \param filter Uploads a new
- * filter definition to the homeserver. Returns a filter ID that may be used
- * in future requests to restrict which events are returned to the client.
+ * authorized to make requests for this user id.
+ *
+ * \param filter
+ * The filter to upload.
*/
explicit DefineFilterJob(const QString& userId, const Filter& filter);
- ~DefineFilterJob() override;
-
// Result properties
/// The ID of the filter that was created. Cannot start
/// with a ``{`` as this character is used to determine
/// if the filter provided is inline JSON or a previously
/// declared filter by homeservers on some APIs.
- const QString& filterId() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QString filterId() const { return loadFromJson<QString>("filter_id"_ls); }
};
/*! \brief Download a filter
@@ -57,8 +46,10 @@ class GetFilterJob : public BaseJob {
public:
/*! \brief Download a filter
*
+ *
* \param userId
* The user ID to download a filter for.
+ *
* \param filterId
* The filter ID to download.
*/
@@ -71,19 +62,11 @@ public:
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId,
const QString& filterId);
- ~GetFilterJob() override;
// Result properties
/// "The filter defintion"
- const Filter& data() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ Filter data() const { return fromJson<Filter>(jsonData()); }
};
} // namespace Quotient
diff --git a/lib/csapi/inviting.cpp b/lib/csapi/inviting.cpp
index f070c3ce..01620f9e 100644
--- a/lib/csapi/inviting.cpp
+++ b/lib/csapi/inviting.cpp
@@ -4,19 +4,16 @@
#include "inviting.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
InviteUserJob::InviteUserJob(const QString& roomId, const QString& userId)
: BaseJob(HttpVerb::Post, QStringLiteral("InviteUserJob"),
- basePath % "/rooms/" % roomId % "/invite")
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/invite")
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("user_id"), userId);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
diff --git a/lib/csapi/inviting.h b/lib/csapi/inviting.h
index 41d78ae6..a7ec6093 100644
--- a/lib/csapi/inviting.h
+++ b/lib/csapi/inviting.h
@@ -8,8 +8,6 @@
namespace Quotient {
-// Operations
-
/*! \brief Invite a user to participate in a particular room.
*
* .. _invite-by-user-id-endpoint:
@@ -35,8 +33,10 @@ class InviteUserJob : public BaseJob {
public:
/*! \brief Invite a user to participate in a particular room.
*
+ *
* \param roomId
* The room identifier (not alias) to which to invite the user.
+ *
* \param userId
* The fully qualified user ID of the invitee.
*/
diff --git a/lib/csapi/joining.cpp b/lib/csapi/joining.cpp
index cde179e0..4761e949 100644
--- a/lib/csapi/joining.cpp
+++ b/lib/csapi/joining.cpp
@@ -4,93 +4,23 @@
#include "joining.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-// Converters
-namespace Quotient {
-
-template <>
-struct JsonObjectConverter<JoinRoomByIdJob::ThirdPartySigned> {
- 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 Quotient
-
-class JoinRoomByIdJob::Private {
-public:
- QString roomId;
-};
-
JoinRoomByIdJob::JoinRoomByIdJob(
const QString& roomId, const Omittable<ThirdPartySigned>& thirdPartySigned)
: BaseJob(HttpVerb::Post, QStringLiteral("JoinRoomByIdJob"),
- basePath % "/rooms/" % roomId % "/join")
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId % "/join")
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("third_party_signed"),
thirdPartySigned);
- setRequestData(_data);
+ setRequestData(std::move(_data));
+ addExpectedKey("room_id");
}
-JoinRoomByIdJob::~JoinRoomByIdJob() = default;
-
-const QString& JoinRoomByIdJob::roomId() const { return d->roomId; }
-
-BaseJob::Status JoinRoomByIdJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- if (!json.contains("room_id"_ls))
- return { IncorrectResponse,
- "The key 'room_id' not found in the response" };
- fromJson(json.value("room_id"_ls), d->roomId);
-
- return Success;
-}
-
-// Converters
-namespace Quotient {
-
-template <>
-struct JsonObjectConverter<JoinRoomJob::Signed> {
- 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> {
- static void dumpTo(QJsonObject& jo, const JoinRoomJob::ThirdPartySigned& pod)
- {
- addParam<>(jo, QStringLiteral("signed"), pod.signedData);
- }
-};
-
-} // namespace Quotient
-
-class JoinRoomJob::Private {
-public:
- QString roomId;
-};
-
-BaseJob::Query queryToJoinRoom(const QStringList& serverName)
+auto queryToJoinRoom(const QStringList& serverName)
{
BaseJob::Query _q;
addParam<IfNotEmpty>(_q, QStringLiteral("server_name"), serverName);
@@ -101,26 +31,12 @@ JoinRoomJob::JoinRoomJob(const QString& roomIdOrAlias,
const QStringList& serverName,
const Omittable<ThirdPartySigned>& thirdPartySigned)
: BaseJob(HttpVerb::Post, QStringLiteral("JoinRoomJob"),
- basePath % "/join/" % roomIdOrAlias, queryToJoinRoom(serverName))
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/join/" % roomIdOrAlias,
+ queryToJoinRoom(serverName))
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("third_party_signed"),
thirdPartySigned);
- setRequestData(_data);
-}
-
-JoinRoomJob::~JoinRoomJob() = default;
-
-const QString& JoinRoomJob::roomId() const { return d->roomId; }
-
-BaseJob::Status JoinRoomJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- if (!json.contains("room_id"_ls))
- return { IncorrectResponse,
- "The key 'room_id' not found in the response" };
- fromJson(json.value("room_id"_ls), d->roomId);
-
- return Success;
+ setRequestData(std::move(_data));
+ addExpectedKey("room_id");
}
diff --git a/lib/csapi/joining.h b/lib/csapi/joining.h
index 6d93bcb1..6822fbdf 100644
--- a/lib/csapi/joining.h
+++ b/lib/csapi/joining.h
@@ -4,16 +4,12 @@
#pragma once
-#include "converters.h"
+#include "csapi/definitions/third_party_signed.h"
#include "jobs/basejob.h"
-#include <QtCore/QJsonObject>
-
namespace Quotient {
-// Operations
-
/*! \brief Start the requesting user participating in a particular room.
*
* *Note that this API requires a room ID, not alias.* ``/join/{roomIdOrAlias}``
@@ -33,49 +29,36 @@ namespace Quotient {
*/
class JoinRoomByIdJob : public BaseJob {
public:
- // Inner data structures
-
- /// A signature of an ``m.third_party_invite`` token to prove that this user
- /// owns a third party identity which has been invited to the room.
- struct ThirdPartySigned {
- /// The Matrix ID of the user who issued the invite.
- QString sender;
- /// The Matrix ID of the invitee.
- QString mxid;
- /// The state key of the m.third_party_invite event.
- QString token;
- /// A signatures object containing a signature of the entire signed
- /// object.
- QJsonObject signatures;
- };
-
- // Construction/destruction
-
/*! \brief Start the requesting user participating in a particular room.
*
+ *
* \param roomId
* The room identifier (not alias) to join.
+ *
* \param thirdPartySigned
- * A signature of an ``m.third_party_invite`` token to prove that this
- * user owns a third party identity which has been invited to the room.
+ * *Note that this API requires a room ID, not alias.*
+ * ``/join/{roomIdOrAlias}`` *exists if you have a room alias.*
+ *
+ * This API starts a user participating in a particular room, if that user
+ * is allowed to participate in that room. After this call, the client is
+ * allowed to see all current state events in the room, and all subsequent
+ * events associated with the room until the user leaves the room.
+ *
+ * After a user has joined a room, the room will appear as an entry in the
+ * response of the |/initialSync|_ and |/sync|_ APIs.
+ *
+ * If a ``third_party_signed`` was supplied, the homeserver must verify
+ * that it matches a pending ``m.room.third_party_invite`` event in the
+ * room, and perform key validity checking if required by the event.
*/
explicit JoinRoomByIdJob(
const QString& roomId,
const Omittable<ThirdPartySigned>& thirdPartySigned = none);
- ~JoinRoomByIdJob() override;
-
// Result properties
/// The joined room ID.
- const QString& roomId() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QString roomId() const { return loadFromJson<QString>("room_id"_ls); }
};
/*! \brief Start the requesting user participating in a particular room.
@@ -97,72 +80,40 @@ private:
*/
class JoinRoomJob : public BaseJob {
public:
- // Inner data structures
-
- /// *Note that this API takes either a room ID or alias, unlike*
- /// ``/room/{roomId}/join``.
- ///
- /// This API starts a user participating in a particular room, if that user
- /// is allowed to participate in that room. After this call, the client is
- /// allowed to see all current state events in the room, and all subsequent
- /// events associated with the room until the user leaves the room.
- ///
- /// After a user has joined a room, the room will appear as an entry in the
- /// response of the |/initialSync|_ and |/sync|_ APIs.
- ///
- /// If a ``third_party_signed`` was supplied, the homeserver must verify
- /// that it matches a pending ``m.room.third_party_invite`` event in the
- /// room, and perform key validity checking if required by the event.
- struct Signed {
- /// The Matrix ID of the user who issued the invite.
- QString sender;
- /// The Matrix ID of the invitee.
- QString mxid;
- /// The state key of the m.third_party_invite event.
- QString token;
- /// A signatures object containing a signature of the entire signed
- /// object.
- QJsonObject signatures;
- };
-
- /// A signature of an ``m.third_party_invite`` token to prove that this user
- /// owns a third party identity which has been invited to the room.
- struct ThirdPartySigned {
- /// A signature of an ``m.third_party_invite`` token to prove that this
- /// user owns a third party identity which has been invited to the room.
- Signed signedData;
- };
-
- // Construction/destruction
-
/*! \brief Start the requesting user participating in a particular room.
*
+ *
* \param roomIdOrAlias
* The room identifier or alias to join.
+ *
* \param serverName
* The servers to attempt to join the room through. One of the servers
* must be participating in the room.
+ *
* \param thirdPartySigned
- * A signature of an ``m.third_party_invite`` token to prove that this
- * user owns a third party identity which has been invited to the room.
+ * *Note that this API takes either a room ID or alias, unlike*
+ * ``/room/{roomId}/join``.
+ *
+ * This API starts a user participating in a particular room, if that user
+ * is allowed to participate in that room. After this call, the client is
+ * allowed to see all current state events in the room, and all subsequent
+ * events associated with the room until the user leaves the room.
+ *
+ * After a user has joined a room, the room will appear as an entry in the
+ * response of the |/initialSync|_ and |/sync|_ APIs.
+ *
+ * If a ``third_party_signed`` was supplied, the homeserver must verify
+ * that it matches a pending ``m.room.third_party_invite`` event in the
+ * room, and perform key validity checking if required by the event.
*/
explicit JoinRoomJob(
const QString& roomIdOrAlias, const QStringList& serverName = {},
const Omittable<ThirdPartySigned>& thirdPartySigned = none);
- ~JoinRoomJob() override;
-
// Result properties
/// The joined room ID.
- const QString& roomId() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QString roomId() const { return loadFromJson<QString>("room_id"_ls); }
};
} // namespace Quotient
diff --git a/lib/csapi/keys.cpp b/lib/csapi/keys.cpp
index b1a947b3..34ab47c9 100644
--- a/lib/csapi/keys.cpp
+++ b/lib/csapi/keys.cpp
@@ -4,161 +4,48 @@
#include "keys.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-class UploadKeysJob::Private {
-public:
- QHash<QString, int> oneTimeKeyCounts;
-};
-
UploadKeysJob::UploadKeysJob(const Omittable<DeviceKeys>& deviceKeys,
const QHash<QString, QVariant>& oneTimeKeys)
: BaseJob(HttpVerb::Post, QStringLiteral("UploadKeysJob"),
- basePath % "/keys/upload")
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/keys/upload")
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("device_keys"), deviceKeys);
addParam<IfNotEmpty>(_data, QStringLiteral("one_time_keys"), oneTimeKeys);
- setRequestData(_data);
-}
-
-UploadKeysJob::~UploadKeysJob() = default;
-
-const QHash<QString, int>& UploadKeysJob::oneTimeKeyCounts() const
-{
- return d->oneTimeKeyCounts;
-}
-
-BaseJob::Status UploadKeysJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- if (!json.contains("one_time_key_counts"_ls))
- return { IncorrectResponse,
- "The key 'one_time_key_counts' not found in the response" };
- fromJson(json.value("one_time_key_counts"_ls), d->oneTimeKeyCounts);
-
- return Success;
+ setRequestData(std::move(_data));
+ addExpectedKey("one_time_key_counts");
}
-// Converters
-namespace Quotient {
-
-template <>
-struct JsonObjectConverter<QueryKeysJob::UnsignedDeviceInfo> {
- static void fillFrom(const QJsonObject& jo,
- QueryKeysJob::UnsignedDeviceInfo& result)
- {
- fromJson(jo.value("device_display_name"_ls), result.deviceDisplayName);
- }
-};
-
-template <>
-struct JsonObjectConverter<QueryKeysJob::DeviceInformation> {
- static void fillFrom(const QJsonObject& jo,
- QueryKeysJob::DeviceInformation& result)
- {
- fillFromJson<DeviceKeys>(jo, result);
- fromJson(jo.value("unsigned"_ls), result.unsignedData);
- }
-};
-
-} // namespace Quotient
-
-class QueryKeysJob::Private {
-public:
- QHash<QString, QJsonObject> failures;
- QHash<QString, QHash<QString, DeviceInformation>> deviceKeys;
-};
-
QueryKeysJob::QueryKeysJob(const QHash<QString, QStringList>& deviceKeys,
Omittable<int> timeout, const QString& token)
: BaseJob(HttpVerb::Post, QStringLiteral("QueryKeysJob"),
- basePath % "/keys/query")
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/keys/query")
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("timeout"), timeout);
addParam<>(_data, QStringLiteral("device_keys"), deviceKeys);
addParam<IfNotEmpty>(_data, QStringLiteral("token"), token);
- setRequestData(_data);
-}
-
-QueryKeysJob::~QueryKeysJob() = default;
-
-const QHash<QString, QJsonObject>& QueryKeysJob::failures() const
-{
- return d->failures;
-}
-
-const QHash<QString, QHash<QString, QueryKeysJob::DeviceInformation>>&
-QueryKeysJob::deviceKeys() const
-{
- return d->deviceKeys;
+ setRequestData(std::move(_data));
}
-BaseJob::Status QueryKeysJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("failures"_ls), d->failures);
- fromJson(json.value("device_keys"_ls), d->deviceKeys);
-
- return Success;
-}
-
-class ClaimKeysJob::Private {
-public:
- QHash<QString, QJsonObject> failures;
- QHash<QString, QHash<QString, QVariant>> oneTimeKeys;
-};
-
ClaimKeysJob::ClaimKeysJob(
const QHash<QString, QHash<QString, QString>>& oneTimeKeys,
Omittable<int> timeout)
: BaseJob(HttpVerb::Post, QStringLiteral("ClaimKeysJob"),
- basePath % "/keys/claim")
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/keys/claim")
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("timeout"), timeout);
addParam<>(_data, QStringLiteral("one_time_keys"), oneTimeKeys);
- setRequestData(_data);
-}
-
-ClaimKeysJob::~ClaimKeysJob() = default;
-
-const QHash<QString, QJsonObject>& ClaimKeysJob::failures() const
-{
- return d->failures;
-}
-
-const QHash<QString, QHash<QString, QVariant>>& ClaimKeysJob::oneTimeKeys() const
-{
- return d->oneTimeKeys;
+ setRequestData(std::move(_data));
+ addExpectedKey("one_time_keys");
}
-BaseJob::Status ClaimKeysJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("failures"_ls), d->failures);
- fromJson(json.value("one_time_keys"_ls), d->oneTimeKeys);
-
- return Success;
-}
-
-class GetKeysChangesJob::Private {
-public:
- QStringList changed;
- QStringList left;
-};
-
-BaseJob::Query queryToGetKeysChanges(const QString& from, const QString& to)
+auto queryToGetKeysChanges(const QString& from, const QString& to)
{
BaseJob::Query _q;
addParam<>(_q, QStringLiteral("from"), from);
@@ -170,27 +57,13 @@ QUrl GetKeysChangesJob::makeRequestUrl(QUrl baseUrl, const QString& from,
const QString& to)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/keys/changes",
+ QStringLiteral("/_matrix/client/r0")
+ % "/keys/changes",
queryToGetKeysChanges(from, to));
}
GetKeysChangesJob::GetKeysChangesJob(const QString& from, const QString& to)
: BaseJob(HttpVerb::Get, QStringLiteral("GetKeysChangesJob"),
- basePath % "/keys/changes", queryToGetKeysChanges(from, to))
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/keys/changes",
+ queryToGetKeysChanges(from, to))
{}
-
-GetKeysChangesJob::~GetKeysChangesJob() = default;
-
-const QStringList& GetKeysChangesJob::changed() const { return d->changed; }
-
-const QStringList& GetKeysChangesJob::left() const { return d->left; }
-
-BaseJob::Status GetKeysChangesJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("changed"_ls), d->changed);
- fromJson(json.value("left"_ls), d->left);
-
- return Success;
-}
diff --git a/lib/csapi/keys.h b/lib/csapi/keys.h
index 2673acc5..b7a8dc71 100644
--- a/lib/csapi/keys.h
+++ b/lib/csapi/keys.h
@@ -4,20 +4,12 @@
#pragma once
-#include "converters.h"
-
#include "csapi/definitions/device_keys.h"
#include "jobs/basejob.h"
-#include <QtCore/QHash>
-#include <QtCore/QJsonObject>
-#include <QtCore/QVariant>
-
namespace Quotient {
-// Operations
-
/*! \brief Upload end-to-end encryption keys.
*
* Publishes end-to-end encryption keys for the device.
@@ -26,34 +18,30 @@ class UploadKeysJob : public BaseJob {
public:
/*! \brief Upload end-to-end encryption keys.
*
+ *
* \param deviceKeys
* Identity keys for the device. May be absent if no new
* identity keys are required.
+ *
* \param oneTimeKeys
* One-time public keys for "pre-key" messages. The names of
* the properties should be in the format
* ``<algorithm>:<key_id>``. The format of the key is determined
- * by the key algorithm.
+ * by the `key algorithm <#key-algorithms>`_.
*
* May be absent if no new one-time keys are required.
*/
explicit UploadKeysJob(const Omittable<DeviceKeys>& deviceKeys = none,
const QHash<QString, QVariant>& oneTimeKeys = {});
- ~UploadKeysJob() override;
-
// Result properties
/// For each key algorithm, the number of unclaimed one-time keys
/// of that type currently held on the server for this device.
- const QHash<QString, int>& oneTimeKeyCounts() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QHash<QString, int> oneTimeKeyCounts() const
+ {
+ return loadFromJson<QHash<QString, int>>("one_time_key_counts"_ls);
+ }
};
/*! \brief Download device identity keys.
@@ -73,7 +61,9 @@ public:
};
/// Returns the current devices and identity keys for the given users.
- struct DeviceInformation : DeviceKeys {
+ struct DeviceKeys :
+
+ Quotient::DeviceKeys {
/// Additional data added to the device key information
/// by intermediate servers, and not covered by the
/// signatures.
@@ -84,13 +74,16 @@ public:
/*! \brief Download device identity keys.
*
+ *
* \param deviceKeys
* The keys to be downloaded. A map from user ID, to a list of
* device IDs, or to an empty list to indicate all devices for the
* corresponding user.
+ *
* \param timeout
* The time (in milliseconds) to wait when downloading keys from
* remote servers. 10 seconds is the recommended default.
+ *
* \param token
* If the client is fetching keys as a result of a device update received
* in a sync request, this should be the 'since' token of that sync
@@ -101,8 +94,6 @@ public:
Omittable<int> timeout = none,
const QString& token = {});
- ~QueryKeysJob() override;
-
// Result properties
/// If any remote homeservers could not be reached, they are
@@ -112,21 +103,39 @@ public:
/// If the homeserver could be reached, but the user or device
/// was unknown, no failure is recorded. Instead, the corresponding
/// user or device is missing from the ``device_keys`` result.
- const QHash<QString, QJsonObject>& failures() const;
+ QHash<QString, QJsonObject> failures() const
+ {
+ return loadFromJson<QHash<QString, QJsonObject>>("failures"_ls);
+ }
/// Information on the queried devices. A map from user ID, to a
/// map from device ID to device information. For each device,
/// the information returned will be the same as uploaded via
/// ``/keys/upload``, with the addition of an ``unsigned``
/// property.
- const QHash<QString, QHash<QString, DeviceInformation>>& deviceKeys() const;
+ QHash<QString, QHash<QString, DeviceKeys>> deviceKeys() const
+ {
+ return loadFromJson<QHash<QString, QHash<QString, DeviceKeys>>>(
+ "device_keys"_ls);
+ }
+};
-protected:
- Status parseJson(const QJsonDocument& data) override;
+template <>
+struct JsonObjectConverter<QueryKeysJob::UnsignedDeviceInfo> {
+ static void fillFrom(const QJsonObject& jo,
+ QueryKeysJob::UnsignedDeviceInfo& result)
+ {
+ fromJson(jo.value("device_display_name"_ls), result.deviceDisplayName);
+ }
+};
-private:
- class Private;
- QScopedPointer<Private> d;
+template <>
+struct JsonObjectConverter<QueryKeysJob::DeviceKeys> {
+ static void fillFrom(const QJsonObject& jo, QueryKeysJob::DeviceKeys& result)
+ {
+ fillFromJson<DeviceKeys>(jo, result);
+ fromJson(jo.value("unsigned"_ls), result.unsignedData);
+ }
};
/*! \brief Claim one-time encryption keys.
@@ -137,9 +146,11 @@ class ClaimKeysJob : public BaseJob {
public:
/*! \brief Claim one-time encryption keys.
*
+ *
* \param oneTimeKeys
* The keys to be claimed. A map from user ID, to a map from
* device ID to algorithm name.
+ *
* \param timeout
* The time (in milliseconds) to wait when downloading keys from
* remote servers. 10 seconds is the recommended default.
@@ -148,8 +159,6 @@ public:
const QHash<QString, QHash<QString, QString>>& oneTimeKeys,
Omittable<int> timeout = none);
- ~ClaimKeysJob() override;
-
// Result properties
/// If any remote homeservers could not be reached, they are
@@ -159,18 +168,22 @@ public:
/// If the homeserver could be reached, but the user or device
/// was unknown, no failure is recorded. Instead, the corresponding
/// user or device is missing from the ``one_time_keys`` result.
- const QHash<QString, QJsonObject>& failures() const;
+ QHash<QString, QJsonObject> failures() const
+ {
+ return loadFromJson<QHash<QString, QJsonObject>>("failures"_ls);
+ }
/// One-time keys for the queried devices. A map from user ID, to a
- /// map from devices to a map from ``<algorithm>:<key_id>`` to the key object.
- const QHash<QString, QHash<QString, QVariant>>& oneTimeKeys() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ /// map from devices to a map from ``<algorithm>:<key_id>`` to the key
+ /// object.
+ ///
+ /// See the `key algorithms <#key-algorithms>`_ section for information
+ /// on the Key Object format.
+ QHash<QString, QHash<QString, QVariant>> oneTimeKeys() const
+ {
+ return loadFromJson<QHash<QString, QHash<QString, QVariant>>>(
+ "one_time_keys"_ls);
+ }
};
/*! \brief Query users with recent device key updates.
@@ -189,12 +202,14 @@ class GetKeysChangesJob : public BaseJob {
public:
/*! \brief Query users with recent device key updates.
*
+ *
* \param from
* The desired start point of the list. Should be the ``next_batch`` field
* from a response to an earlier call to |/sync|. Users who have not
* uploaded new device identity keys since this point, nor deleted
* existing devices with identity keys since then, will be excluded
* from the results.
+ *
* \param to
* The desired end point of the list. Should be the ``next_batch``
* field from a recent call to |/sync| - typically the most recent
@@ -210,25 +225,20 @@ public:
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& from,
const QString& to);
- ~GetKeysChangesJob() override;
// Result properties
/// The Matrix User IDs of all users who updated their device
/// identity keys.
- const QStringList& changed() const;
+ QStringList changed() const
+ {
+ return loadFromJson<QStringList>("changed"_ls);
+ }
/// The Matrix User IDs of all users who may have left all
/// the end-to-end encrypted rooms they previously shared
/// with the user.
- const QStringList& left() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QStringList left() const { return loadFromJson<QStringList>("left"_ls); }
};
} // namespace Quotient
diff --git a/lib/csapi/kicking.cpp b/lib/csapi/kicking.cpp
index 39125f42..7de5ce01 100644
--- a/lib/csapi/kicking.cpp
+++ b/lib/csapi/kicking.cpp
@@ -4,21 +4,17 @@
#include "kicking.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
KickJob::KickJob(const QString& roomId, const QString& userId,
const QString& reason)
: BaseJob(HttpVerb::Post, QStringLiteral("KickJob"),
- basePath % "/rooms/" % roomId % "/kick")
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId % "/kick")
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("user_id"), userId);
addParam<IfNotEmpty>(_data, QStringLiteral("reason"), reason);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
diff --git a/lib/csapi/kicking.h b/lib/csapi/kicking.h
index 0633a7f6..594f5845 100644
--- a/lib/csapi/kicking.h
+++ b/lib/csapi/kicking.h
@@ -8,8 +8,6 @@
namespace Quotient {
-// Operations
-
/*! \brief Kick a user from the room.
*
* Kick a user from the room.
@@ -26,10 +24,13 @@ class KickJob : public BaseJob {
public:
/*! \brief Kick a user from the room.
*
+ *
* \param roomId
* The room identifier (not alias) from which the user should be kicked.
+ *
* \param userId
* The fully qualified user ID of the user being kicked.
+ *
* \param reason
* The reason the user has been kicked. This will be supplied as the
* ``reason`` on the target's updated `m.room.member`_ event.
diff --git a/lib/csapi/leaving.cpp b/lib/csapi/leaving.cpp
index 2fa1da56..8bd170bf 100644
--- a/lib/csapi/leaving.cpp
+++ b/lib/csapi/leaving.cpp
@@ -4,32 +4,32 @@
#include "leaving.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
QUrl LeaveRoomJob::makeRequestUrl(QUrl baseUrl, const QString& roomId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/rooms/" % roomId % "/leave");
+ QStringLiteral("/_matrix/client/r0")
+ % "/rooms/" % roomId % "/leave");
}
LeaveRoomJob::LeaveRoomJob(const QString& roomId)
: BaseJob(HttpVerb::Post, QStringLiteral("LeaveRoomJob"),
- basePath % "/rooms/" % roomId % "/leave")
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/leave")
{}
QUrl ForgetRoomJob::makeRequestUrl(QUrl baseUrl, const QString& roomId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/rooms/" % roomId % "/forget");
+ QStringLiteral("/_matrix/client/r0")
+ % "/rooms/" % roomId % "/forget");
}
ForgetRoomJob::ForgetRoomJob(const QString& roomId)
: BaseJob(HttpVerb::Post, QStringLiteral("ForgetRoomJob"),
- basePath % "/rooms/" % roomId % "/forget")
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/forget")
{}
diff --git a/lib/csapi/leaving.h b/lib/csapi/leaving.h
index 45b983f3..0a4c401c 100644
--- a/lib/csapi/leaving.h
+++ b/lib/csapi/leaving.h
@@ -8,8 +8,6 @@
namespace Quotient {
-// Operations
-
/*! \brief Stop the requesting user participating in a particular room.
*
* This API stops a user participating in a particular room.
@@ -28,6 +26,7 @@ class LeaveRoomJob : public BaseJob {
public:
/*! \brief Stop the requesting user participating in a particular room.
*
+ *
* \param roomId
* The room identifier to leave.
*/
@@ -57,6 +56,7 @@ class ForgetRoomJob : public BaseJob {
public:
/*! \brief Stop the requesting user remembering about a particular room.
*
+ *
* \param roomId
* The room identifier to forget.
*/
diff --git a/lib/csapi/list_joined_rooms.cpp b/lib/csapi/list_joined_rooms.cpp
index 34eb0d42..8d7e267f 100644
--- a/lib/csapi/list_joined_rooms.cpp
+++ b/lib/csapi/list_joined_rooms.cpp
@@ -4,45 +4,20 @@
#include "list_joined_rooms.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-class GetJoinedRoomsJob::Private {
-public:
- QStringList joinedRooms;
-};
-
QUrl GetJoinedRoomsJob::makeRequestUrl(QUrl baseUrl)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/joined_rooms");
+ QStringLiteral("/_matrix/client/r0")
+ % "/joined_rooms");
}
GetJoinedRoomsJob::GetJoinedRoomsJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetJoinedRoomsJob"),
- basePath % "/joined_rooms")
- , d(new Private)
-{}
-
-GetJoinedRoomsJob::~GetJoinedRoomsJob() = default;
-
-const QStringList& GetJoinedRoomsJob::joinedRooms() const
+ QStringLiteral("/_matrix/client/r0") % "/joined_rooms")
{
- return d->joinedRooms;
-}
-
-BaseJob::Status GetJoinedRoomsJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- if (!json.contains("joined_rooms"_ls))
- return { IncorrectResponse,
- "The key 'joined_rooms' not found in the response" };
- fromJson(json.value("joined_rooms"_ls), d->joinedRooms);
-
- return Success;
+ addExpectedKey("joined_rooms");
}
diff --git a/lib/csapi/list_joined_rooms.h b/lib/csapi/list_joined_rooms.h
index a170d623..1034aa7b 100644
--- a/lib/csapi/list_joined_rooms.h
+++ b/lib/csapi/list_joined_rooms.h
@@ -8,8 +8,6 @@
namespace Quotient {
-// Operations
-
/*! \brief Lists the user's current rooms.
*
* This API returns a list of the user's current rooms.
@@ -25,19 +23,14 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl);
- ~GetJoinedRoomsJob() override;
// Result properties
/// The ID of each room in which the user has ``joined`` membership.
- const QStringList& joinedRooms() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QStringList joinedRooms() const
+ {
+ return loadFromJson<QStringList>("joined_rooms"_ls);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/list_public_rooms.cpp b/lib/csapi/list_public_rooms.cpp
index 83320ec0..cdc5c716 100644
--- a/lib/csapi/list_public_rooms.cpp
+++ b/lib/csapi/list_public_rooms.cpp
@@ -4,66 +4,39 @@
#include "list_public_rooms.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-class GetRoomVisibilityOnDirectoryJob::Private {
-public:
- QString visibility;
-};
-
QUrl GetRoomVisibilityOnDirectoryJob::makeRequestUrl(QUrl baseUrl,
const QString& roomId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/directory/list/room/" % roomId);
+ QStringLiteral("/_matrix/client/r0")
+ % "/directory/list/room/" % roomId);
}
GetRoomVisibilityOnDirectoryJob::GetRoomVisibilityOnDirectoryJob(
const QString& roomId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetRoomVisibilityOnDirectoryJob"),
- basePath % "/directory/list/room/" % roomId, false)
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/directory/list/room/"
+ % roomId,
+ false)
{}
-GetRoomVisibilityOnDirectoryJob::~GetRoomVisibilityOnDirectoryJob() = default;
-
-const QString& GetRoomVisibilityOnDirectoryJob::visibility() const
-{
- return d->visibility;
-}
-
-BaseJob::Status
-GetRoomVisibilityOnDirectoryJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("visibility"_ls), d->visibility);
-
- return Success;
-}
-
SetRoomVisibilityOnDirectoryJob::SetRoomVisibilityOnDirectoryJob(
const QString& roomId, const QString& visibility)
: BaseJob(HttpVerb::Put, QStringLiteral("SetRoomVisibilityOnDirectoryJob"),
- basePath % "/directory/list/room/" % roomId)
+ QStringLiteral("/_matrix/client/r0") % "/directory/list/room/"
+ % roomId)
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("visibility"), visibility);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
-class GetPublicRoomsJob::Private {
-public:
- PublicRoomsResponse data;
-};
-
-BaseJob::Query queryToGetPublicRooms(Omittable<int> limit, const QString& since,
- const QString& server)
+auto queryToGetPublicRooms(Omittable<int> limit, const QString& since,
+ const QString& server)
{
BaseJob::Query _q;
addParam<IfNotEmpty>(_q, QStringLiteral("limit"), limit);
@@ -76,49 +49,20 @@ QUrl GetPublicRoomsJob::makeRequestUrl(QUrl baseUrl, Omittable<int> limit,
const QString& since,
const QString& server)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/publicRooms",
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ QStringLiteral("/_matrix/client/r0")
+ % "/publicRooms",
queryToGetPublicRooms(limit, since, server));
}
GetPublicRoomsJob::GetPublicRoomsJob(Omittable<int> limit, const QString& since,
const QString& server)
: BaseJob(HttpVerb::Get, QStringLiteral("GetPublicRoomsJob"),
- basePath % "/publicRooms",
+ QStringLiteral("/_matrix/client/r0") % "/publicRooms",
queryToGetPublicRooms(limit, since, server), {}, false)
- , d(new Private)
{}
-GetPublicRoomsJob::~GetPublicRoomsJob() = default;
-
-const PublicRoomsResponse& GetPublicRoomsJob::data() const { return d->data; }
-
-BaseJob::Status GetPublicRoomsJob::parseJson(const QJsonDocument& data)
-{
- fromJson(data, d->data);
-
- return Success;
-}
-
-// Converters
-namespace Quotient {
-
-template <>
-struct JsonObjectConverter<QueryPublicRoomsJob::Filter> {
- static void dumpTo(QJsonObject& jo, const QueryPublicRoomsJob::Filter& pod)
- {
- addParam<IfNotEmpty>(jo, QStringLiteral("generic_search_term"),
- pod.genericSearchTerm);
- }
-};
-
-} // namespace Quotient
-
-class QueryPublicRoomsJob::Private {
-public:
- PublicRoomsResponse data;
-};
-
-BaseJob::Query queryToQueryPublicRooms(const QString& server)
+auto queryToQueryPublicRooms(const QString& server)
{
BaseJob::Query _q;
addParam<IfNotEmpty>(_q, QStringLiteral("server"), server);
@@ -132,8 +76,8 @@ QueryPublicRoomsJob::QueryPublicRoomsJob(const QString& server,
Omittable<bool> includeAllNetworks,
const QString& thirdPartyInstanceId)
: BaseJob(HttpVerb::Post, QStringLiteral("QueryPublicRoomsJob"),
- basePath % "/publicRooms", queryToQueryPublicRooms(server))
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/publicRooms",
+ queryToQueryPublicRooms(server))
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("limit"), limit);
@@ -143,16 +87,6 @@ QueryPublicRoomsJob::QueryPublicRoomsJob(const QString& server,
includeAllNetworks);
addParam<IfNotEmpty>(_data, QStringLiteral("third_party_instance_id"),
thirdPartyInstanceId);
- setRequestData(_data);
-}
-
-QueryPublicRoomsJob::~QueryPublicRoomsJob() = default;
-
-const PublicRoomsResponse& QueryPublicRoomsJob::data() const { return d->data; }
-
-BaseJob::Status QueryPublicRoomsJob::parseJson(const QJsonDocument& data)
-{
- fromJson(data, d->data);
-
- return Success;
+ setRequestData(std::move(_data));
+ addExpectedKey("chunk");
}
diff --git a/lib/csapi/list_public_rooms.h b/lib/csapi/list_public_rooms.h
index 0c9a2620..5ef7c23e 100644
--- a/lib/csapi/list_public_rooms.h
+++ b/lib/csapi/list_public_rooms.h
@@ -4,16 +4,12 @@
#pragma once
-#include "converters.h"
-
#include "csapi/definitions/public_rooms_response.h"
#include "jobs/basejob.h"
namespace Quotient {
-// Operations
-
/*! \brief Gets the visibility of a room in the directory
*
* Gets the visibility of a given room on the server's public room directory.
@@ -22,6 +18,7 @@ class GetRoomVisibilityOnDirectoryJob : public BaseJob {
public:
/*! \brief Gets the visibility of a room in the directory
*
+ *
* \param roomId
* The room ID.
*/
@@ -33,19 +30,14 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId);
- ~GetRoomVisibilityOnDirectoryJob() override;
// Result properties
/// The visibility of the room in the directory.
- const QString& visibility() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QString visibility() const
+ {
+ return loadFromJson<QString>("visibility"_ls);
+ }
};
/*! \brief Sets the visibility of a room in the room directory
@@ -61,8 +53,10 @@ class SetRoomVisibilityOnDirectoryJob : public BaseJob {
public:
/*! \brief Sets the visibility of a room in the room directory
*
+ *
* \param roomId
* The room ID.
+ *
* \param visibility
* The new visibility setting for the room.
* Defaults to 'public'.
@@ -82,13 +76,16 @@ class GetPublicRoomsJob : public BaseJob {
public:
/*! \brief Lists the public rooms on the server.
*
+ *
* \param limit
* Limit the number of results returned.
+ *
* \param since
* A pagination token from a previous request, allowing clients to
* get the next (or previous) batch of rooms.
* The direction of pagination is specified solely by which token
* is supplied, rather than via an explicit flag.
+ *
* \param server
* The server to fetch the public room lists from. Defaults to the
* local server.
@@ -105,19 +102,14 @@ public:
static QUrl makeRequestUrl(QUrl baseUrl, Omittable<int> limit = none,
const QString& since = {},
const QString& server = {});
- ~GetPublicRoomsJob() override;
// Result properties
/// A list of the rooms on the server.
- const PublicRoomsResponse& data() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ PublicRoomsResponse data() const
+ {
+ return fromJson<PublicRoomsResponse>(jsonData());
+ }
};
/*! \brief Lists the public rooms on the server with optional filter.
@@ -138,25 +130,58 @@ public:
QString genericSearchTerm;
};
+ /// Lists the public rooms on the server, with optional filter.
+ ///
+ /// This API returns paginated responses. The rooms are ordered by the
+ /// number of joined members, with the largest rooms first.
+ struct PublicRoomsChunk {
+ /// Aliases of the room. May be empty.
+ QStringList aliases;
+ /// The canonical alias of the room, if any.
+ QString canonicalAlias;
+ /// The name of the room, if any.
+ QString name;
+ /// The number of members joined to the room.
+ int numJoinedMembers;
+ /// The ID of the room.
+ QString roomId;
+ /// The topic of the room, if any.
+ QString topic;
+ /// Whether the room may be viewed by guest users without joining.
+ bool worldReadable;
+ /// Whether guest users may join the room and participate in it.
+ /// If they can, they will be subject to ordinary power level
+ /// rules like any other user.
+ bool guestCanJoin;
+ /// The URL for the room's avatar, if one is set.
+ QString avatarUrl;
+ };
+
// Construction/destruction
/*! \brief Lists the public rooms on the server with optional filter.
*
+ *
* \param server
* The server to fetch the public room lists from. Defaults to the
* local server.
+ *
* \param limit
* Limit the number of results returned.
+ *
* \param since
* A pagination token from a previous request, allowing clients
* to get the next (or previous) batch of rooms. The direction
* of pagination is specified solely by which token is supplied,
* rather than via an explicit flag.
+ *
* \param filter
* Filter to apply to the results.
+ *
* \param includeAllNetworks
* Whether or not to include all known networks/protocols from
* application services on the homeserver. Defaults to false.
+ *
* \param thirdPartyInstanceId
* The specific third party network/protocol to request from the
* homeserver. Can only be used if ``include_all_networks`` is false.
@@ -168,19 +193,56 @@ public:
Omittable<bool> includeAllNetworks = none,
const QString& thirdPartyInstanceId = {});
- ~QueryPublicRoomsJob() override;
-
// Result properties
- /// A list of the rooms on the server.
- const PublicRoomsResponse& data() const;
+ /// A paginated chunk of public rooms.
+ QVector<PublicRoomsChunk> chunk() const
+ {
+ return loadFromJson<QVector<PublicRoomsChunk>>("chunk"_ls);
+ }
+
+ /// A pagination token for the response. The absence of this token
+ /// means there are no more results to fetch and the client should
+ /// stop paginating.
+ QString nextBatch() const { return loadFromJson<QString>("next_batch"_ls); }
+
+ /// A pagination token that allows fetching previous results. The
+ /// absence of this token means there are no results before this
+ /// batch, i.e. this is the first batch.
+ QString prevBatch() const { return loadFromJson<QString>("prev_batch"_ls); }
+
+ /// An estimate on the total number of public rooms, if the
+ /// server has an estimate.
+ Omittable<int> totalRoomCountEstimate() const
+ {
+ return loadFromJson<Omittable<int>>("total_room_count_estimate"_ls);
+ }
+};
-protected:
- Status parseJson(const QJsonDocument& data) override;
+template <>
+struct JsonObjectConverter<QueryPublicRoomsJob::Filter> {
+ static void dumpTo(QJsonObject& jo, const QueryPublicRoomsJob::Filter& pod)
+ {
+ addParam<IfNotEmpty>(jo, QStringLiteral("generic_search_term"),
+ pod.genericSearchTerm);
+ }
+};
-private:
- class Private;
- QScopedPointer<Private> d;
+template <>
+struct JsonObjectConverter<QueryPublicRoomsJob::PublicRoomsChunk> {
+ static void fillFrom(const QJsonObject& jo,
+ QueryPublicRoomsJob::PublicRoomsChunk& 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);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/login.cpp b/lib/csapi/login.cpp
index 3e98f56b..a5bac9ea 100644
--- a/lib/csapi/login.cpp
+++ b/lib/csapi/login.cpp
@@ -4,77 +4,29 @@
#include "login.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-// Converters
-namespace Quotient {
-
-template <>
-struct JsonObjectConverter<GetLoginFlowsJob::LoginFlow> {
- static void fillFrom(const QJsonObject& jo,
- GetLoginFlowsJob::LoginFlow& result)
- {
- fromJson(jo.value("type"_ls), result.type);
- }
-};
-
-} // namespace Quotient
-
-class GetLoginFlowsJob::Private {
-public:
- QVector<LoginFlow> flows;
-};
-
QUrl GetLoginFlowsJob::makeRequestUrl(QUrl baseUrl)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/login");
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ QStringLiteral("/_matrix/client/r0")
+ % "/login");
}
GetLoginFlowsJob::GetLoginFlowsJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetLoginFlowsJob"),
- basePath % "/login", false)
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/login", false)
{}
-GetLoginFlowsJob::~GetLoginFlowsJob() = default;
-
-const QVector<GetLoginFlowsJob::LoginFlow>& GetLoginFlowsJob::flows() const
-{
- return d->flows;
-}
-
-BaseJob::Status GetLoginFlowsJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("flows"_ls), d->flows);
-
- return Success;
-}
-
-class LoginJob::Private {
-public:
- QString userId;
- QString accessToken;
- QString homeServer;
- QString deviceId;
- Omittable<DiscoveryInformation> wellKnown;
-};
-
LoginJob::LoginJob(const QString& type,
const Omittable<UserIdentifier>& identifier,
const QString& password, const QString& token,
const QString& deviceId,
- const QString& initialDeviceDisplayName, const QString& user,
- const QString& medium, const QString& address)
- : BaseJob(HttpVerb::Post, QStringLiteral("LoginJob"), basePath % "/login",
- false)
- , d(new Private)
+ const QString& initialDeviceDisplayName)
+ : BaseJob(HttpVerb::Post, QStringLiteral("LoginJob"),
+ QStringLiteral("/_matrix/client/r0") % "/login", false)
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("type"), type);
@@ -84,35 +36,5 @@ LoginJob::LoginJob(const QString& type,
addParam<IfNotEmpty>(_data, QStringLiteral("device_id"), deviceId);
addParam<IfNotEmpty>(_data, QStringLiteral("initial_device_display_name"),
initialDeviceDisplayName);
- addParam<IfNotEmpty>(_data, QStringLiteral("user"), user);
- addParam<IfNotEmpty>(_data, QStringLiteral("medium"), medium);
- addParam<IfNotEmpty>(_data, QStringLiteral("address"), address);
- setRequestData(_data);
-}
-
-LoginJob::~LoginJob() = default;
-
-const QString& LoginJob::userId() const { return d->userId; }
-
-const QString& LoginJob::accessToken() const { return d->accessToken; }
-
-const QString& LoginJob::homeServer() const { return d->homeServer; }
-
-const QString& LoginJob::deviceId() const { return d->deviceId; }
-
-const Omittable<DiscoveryInformation>& LoginJob::wellKnown() const
-{
- return d->wellKnown;
-}
-
-BaseJob::Status LoginJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- 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);
- fromJson(json.value("well_known"_ls), d->wellKnown);
-
- return Success;
+ setRequestData(std::move(_data));
}
diff --git a/lib/csapi/login.h b/lib/csapi/login.h
index adecca6f..0483b77c 100644
--- a/lib/csapi/login.h
+++ b/lib/csapi/login.h
@@ -4,19 +4,13 @@
#pragma once
-#include "converters.h"
-
#include "csapi/definitions/user_identifier.h"
#include "csapi/definitions/wellknown/full.h"
#include "jobs/basejob.h"
-#include <QtCore/QVector>
-
namespace Quotient {
-// Operations
-
/*! \brief Get the supported login types to authenticate users
*
* Gets the homeserver's supported login types to authenticate users. Clients
@@ -46,19 +40,23 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl);
- ~GetLoginFlowsJob() override;
// Result properties
/// The homeserver's supported login types
- const QVector<LoginFlow>& flows() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
+ QVector<LoginFlow> flows() const
+ {
+ return loadFromJson<QVector<LoginFlow>>("flows"_ls);
+ }
+};
-private:
- class Private;
- QScopedPointer<Private> d;
+template <>
+struct JsonObjectConverter<GetLoginFlowsJob::LoginFlow> {
+ static void fillFrom(const QJsonObject& jo,
+ GetLoginFlowsJob::LoginFlow& result)
+ {
+ fromJson(jo.value("type"_ls), result.type);
+ }
};
/*! \brief Authenticates the user.
@@ -78,45 +76,47 @@ class LoginJob : public BaseJob {
public:
/*! \brief Authenticates the user.
*
+ *
* \param type
* The login type being used.
+ *
* \param identifier
* Identification information for the user.
+ *
* \param password
* Required when ``type`` is ``m.login.password``. The user's
* password.
+ *
* \param token
* Required when ``type`` is ``m.login.token``. Part of `Token-based`_
- * login. \param deviceId ID of the client device. If this does not
- * correspond to a known client device, a new device will be created. The
- * server will auto-generate a device_id if this is not specified. \param
- * initialDeviceDisplayName A display name to assign to the newly-created
- * device. Ignored if ``device_id`` corresponds to a known device. \param
- * user The fully qualified user ID or just local part of the user ID, to
- * log in. Deprecated in favour of ``identifier``. \param medium When
- * logging in using a third party identifier, the medium of the identifier.
- * Must be 'email'. Deprecated in favour of ``identifier``. \param address
- * Third party identifier for the user. Deprecated in favour of
- * ``identifier``.
+ * login.
+ *
+ * \param deviceId
+ * ID of the client device. If this does not correspond to a
+ * known client device, a new device will be created. The server
+ * will auto-generate a device_id if this is not specified.
+ *
+ * \param initialDeviceDisplayName
+ * A display name to assign to the newly-created device. Ignored
+ * if ``device_id`` corresponds to a known device.
*/
explicit LoginJob(const QString& type,
const Omittable<UserIdentifier>& identifier = none,
const QString& password = {}, const QString& token = {},
const QString& deviceId = {},
- const QString& initialDeviceDisplayName = {},
- const QString& user = {}, const QString& medium = {},
- const QString& address = {});
-
- ~LoginJob() override;
+ const QString& initialDeviceDisplayName = {});
// Result properties
/// The fully-qualified Matrix ID that has been registered.
- const QString& userId() const;
+ QString userId() const { return loadFromJson<QString>("user_id"_ls); }
/// An access token for the account.
/// This access token can then be used to authorize other requests.
- const QString& accessToken() const;
+ QString accessToken() const
+ {
+ return loadFromJson<QString>("access_token"_ls);
+ }
/// The server_name of the homeserver on which the account has
/// been registered.
@@ -124,24 +124,23 @@ public:
/// **Deprecated**. Clients should extract the server_name from
/// ``user_id`` (by splitting at the first colon) if they require
/// it. Note also that ``homeserver`` is not spelt this way.
- const QString& homeServer() const;
+ QString homeServer() const
+ {
+ return loadFromJson<QString>("home_server"_ls);
+ }
/// ID of the logged-in device. Will be the same as the
/// corresponding parameter in the request, if one was specified.
- const QString& deviceId() const;
+ QString deviceId() const { return loadFromJson<QString>("device_id"_ls); }
/// Optional client configuration provided by the server. If present,
/// clients SHOULD use the provided object to reconfigure themselves,
/// optionally validating the URLs within. This object takes the same
/// form as the one returned from .well-known autodiscovery.
- const Omittable<DiscoveryInformation>& wellKnown() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ Omittable<DiscoveryInformation> wellKnown() const
+ {
+ return loadFromJson<Omittable<DiscoveryInformation>>("well_known"_ls);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/logout.cpp b/lib/csapi/logout.cpp
index 36281b79..9583b8ec 100644
--- a/lib/csapi/logout.cpp
+++ b/lib/csapi/logout.cpp
@@ -4,29 +4,30 @@
#include "logout.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
QUrl LogoutJob::makeRequestUrl(QUrl baseUrl)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/logout");
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ QStringLiteral("/_matrix/client/r0")
+ % "/logout");
}
LogoutJob::LogoutJob()
- : BaseJob(HttpVerb::Post, QStringLiteral("LogoutJob"), basePath % "/logout")
+ : BaseJob(HttpVerb::Post, QStringLiteral("LogoutJob"),
+ QStringLiteral("/_matrix/client/r0") % "/logout")
{}
QUrl LogoutAllJob::makeRequestUrl(QUrl baseUrl)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/logout/all");
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ QStringLiteral("/_matrix/client/r0")
+ % "/logout/all");
}
LogoutAllJob::LogoutAllJob()
: BaseJob(HttpVerb::Post, QStringLiteral("LogoutAllJob"),
- basePath % "/logout/all")
+ QStringLiteral("/_matrix/client/r0") % "/logout/all")
{}
diff --git a/lib/csapi/logout.h b/lib/csapi/logout.h
index 2a705620..e9a7ef89 100644
--- a/lib/csapi/logout.h
+++ b/lib/csapi/logout.h
@@ -8,12 +8,11 @@
namespace Quotient {
-// Operations
-
/*! \brief Invalidates a user access token
*
* Invalidates an existing access token, so that it can no longer be used for
- * authorization.
+ * authorization. The device associated with the access token is also deleted.
+ * `Device keys <#device-keys>`_ for the device are deleted alongside the device.
*/
class LogoutJob : public BaseJob {
public:
@@ -31,7 +30,9 @@ public:
/*! \brief Invalidates all access tokens for a user
*
* Invalidates all access tokens for a user, so that they can no longer be used
- * for authorization. This includes the access token that made this request.
+ * for authorization. This includes the access token that made this request. All
+ * devices for the user are also deleted. `Device keys <#device-keys>`_ for the
+ * device are deleted alongside the device.
*
* This endpoint does not require UI authorization because UI authorization is
* designed to protect against attacks where the someone gets hold of a single
diff --git a/lib/csapi/message_pagination.cpp b/lib/csapi/message_pagination.cpp
index ba982748..855c051f 100644
--- a/lib/csapi/message_pagination.cpp
+++ b/lib/csapi/message_pagination.cpp
@@ -4,24 +4,13 @@
#include "message_pagination.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-class GetRoomEventsJob::Private {
-public:
- QString begin;
- QString end;
- RoomEvents chunk;
-};
-
-BaseJob::Query queryToGetRoomEvents(const QString& from, const QString& to,
- const QString& dir, Omittable<int> limit,
- const QString& filter)
+auto queryToGetRoomEvents(const QString& from, const QString& to,
+ const QString& dir, Omittable<int> limit,
+ const QString& filter)
{
BaseJob::Query _q;
addParam<>(_q, QStringLiteral("from"), from);
@@ -37,35 +26,17 @@ QUrl GetRoomEventsJob::makeRequestUrl(QUrl baseUrl, const QString& roomId,
const QString& to, Omittable<int> limit,
const QString& filter)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/rooms/" % roomId % "/messages",
- queryToGetRoomEvents(from, to, dir, limit,
- filter));
+ return BaseJob::makeRequestUrl(
+ std::move(baseUrl),
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId % "/messages",
+ queryToGetRoomEvents(from, to, dir, limit, filter));
}
GetRoomEventsJob::GetRoomEventsJob(const QString& roomId, const QString& from,
const QString& dir, const QString& to,
Omittable<int> limit, const QString& filter)
: BaseJob(HttpVerb::Get, QStringLiteral("GetRoomEventsJob"),
- basePath % "/rooms/" % roomId % "/messages",
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/messages",
queryToGetRoomEvents(from, to, dir, limit, filter))
- , d(new Private)
{}
-
-GetRoomEventsJob::~GetRoomEventsJob() = default;
-
-const QString& GetRoomEventsJob::begin() const { return d->begin; }
-
-const QString& GetRoomEventsJob::end() const { return d->end; }
-
-RoomEvents&& GetRoomEventsJob::chunk() { return std::move(d->chunk); }
-
-BaseJob::Status GetRoomEventsJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- 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/message_pagination.h b/lib/csapi/message_pagination.h
index b0d95bad..e9f9e6d4 100644
--- a/lib/csapi/message_pagination.h
+++ b/lib/csapi/message_pagination.h
@@ -4,40 +4,46 @@
#pragma once
-#include "converters.h"
-
#include "events/eventloader.h"
#include "jobs/basejob.h"
namespace Quotient {
-// Operations
-
/*! \brief Get a list of events for this room
*
* This API returns a list of message and state events for a room. It uses
* pagination query parameters to paginate history in the room.
+ *
+ * *Note*: This endpoint supports lazy-loading of room member events. See
+ * `Lazy-loading room members <#lazy-loading-room-members>`_ for more
+ * information.
*/
class GetRoomEventsJob : public BaseJob {
public:
/*! \brief Get a list of events for this room
*
+ *
* \param roomId
* The room to get events from.
+ *
* \param from
* The token to start returning events from. This token can be obtained
* from a ``prev_batch`` token returned for each room by the sync API,
* or from a ``start`` or ``end`` token returned by a previous request
* to this endpoint.
+ *
* \param dir
* The direction to return events from.
+ *
* \param to
* The token to stop returning events at. This token can be obtained from
* a ``prev_batch`` token returned for each room by the sync endpoint,
* or from a ``start`` or ``end`` token returned by a previous request to
* this endpoint.
+ *
* \param limit
* The maximum number of events to return. Default: 10.
+ *
* \param filter
* A JSON RoomEventFilter to filter returned events with.
*/
@@ -56,27 +62,32 @@ public:
const QString& to = {},
Omittable<int> limit = none,
const QString& filter = {});
- ~GetRoomEventsJob() override;
// Result properties
/// The token the pagination starts from. If ``dir=b`` this will be
/// the token supplied in ``from``.
- const QString& begin() const;
+ QString begin() const { return loadFromJson<QString>("start"_ls); }
/// The token the pagination ends at. If ``dir=b`` this token should
/// be used again to request even earlier events.
- const QString& end() const;
-
- /// A list of room events.
- RoomEvents&& chunk();
+ QString end() const { return loadFromJson<QString>("end"_ls); }
-protected:
- Status parseJson(const QJsonDocument& data) override;
+ /// A list of room events. The order depends on the ``dir`` parameter.
+ /// For ``dir=b`` events will be in reverse-chronological order,
+ /// for ``dir=f`` in chronological order, so that events start
+ /// at the ``from`` point.
+ RoomEvents chunk() { return takeFromJson<RoomEvents>("chunk"_ls); }
-private:
- class Private;
- QScopedPointer<Private> d;
+ /// A list of state events relevant to showing the ``chunk``. For example, if
+ /// ``lazy_load_members`` is enabled in the filter then this may contain
+ /// the membership events for the senders of events in the ``chunk``.
+ ///
+ /// Unless ``include_redundant_members`` is ``true``, the server
+ /// may remove membership events which would have already been
+ /// sent to the client in prior calls to this endpoint, assuming
+ /// the membership of those members has not changed.
+ StateEvents state() { return takeFromJson<StateEvents>("state"_ls); }
};
} // namespace Quotient
diff --git a/lib/csapi/notifications.cpp b/lib/csapi/notifications.cpp
index d00d5425..a479d500 100644
--- a/lib/csapi/notifications.cpp
+++ b/lib/csapi/notifications.cpp
@@ -4,41 +4,12 @@
#include "notifications.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-// Converters
-namespace Quotient {
-
-template <>
-struct JsonObjectConverter<GetNotificationsJob::Notification> {
- static void fillFrom(const QJsonObject& jo,
- GetNotificationsJob::Notification& 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 Quotient
-
-class GetNotificationsJob::Private {
-public:
- QString nextToken;
- std::vector<Notification> notifications;
-};
-
-BaseJob::Query queryToGetNotifications(const QString& from,
- Omittable<int> limit, const QString& only)
+auto queryToGetNotifications(const QString& from, Omittable<int> limit,
+ const QString& only)
{
BaseJob::Query _q;
addParam<IfNotEmpty>(_q, QStringLiteral("from"), from);
@@ -52,7 +23,8 @@ QUrl GetNotificationsJob::makeRequestUrl(QUrl baseUrl, const QString& from,
const QString& only)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/notifications",
+ QStringLiteral("/_matrix/client/r0")
+ % "/notifications",
queryToGetNotifications(from, limit, only));
}
@@ -60,29 +32,8 @@ GetNotificationsJob::GetNotificationsJob(const QString& from,
Omittable<int> limit,
const QString& only)
: BaseJob(HttpVerb::Get, QStringLiteral("GetNotificationsJob"),
- basePath % "/notifications",
+ QStringLiteral("/_matrix/client/r0") % "/notifications",
queryToGetNotifications(from, limit, only))
- , d(new Private)
-{}
-
-GetNotificationsJob::~GetNotificationsJob() = default;
-
-const QString& GetNotificationsJob::nextToken() const { return d->nextToken; }
-
-std::vector<GetNotificationsJob::Notification>&&
-GetNotificationsJob::notifications()
-{
- return std::move(d->notifications);
-}
-
-BaseJob::Status GetNotificationsJob::parseJson(const QJsonDocument& data)
{
- auto json = data.object();
- fromJson(json.value("next_token"_ls), d->nextToken);
- if (!json.contains("notifications"_ls))
- return { IncorrectResponse,
- "The key 'notifications' not found in the response" };
- fromJson(json.value("notifications"_ls), d->notifications);
-
- return Success;
+ addExpectedKey("notifications");
}
diff --git a/lib/csapi/notifications.h b/lib/csapi/notifications.h
index 0e86e424..095e9325 100644
--- a/lib/csapi/notifications.h
+++ b/lib/csapi/notifications.h
@@ -4,19 +4,11 @@
#pragma once
-#include "converters.h"
-
#include "events/eventloader.h"
#include "jobs/basejob.h"
-#include <QtCore/QJsonObject>
-#include <QtCore/QVariant>
-#include <QtCore/QVector>
-
namespace Quotient {
-// Operations
-
/*! \brief Gets a list of events that the user has been notified about
*
* This API is used to paginate through the list of events that the
@@ -50,10 +42,13 @@ public:
/*! \brief Gets a list of events that the user has been notified about
*
+ *
* \param from
* Pagination token given to retrieve the next set of events.
+ *
* \param limit
* Limit on the number of events to return in this request.
+ *
* \param only
* Allows basic filtering of events returned. Supply ``highlight``
* to return only events where the notification had the highlight
@@ -71,24 +66,33 @@ public:
static QUrl makeRequestUrl(QUrl baseUrl, const QString& from = {},
Omittable<int> limit = none,
const QString& only = {});
- ~GetNotificationsJob() override;
// Result properties
/// The token to supply in the ``from`` param of the next
/// ``/notifications`` request in order to request more
/// events. If this is absent, there are no more results.
- const QString& nextToken() const;
+ QString nextToken() const { return loadFromJson<QString>("next_token"_ls); }
/// The list of events that triggered notifications.
- std::vector<Notification>&& notifications();
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
+ std::vector<Notification> notifications()
+ {
+ return takeFromJson<std::vector<Notification>>("notifications"_ls);
+ }
+};
-private:
- class Private;
- QScopedPointer<Private> d;
+template <>
+struct JsonObjectConverter<GetNotificationsJob::Notification> {
+ static void fillFrom(const QJsonObject& jo,
+ GetNotificationsJob::Notification& 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 Quotient
diff --git a/lib/csapi/openid.cpp b/lib/csapi/openid.cpp
index 9def2377..3941e9c0 100644
--- a/lib/csapi/openid.cpp
+++ b/lib/csapi/openid.cpp
@@ -4,66 +4,15 @@
#include "openid.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-class RequestOpenIdTokenJob::Private {
-public:
- QString accessToken;
- QString tokenType;
- QString matrixServerName;
- int expiresIn;
-};
-
RequestOpenIdTokenJob::RequestOpenIdTokenJob(const QString& userId,
const QJsonObject& body)
: BaseJob(HttpVerb::Post, QStringLiteral("RequestOpenIdTokenJob"),
- basePath % "/user/" % userId % "/openid/request_token")
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/user/" % userId
+ % "/openid/request_token")
{
setRequestData(Data(toJson(body)));
}
-
-RequestOpenIdTokenJob::~RequestOpenIdTokenJob() = default;
-
-const QString& RequestOpenIdTokenJob::accessToken() const
-{
- return d->accessToken;
-}
-
-const QString& RequestOpenIdTokenJob::tokenType() const { return d->tokenType; }
-
-const QString& RequestOpenIdTokenJob::matrixServerName() const
-{
- return d->matrixServerName;
-}
-
-int RequestOpenIdTokenJob::expiresIn() const { return d->expiresIn; }
-
-BaseJob::Status RequestOpenIdTokenJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- if (!json.contains("access_token"_ls))
- return { IncorrectResponse,
- "The key 'access_token' not found in the response" };
- fromJson(json.value("access_token"_ls), d->accessToken);
- if (!json.contains("token_type"_ls))
- return { IncorrectResponse,
- "The key 'token_type' not found in the response" };
- fromJson(json.value("token_type"_ls), d->tokenType);
- if (!json.contains("matrix_server_name"_ls))
- return { IncorrectResponse,
- "The key 'matrix_server_name' not found in the response" };
- fromJson(json.value("matrix_server_name"_ls), d->matrixServerName);
- if (!json.contains("expires_in"_ls))
- return { IncorrectResponse,
- "The key 'expires_in' not found in the response" };
- fromJson(json.value("expires_in"_ls), d->expiresIn);
-
- return Success;
-}
diff --git a/lib/csapi/openid.h b/lib/csapi/openid.h
index bda4ce74..e69f9ad0 100644
--- a/lib/csapi/openid.h
+++ b/lib/csapi/openid.h
@@ -4,16 +4,12 @@
#pragma once
-#include "converters.h"
+#include "csapi/definitions/openid_token.h"
#include "jobs/basejob.h"
-#include <QtCore/QJsonObject>
-
namespace Quotient {
-// Operations
-
/*! \brief Get an OpenID token object to verify the requester's identity.
*
* Gets an OpenID token object that the requester may supply to another
@@ -29,41 +25,25 @@ class RequestOpenIdTokenJob : public BaseJob {
public:
/*! \brief Get an OpenID token object to verify the requester's identity.
*
+ *
* \param userId
* The user to request and OpenID token for. Should be the user who
* is authenticated for the request.
+ *
* \param body
* An empty object. Reserved for future expansion.
*/
explicit RequestOpenIdTokenJob(const QString& userId,
const QJsonObject& body = {});
- ~RequestOpenIdTokenJob() override;
-
// Result properties
- /// An access token the consumer may use to verify the identity of
- /// the person who generated the token. This is given to the federation
- /// API ``GET /openid/userinfo``.
- const QString& accessToken() const;
-
- /// The string ``Bearer``.
- const QString& tokenType() const;
-
- /// The homeserver domain the consumer should use when attempting to
- /// verify the user's identity.
- const QString& matrixServerName() const;
-
- /// The number of seconds before this token expires and a new one must
- /// be generated.
- int expiresIn() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ /// OpenID token information. This response is nearly compatible with the
+ /// response documented in the `OpenID 1.0 Specification
+ /// <http://openid.net/specs/openid-connect-core-1_0.html#TokenResponse>`_
+ /// with the only difference being the lack of an ``id_token``. Instead,
+ /// the Matrix homeserver's name is provided.
+ OpenidToken data() const { return fromJson<OpenidToken>(jsonData()); }
};
} // namespace Quotient
diff --git a/lib/csapi/peeking_events.cpp b/lib/csapi/peeking_events.cpp
index 4d886812..70a5b6f3 100644
--- a/lib/csapi/peeking_events.cpp
+++ b/lib/csapi/peeking_events.cpp
@@ -4,23 +4,12 @@
#include "peeking_events.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-class PeekEventsJob::Private {
-public:
- QString begin;
- QString end;
- RoomEvents chunk;
-};
-
-BaseJob::Query queryToPeekEvents(const QString& from, Omittable<int> timeout,
- const QString& roomId)
+auto queryToPeekEvents(const QString& from, Omittable<int> timeout,
+ const QString& roomId)
{
BaseJob::Query _q;
addParam<IfNotEmpty>(_q, QStringLiteral("from"), from);
@@ -32,31 +21,15 @@ BaseJob::Query queryToPeekEvents(const QString& from, Omittable<int> timeout,
QUrl PeekEventsJob::makeRequestUrl(QUrl baseUrl, const QString& from,
Omittable<int> timeout, const QString& roomId)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/events",
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ QStringLiteral("/_matrix/client/r0")
+ % "/events",
queryToPeekEvents(from, timeout, roomId));
}
PeekEventsJob::PeekEventsJob(const QString& from, Omittable<int> timeout,
const QString& roomId)
: BaseJob(HttpVerb::Get, QStringLiteral("PeekEventsJob"),
- basePath % "/events", queryToPeekEvents(from, timeout, roomId))
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/events",
+ queryToPeekEvents(from, timeout, roomId))
{}
-
-PeekEventsJob::~PeekEventsJob() = default;
-
-const QString& PeekEventsJob::begin() const { return d->begin; }
-
-const QString& PeekEventsJob::end() const { return d->end; }
-
-RoomEvents&& PeekEventsJob::chunk() { return std::move(d->chunk); }
-
-BaseJob::Status PeekEventsJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- 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/peeking_events.h b/lib/csapi/peeking_events.h
index 12a66a02..bfb9e24a 100644
--- a/lib/csapi/peeking_events.h
+++ b/lib/csapi/peeking_events.h
@@ -4,15 +4,11 @@
#pragma once
-#include "converters.h"
-
#include "events/eventloader.h"
#include "jobs/basejob.h"
namespace Quotient {
-// Operations
-
/*! \brief Listen on the event stream.
*
* This will listen for new events related to a particular room and return
@@ -30,11 +26,14 @@ class PeekEventsJob : public BaseJob {
public:
/*! \brief Listen on the event stream.
*
+ *
* \param from
* The token to stream from. This token is either from a previous
* request to this API or from the initial sync API.
+ *
* \param timeout
* The maximum time in milliseconds to wait for an event.
+ *
* \param roomId
* The room ID for which events should be returned.
*/
@@ -50,27 +49,19 @@ public:
static QUrl makeRequestUrl(QUrl baseUrl, const QString& from = {},
Omittable<int> timeout = none,
const QString& roomId = {});
- ~PeekEventsJob() override;
// Result properties
/// A token which correlates to the first value in ``chunk``. This
/// is usually the same token supplied to ``from=``.
- const QString& begin() const;
+ QString begin() const { return loadFromJson<QString>("start"_ls); }
/// A token which correlates to the last value in ``chunk``. This
/// token should be used in the next request to ``/events``.
- const QString& end() const;
+ QString end() const { return loadFromJson<QString>("end"_ls); }
/// An array of events.
- RoomEvents&& chunk();
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ RoomEvents chunk() { return takeFromJson<RoomEvents>("chunk"_ls); }
};
} // namespace Quotient
diff --git a/lib/csapi/presence.cpp b/lib/csapi/presence.cpp
index 932ccc6e..58d0d157 100644
--- a/lib/csapi/presence.cpp
+++ b/lib/csapi/presence.cpp
@@ -4,71 +4,33 @@
#include "presence.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
SetPresenceJob::SetPresenceJob(const QString& userId, const QString& presence,
const QString& statusMsg)
: BaseJob(HttpVerb::Put, QStringLiteral("SetPresenceJob"),
- basePath % "/presence/" % userId % "/status")
+ QStringLiteral("/_matrix/client/r0") % "/presence/" % userId
+ % "/status")
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("presence"), presence);
addParam<IfNotEmpty>(_data, QStringLiteral("status_msg"), statusMsg);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
-class GetPresenceJob::Private {
-public:
- QString presence;
- Omittable<int> lastActiveAgo;
- QString statusMsg;
- Omittable<bool> currentlyActive;
-};
-
QUrl GetPresenceJob::makeRequestUrl(QUrl baseUrl, const QString& userId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/presence/" % userId % "/status");
+ QStringLiteral("/_matrix/client/r0")
+ % "/presence/" % userId % "/status");
}
GetPresenceJob::GetPresenceJob(const QString& userId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetPresenceJob"),
- basePath % "/presence/" % userId % "/status")
- , d(new Private)
-{}
-
-GetPresenceJob::~GetPresenceJob() = default;
-
-const QString& GetPresenceJob::presence() const { return d->presence; }
-
-Omittable<int> GetPresenceJob::lastActiveAgo() const
-{
- return d->lastActiveAgo;
-}
-
-const QString& GetPresenceJob::statusMsg() const { return d->statusMsg; }
-
-Omittable<bool> GetPresenceJob::currentlyActive() const
+ QStringLiteral("/_matrix/client/r0") % "/presence/" % userId
+ % "/status")
{
- return d->currentlyActive;
-}
-
-BaseJob::Status GetPresenceJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- if (!json.contains("presence"_ls))
- return { IncorrectResponse,
- "The key 'presence' not found in the response" };
- 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;
+ addExpectedKey("presence");
}
diff --git a/lib/csapi/presence.h b/lib/csapi/presence.h
index 21e57603..b34028e7 100644
--- a/lib/csapi/presence.h
+++ b/lib/csapi/presence.h
@@ -4,14 +4,10 @@
#pragma once
-#include "converters.h"
-
#include "jobs/basejob.h"
namespace Quotient {
-// Operations
-
/*! \brief Update this user's presence state.
*
* This API sets the given user's presence state. When setting the status,
@@ -23,10 +19,13 @@ class SetPresenceJob : public BaseJob {
public:
/*! \brief Update this user's presence state.
*
+ *
* \param userId
* The user whose presence state to update.
+ *
* \param presence
* The new presence state.
+ *
* \param statusMsg
* The status message to attach to this state.
*/
@@ -42,6 +41,7 @@ class GetPresenceJob : public BaseJob {
public:
/*! \brief Get this user's presence state.
*
+ *
* \param userId
* The user whose presence state to get.
*/
@@ -53,29 +53,27 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId);
- ~GetPresenceJob() override;
// Result properties
/// This user's presence.
- const QString& presence() const;
+ QString presence() const { return loadFromJson<QString>("presence"_ls); }
/// The length of time in milliseconds since an action was performed
/// by this user.
- Omittable<int> lastActiveAgo() const;
+ Omittable<int> lastActiveAgo() const
+ {
+ return loadFromJson<Omittable<int>>("last_active_ago"_ls);
+ }
/// The state message for this user if one was set.
- const QString& statusMsg() const;
+ QString statusMsg() const { return loadFromJson<QString>("status_msg"_ls); }
/// Whether the user is currently active
- Omittable<bool> currentlyActive() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ Omittable<bool> currentlyActive() const
+ {
+ return loadFromJson<Omittable<bool>>("currently_active"_ls);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/profile.cpp b/lib/csapi/profile.cpp
index d86e3bdc..cb8f72be 100644
--- a/lib/csapi/profile.cpp
+++ b/lib/csapi/profile.cpp
@@ -4,122 +4,67 @@
#include "profile.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
SetDisplayNameJob::SetDisplayNameJob(const QString& userId,
const QString& displayname)
: BaseJob(HttpVerb::Put, QStringLiteral("SetDisplayNameJob"),
- basePath % "/profile/" % userId % "/displayname")
+ QStringLiteral("/_matrix/client/r0") % "/profile/" % userId
+ % "/displayname")
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("displayname"), displayname);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
-class GetDisplayNameJob::Private {
-public:
- QString displayname;
-};
-
QUrl GetDisplayNameJob::makeRequestUrl(QUrl baseUrl, const QString& userId)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/profile/"
- % userId
- % "/displayname");
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ QStringLiteral("/_matrix/client/r0")
+ % "/profile/" % userId % "/displayname");
}
GetDisplayNameJob::GetDisplayNameJob(const QString& userId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetDisplayNameJob"),
- basePath % "/profile/" % userId % "/displayname", false)
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/profile/" % userId
+ % "/displayname",
+ false)
{}
-GetDisplayNameJob::~GetDisplayNameJob() = default;
-
-const QString& GetDisplayNameJob::displayname() const { return d->displayname; }
-
-BaseJob::Status GetDisplayNameJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("displayname"_ls), d->displayname);
-
- return Success;
-}
-
SetAvatarUrlJob::SetAvatarUrlJob(const QString& userId, const QString& avatarUrl)
: BaseJob(HttpVerb::Put, QStringLiteral("SetAvatarUrlJob"),
- basePath % "/profile/" % userId % "/avatar_url")
+ QStringLiteral("/_matrix/client/r0") % "/profile/" % userId
+ % "/avatar_url")
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("avatar_url"), avatarUrl);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
-class GetAvatarUrlJob::Private {
-public:
- QString avatarUrl;
-};
-
QUrl GetAvatarUrlJob::makeRequestUrl(QUrl baseUrl, const QString& userId)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/profile/"
- % userId
- % "/avatar_url");
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ QStringLiteral("/_matrix/client/r0")
+ % "/profile/" % userId % "/avatar_url");
}
GetAvatarUrlJob::GetAvatarUrlJob(const QString& userId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetAvatarUrlJob"),
- basePath % "/profile/" % userId % "/avatar_url", false)
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/profile/" % userId
+ % "/avatar_url",
+ false)
{}
-GetAvatarUrlJob::~GetAvatarUrlJob() = default;
-
-const QString& GetAvatarUrlJob::avatarUrl() const { return d->avatarUrl; }
-
-BaseJob::Status GetAvatarUrlJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("avatar_url"_ls), d->avatarUrl);
-
- return Success;
-}
-
-class GetUserProfileJob::Private {
-public:
- QString avatarUrl;
- QString displayname;
-};
-
QUrl GetUserProfileJob::makeRequestUrl(QUrl baseUrl, const QString& userId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/profile/" % userId);
+ QStringLiteral("/_matrix/client/r0")
+ % "/profile/" % userId);
}
GetUserProfileJob::GetUserProfileJob(const QString& userId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetUserProfileJob"),
- basePath % "/profile/" % userId, false)
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/profile/" % userId, false)
{}
-
-GetUserProfileJob::~GetUserProfileJob() = default;
-
-const QString& GetUserProfileJob::avatarUrl() const { return d->avatarUrl; }
-
-const QString& GetUserProfileJob::displayname() const { return d->displayname; }
-
-BaseJob::Status GetUserProfileJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("avatar_url"_ls), d->avatarUrl);
- fromJson(json.value("displayname"_ls), d->displayname);
-
- return Success;
-}
diff --git a/lib/csapi/profile.h b/lib/csapi/profile.h
index 8279fe20..5b0d06d9 100644
--- a/lib/csapi/profile.h
+++ b/lib/csapi/profile.h
@@ -8,8 +8,6 @@
namespace Quotient {
-// Operations
-
/*! \brief Set the user's display name.
*
* This API sets the given user's display name. You must have permission to
@@ -19,8 +17,10 @@ class SetDisplayNameJob : public BaseJob {
public:
/*! \brief Set the user's display name.
*
+ *
* \param userId
* The user whose display name to set.
+ *
* \param displayname
* The new display name for this user.
*/
@@ -38,6 +38,7 @@ class GetDisplayNameJob : public BaseJob {
public:
/*! \brief Get the user's display name.
*
+ *
* \param userId
* The user whose display name to get.
*/
@@ -49,19 +50,14 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId);
- ~GetDisplayNameJob() override;
// Result properties
/// The user's display name if they have set one, otherwise not present.
- const QString& displayname() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QString displayname() const
+ {
+ return loadFromJson<QString>("displayname"_ls);
+ }
};
/*! \brief Set the user's avatar URL.
@@ -73,8 +69,10 @@ class SetAvatarUrlJob : public BaseJob {
public:
/*! \brief Set the user's avatar URL.
*
+ *
* \param userId
* The user whose avatar URL to set.
+ *
* \param avatarUrl
* The new avatar URL for this user.
*/
@@ -92,6 +90,7 @@ class GetAvatarUrlJob : public BaseJob {
public:
/*! \brief Get the user's avatar URL.
*
+ *
* \param userId
* The user whose avatar URL to get.
*/
@@ -103,19 +102,11 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId);
- ~GetAvatarUrlJob() override;
// Result properties
/// The user's avatar URL if they have set one, otherwise not present.
- const QString& avatarUrl() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QString avatarUrl() const { return loadFromJson<QString>("avatar_url"_ls); }
};
/*! \brief Get this user's profile information.
@@ -129,6 +120,7 @@ class GetUserProfileJob : public BaseJob {
public:
/*! \brief Get this user's profile information.
*
+ *
* \param userId
* The user whose profile information to get.
*/
@@ -140,22 +132,17 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId);
- ~GetUserProfileJob() override;
// Result properties
/// The user's avatar URL if they have set one, otherwise not present.
- const QString& avatarUrl() const;
+ QString avatarUrl() const { return loadFromJson<QString>("avatar_url"_ls); }
/// The user's display name if they have set one, otherwise not present.
- const QString& displayname() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QString displayname() const
+ {
+ return loadFromJson<QString>("displayname"_ls);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/pusher.cpp b/lib/csapi/pusher.cpp
index ad51b901..028022c5 100644
--- a/lib/csapi/pusher.cpp
+++ b/lib/csapi/pusher.cpp
@@ -4,96 +4,29 @@
#include "pusher.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-// Converters
-namespace Quotient {
-
-template <>
-struct JsonObjectConverter<GetPushersJob::PusherData> {
- static void fillFrom(const QJsonObject& jo,
- GetPushersJob::PusherData& result)
- {
- fromJson(jo.value("url"_ls), result.url);
- fromJson(jo.value("format"_ls), result.format);
- }
-};
-
-template <>
-struct JsonObjectConverter<GetPushersJob::Pusher> {
- static void fillFrom(const QJsonObject& jo, GetPushersJob::Pusher& 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 Quotient
-
-class GetPushersJob::Private {
-public:
- QVector<Pusher> pushers;
-};
-
QUrl GetPushersJob::makeRequestUrl(QUrl baseUrl)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/pushers");
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ QStringLiteral("/_matrix/client/r0")
+ % "/pushers");
}
GetPushersJob::GetPushersJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetPushersJob"),
- basePath % "/pushers")
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/pushers")
{}
-GetPushersJob::~GetPushersJob() = default;
-
-const QVector<GetPushersJob::Pusher>& GetPushersJob::pushers() const
-{
- return d->pushers;
-}
-
-BaseJob::Status GetPushersJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("pushers"_ls), d->pushers);
-
- return Success;
-}
-
-// Converters
-namespace Quotient {
-
-template <>
-struct JsonObjectConverter<PostPusherJob::PusherData> {
- static void dumpTo(QJsonObject& jo, const PostPusherJob::PusherData& pod)
- {
- addParam<IfNotEmpty>(jo, QStringLiteral("url"), pod.url);
- addParam<IfNotEmpty>(jo, QStringLiteral("format"), pod.format);
- }
-};
-
-} // namespace Quotient
-
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, QStringLiteral("PostPusherJob"),
- basePath % "/pushers/set")
+ QStringLiteral("/_matrix/client/r0") % "/pushers/set")
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("pushkey"), pushkey);
@@ -105,5 +38,5 @@ PostPusherJob::PostPusherJob(const QString& pushkey, const QString& kind,
addParam<>(_data, QStringLiteral("lang"), lang);
addParam<>(_data, QStringLiteral("data"), data);
addParam<IfNotEmpty>(_data, QStringLiteral("append"), append);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
diff --git a/lib/csapi/pusher.h b/lib/csapi/pusher.h
index d60a2b56..40cd5796 100644
--- a/lib/csapi/pusher.h
+++ b/lib/csapi/pusher.h
@@ -4,16 +4,10 @@
#pragma once
-#include "converters.h"
-
#include "jobs/basejob.h"
-#include <QtCore/QVector>
-
namespace Quotient {
-// Operations
-
/*! \brief Gets the current pushers for the authenticated user
*
* Gets all currently active pushers for the authenticated user.
@@ -73,19 +67,39 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl);
- ~GetPushersJob() override;
// Result properties
/// An array containing the current pushers for the user
- const QVector<Pusher>& pushers() const;
+ QVector<Pusher> pushers() const
+ {
+ return loadFromJson<QVector<Pusher>>("pushers"_ls);
+ }
+};
-protected:
- Status parseJson(const QJsonDocument& data) override;
+template <>
+struct JsonObjectConverter<GetPushersJob::PusherData> {
+ static void fillFrom(const QJsonObject& jo,
+ GetPushersJob::PusherData& result)
+ {
+ fromJson(jo.value("url"_ls), result.url);
+ fromJson(jo.value("format"_ls), result.format);
+ }
+};
-private:
- class Private;
- QScopedPointer<Private> d;
+template <>
+struct JsonObjectConverter<GetPushersJob::Pusher> {
+ static void fillFrom(const QJsonObject& jo, GetPushersJob::Pusher& 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);
+ }
};
/*! \brief Modify a pusher for this user on the homeserver.
@@ -118,6 +132,7 @@ public:
/*! \brief Modify a pusher for this user on the homeserver.
*
+ *
* \param pushkey
* This is a unique identifier for this pusher. The value you
* should use for this is the routing or destination address
@@ -128,10 +143,12 @@ public:
*
* If the ``kind`` is ``"email"``, this is the email address to
* send notifications to.
+ *
* \param kind
* The kind of pusher to configure. ``"http"`` makes a pusher that
* sends HTTP pokes. ``"email"`` makes a pusher that emails the
* user with unread notifications. ``null`` deletes the pusher.
+ *
* \param appId
* This is a reverse-DNS style identifier for the application.
* It is recommended that this end with the platform, such that
@@ -139,22 +156,28 @@ public:
* Max length, 64 chars.
*
* If the ``kind`` is ``"email"``, this is ``"m.email"``.
+ *
* \param appDisplayName
* A string that will allow the user to identify what application
* owns this pusher.
+ *
* \param deviceDisplayName
* A string that will allow the user to identify what device owns
* this pusher.
+ *
* \param lang
* The preferred language for receiving notifications (e.g. 'en'
* or 'en-US').
+ *
* \param data
* A dictionary of information for the pusher implementation
* itself. If ``kind`` is ``http``, this should contain ``url``
* which is the URL to use to send notifications to.
+ *
* \param profileTag
* This string determines which set of device specific rules this
* pusher executes.
+ *
* \param append
* If true, the homeserver should add another pusher with the
* given pushkey and App ID in addition to any others with
@@ -170,4 +193,13 @@ public:
Omittable<bool> append = none);
};
+template <>
+struct JsonObjectConverter<PostPusherJob::PusherData> {
+ static void dumpTo(QJsonObject& jo, const PostPusherJob::PusherData& pod)
+ {
+ addParam<IfNotEmpty>(jo, QStringLiteral("url"), pod.url);
+ addParam<IfNotEmpty>(jo, QStringLiteral("format"), pod.format);
+ }
+};
+
} // namespace Quotient
diff --git a/lib/csapi/pushrules.cpp b/lib/csapi/pushrules.cpp
index cd0fb02d..f2a16f1b 100644
--- a/lib/csapi/pushrules.cpp
+++ b/lib/csapi/pushrules.cpp
@@ -4,92 +4,58 @@
#include "pushrules.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-class GetPushRulesJob::Private {
-public:
- PushRuleset global;
-};
-
QUrl GetPushRulesJob::makeRequestUrl(QUrl baseUrl)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/pushrules");
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ QStringLiteral("/_matrix/client/r0")
+ % "/pushrules");
}
GetPushRulesJob::GetPushRulesJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetPushRulesJob"),
- basePath % "/pushrules")
- , d(new Private)
-{}
-
-GetPushRulesJob::~GetPushRulesJob() = default;
-
-const PushRuleset& GetPushRulesJob::global() const { return d->global; }
-
-BaseJob::Status GetPushRulesJob::parseJson(const QJsonDocument& data)
+ QStringLiteral("/_matrix/client/r0") % "/pushrules")
{
- auto json = data.object();
- if (!json.contains("global"_ls))
- return { IncorrectResponse,
- "The key 'global' not found in the response" };
- fromJson(json.value("global"_ls), d->global);
-
- return Success;
+ addExpectedKey("global");
}
-class GetPushRuleJob::Private {
-public:
- PushRule data;
-};
-
QUrl GetPushRuleJob::makeRequestUrl(QUrl baseUrl, const QString& scope,
const QString& kind, const QString& ruleId)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/pushrules/"
- % scope % "/" % kind
- % "/" % ruleId);
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ QStringLiteral("/_matrix/client/r0")
+ % "/pushrules/" % scope % "/" % kind
+ % "/" % ruleId);
}
GetPushRuleJob::GetPushRuleJob(const QString& scope, const QString& kind,
const QString& ruleId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetPushRuleJob"),
- basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId)
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/pushrules/" % scope % "/"
+ % kind % "/" % ruleId)
{}
-GetPushRuleJob::~GetPushRuleJob() = default;
-
-const PushRule& GetPushRuleJob::data() const { return d->data; }
-
-BaseJob::Status GetPushRuleJob::parseJson(const QJsonDocument& data)
-{
- fromJson(data, d->data);
-
- return Success;
-}
-
QUrl DeletePushRuleJob::makeRequestUrl(QUrl baseUrl, const QString& scope,
const QString& kind,
const QString& ruleId)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/pushrules/"
- % scope % "/" % kind
- % "/" % ruleId);
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ QStringLiteral("/_matrix/client/r0")
+ % "/pushrules/" % scope % "/" % kind
+ % "/" % ruleId);
}
DeletePushRuleJob::DeletePushRuleJob(const QString& scope, const QString& kind,
const QString& ruleId)
: BaseJob(HttpVerb::Delete, QStringLiteral("DeletePushRuleJob"),
- basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId)
+ QStringLiteral("/_matrix/client/r0") % "/pushrules/" % scope % "/"
+ % kind % "/" % ruleId)
{}
-BaseJob::Query queryToSetPushRule(const QString& before, const QString& after)
+auto queryToSetPushRule(const QString& before, const QString& after)
{
BaseJob::Query _q;
addParam<IfNotEmpty>(_q, QStringLiteral("before"), before);
@@ -103,27 +69,24 @@ SetPushRuleJob::SetPushRuleJob(const QString& scope, const QString& kind,
const QVector<PushCondition>& conditions,
const QString& pattern)
: BaseJob(HttpVerb::Put, QStringLiteral("SetPushRuleJob"),
- basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId,
+ QStringLiteral("/_matrix/client/r0") % "/pushrules/" % scope % "/"
+ % kind % "/" % ruleId,
queryToSetPushRule(before, after))
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("actions"), actions);
addParam<IfNotEmpty>(_data, QStringLiteral("conditions"), conditions);
addParam<IfNotEmpty>(_data, QStringLiteral("pattern"), pattern);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
-class IsPushRuleEnabledJob::Private {
-public:
- bool enabled;
-};
-
QUrl IsPushRuleEnabledJob::makeRequestUrl(QUrl baseUrl, const QString& scope,
const QString& kind,
const QString& ruleId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/pushrules/" % scope % "/" % kind
+ QStringLiteral("/_matrix/client/r0")
+ % "/pushrules/" % scope % "/" % kind
% "/" % ruleId % "/enabled");
}
@@ -131,49 +94,31 @@ IsPushRuleEnabledJob::IsPushRuleEnabledJob(const QString& scope,
const QString& kind,
const QString& ruleId)
: BaseJob(HttpVerb::Get, QStringLiteral("IsPushRuleEnabledJob"),
- basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId
- % "/enabled")
- , d(new Private)
-{}
-
-IsPushRuleEnabledJob::~IsPushRuleEnabledJob() = default;
-
-bool IsPushRuleEnabledJob::enabled() const { return d->enabled; }
-
-BaseJob::Status IsPushRuleEnabledJob::parseJson(const QJsonDocument& data)
+ QStringLiteral("/_matrix/client/r0") % "/pushrules/" % scope % "/"
+ % kind % "/" % ruleId % "/enabled")
{
- auto json = data.object();
- if (!json.contains("enabled"_ls))
- return { IncorrectResponse,
- "The key 'enabled' not found in the response" };
- fromJson(json.value("enabled"_ls), d->enabled);
-
- return Success;
+ addExpectedKey("enabled");
}
SetPushRuleEnabledJob::SetPushRuleEnabledJob(const QString& scope,
const QString& kind,
const QString& ruleId, bool enabled)
: BaseJob(HttpVerb::Put, QStringLiteral("SetPushRuleEnabledJob"),
- basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId
- % "/enabled")
+ QStringLiteral("/_matrix/client/r0") % "/pushrules/" % scope % "/"
+ % kind % "/" % ruleId % "/enabled")
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("enabled"), enabled);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
-class GetPushRuleActionsJob::Private {
-public:
- QStringList actions;
-};
-
QUrl GetPushRuleActionsJob::makeRequestUrl(QUrl baseUrl, const QString& scope,
const QString& kind,
const QString& ruleId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/pushrules/" % scope % "/" % kind
+ QStringLiteral("/_matrix/client/r0")
+ % "/pushrules/" % scope % "/" % kind
% "/" % ruleId % "/actions");
}
@@ -181,24 +126,10 @@ GetPushRuleActionsJob::GetPushRuleActionsJob(const QString& scope,
const QString& kind,
const QString& ruleId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetPushRuleActionsJob"),
- basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId
- % "/actions")
- , d(new Private)
-{}
-
-GetPushRuleActionsJob::~GetPushRuleActionsJob() = default;
-
-const QStringList& GetPushRuleActionsJob::actions() const { return d->actions; }
-
-BaseJob::Status GetPushRuleActionsJob::parseJson(const QJsonDocument& data)
+ QStringLiteral("/_matrix/client/r0") % "/pushrules/" % scope % "/"
+ % kind % "/" % ruleId % "/actions")
{
- auto json = data.object();
- if (!json.contains("actions"_ls))
- return { IncorrectResponse,
- "The key 'actions' not found in the response" };
- fromJson(json.value("actions"_ls), d->actions);
-
- return Success;
+ addExpectedKey("actions");
}
SetPushRuleActionsJob::SetPushRuleActionsJob(const QString& scope,
@@ -206,10 +137,10 @@ SetPushRuleActionsJob::SetPushRuleActionsJob(const QString& scope,
const QString& ruleId,
const QStringList& actions)
: BaseJob(HttpVerb::Put, QStringLiteral("SetPushRuleActionsJob"),
- basePath % "/pushrules/" % scope % "/" % kind % "/" % ruleId
- % "/actions")
+ QStringLiteral("/_matrix/client/r0") % "/pushrules/" % scope % "/"
+ % kind % "/" % ruleId % "/actions")
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("actions"), actions);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
diff --git a/lib/csapi/pushrules.h b/lib/csapi/pushrules.h
index a9169151..0971dc6b 100644
--- a/lib/csapi/pushrules.h
+++ b/lib/csapi/pushrules.h
@@ -4,20 +4,14 @@
#pragma once
-#include "converters.h"
-
#include "csapi/definitions/push_condition.h"
#include "csapi/definitions/push_rule.h"
#include "csapi/definitions/push_ruleset.h"
#include "jobs/basejob.h"
-#include <QtCore/QVector>
-
namespace Quotient {
-// Operations
-
/*! \brief Retrieve all push rulesets.
*
* Retrieve all push rulesets for this user. Clients can "drill-down" on
@@ -36,19 +30,14 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl);
- ~GetPushRulesJob() override;
// Result properties
/// The global ruleset.
- const PushRuleset& global() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ PushRuleset global() const
+ {
+ return loadFromJson<PushRuleset>("global"_ls);
+ }
};
/*! \brief Retrieve a push rule.
@@ -59,10 +48,13 @@ class GetPushRuleJob : public BaseJob {
public:
/*! \brief Retrieve a push rule.
*
+ *
* \param scope
* ``global`` to specify global rules.
+ *
* \param kind
* The kind of rule
+ *
* \param ruleId
* The identifier for the rule.
*/
@@ -76,19 +68,12 @@ public:
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& scope,
const QString& kind, const QString& ruleId);
- ~GetPushRuleJob() override;
// Result properties
- /// The push rule.
- const PushRule& data() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ /// The specific push rule. This will also include keys specific to the
+ /// rule itself such as the rule's ``actions`` and ``conditions`` if set.
+ PushRule data() const { return fromJson<PushRule>(jsonData()); }
};
/*! \brief Delete a push rule.
@@ -99,10 +84,13 @@ class DeletePushRuleJob : public BaseJob {
public:
/*! \brief Delete a push rule.
*
+ *
* \param scope
* ``global`` to specify global rules.
+ *
* \param kind
* The kind of rule
+ *
* \param ruleId
* The identifier for the rule.
*/
@@ -130,28 +118,37 @@ class SetPushRuleJob : public BaseJob {
public:
/*! \brief Add or change a push rule.
*
+ *
* \param scope
* ``global`` to specify global rules.
+ *
* \param kind
* The kind of rule
+ *
* \param ruleId
* The identifier for the rule.
+ *
* \param actions
* The action(s) to perform when the conditions for this rule are met.
+ *
* \param before
* Use 'before' with a ``rule_id`` as its value to make the new rule the
* next-most important rule with respect to the given user defined rule.
* It is not possible to add a rule relative to a predefined server rule.
+ *
* \param after
* This makes the new rule the next-less important rule relative to the
* given user defined rule. It is not possible to add a rule relative
* to a predefined server rule.
+ *
* \param conditions
* The conditions that must hold true for an event in order for a
* rule to be applied to an event. A rule with no conditions
- * always matches. Only applicable to ``underride`` and ``override``
- * rules. \param pattern Only applicable to ``content`` rules. The
- * glob-style pattern to match against.
+ * always matches. Only applicable to ``underride`` and ``override`` rules.
+ *
+ * \param pattern
+ * Only applicable to ``content`` rules. The glob-style pattern to match
+ * against.
*/
explicit SetPushRuleJob(const QString& scope, const QString& kind,
const QString& ruleId, const QStringList& actions,
@@ -169,11 +166,14 @@ class IsPushRuleEnabledJob : public BaseJob {
public:
/*! \brief Get whether a push rule is enabled
*
+ *
* \param scope
* Either ``global`` or ``device/<profile_tag>`` to specify global
* rules or device rules for the given ``profile_tag``.
+ *
* \param kind
* The kind of rule
+ *
* \param ruleId
* The identifier for the rule.
*/
@@ -187,19 +187,11 @@ public:
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& scope,
const QString& kind, const QString& ruleId);
- ~IsPushRuleEnabledJob() override;
// Result properties
/// Whether the push rule is enabled or not.
- bool enabled() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ bool enabled() const { return loadFromJson<bool>("enabled"_ls); }
};
/*! \brief Enable or disable a push rule.
@@ -210,12 +202,16 @@ class SetPushRuleEnabledJob : public BaseJob {
public:
/*! \brief Enable or disable a push rule.
*
+ *
* \param scope
* ``global`` to specify global rules.
+ *
* \param kind
* The kind of rule
+ *
* \param ruleId
* The identifier for the rule.
+ *
* \param enabled
* Whether the push rule is enabled or not.
*/
@@ -231,11 +227,14 @@ class GetPushRuleActionsJob : public BaseJob {
public:
/*! \brief The actions for a push rule
*
+ *
* \param scope
* Either ``global`` or ``device/<profile_tag>`` to specify global
* rules or device rules for the given ``profile_tag``.
+ *
* \param kind
* The kind of rule
+ *
* \param ruleId
* The identifier for the rule.
*/
@@ -249,19 +248,14 @@ public:
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& scope,
const QString& kind, const QString& ruleId);
- ~GetPushRuleActionsJob() override;
// Result properties
/// The action(s) to perform for this rule.
- const QStringList& actions() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QStringList actions() const
+ {
+ return loadFromJson<QStringList>("actions"_ls);
+ }
};
/*! \brief Set the actions for a push rule.
@@ -273,12 +267,16 @@ class SetPushRuleActionsJob : public BaseJob {
public:
/*! \brief Set the actions for a push rule.
*
+ *
* \param scope
* ``global`` to specify global rules.
+ *
* \param kind
* The kind of rule
+ *
* \param ruleId
* The identifier for the rule.
+ *
* \param actions
* The action(s) to perform for this rule.
*/
diff --git a/lib/csapi/read_markers.cpp b/lib/csapi/read_markers.cpp
index 76145808..39e4d148 100644
--- a/lib/csapi/read_markers.cpp
+++ b/lib/csapi/read_markers.cpp
@@ -4,22 +4,19 @@
#include "read_markers.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
SetReadMarkerJob::SetReadMarkerJob(const QString& roomId,
const QString& mFullyRead,
const QString& mRead)
: BaseJob(HttpVerb::Post, QStringLiteral("SetReadMarkerJob"),
- basePath % "/rooms/" % roomId % "/read_markers")
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/read_markers")
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("m.fully_read"), mFullyRead);
addParam<IfNotEmpty>(_data, QStringLiteral("m.read"), mRead);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
diff --git a/lib/csapi/read_markers.h b/lib/csapi/read_markers.h
index 539aa5e4..addb9123 100644
--- a/lib/csapi/read_markers.h
+++ b/lib/csapi/read_markers.h
@@ -8,8 +8,6 @@
namespace Quotient {
-// Operations
-
/*! \brief Set the position of the read marker for a room.
*
* Sets the position of the read marker for a given room, and optionally
@@ -19,11 +17,14 @@ class SetReadMarkerJob : public BaseJob {
public:
/*! \brief Set the position of the read marker for a room.
*
+ *
* \param roomId
* The room ID to set the read marker in for the user.
+ *
* \param mFullyRead
* The event ID the read marker should be located at. The
* event MUST belong to the room.
+ *
* \param mRead
* The event ID to set the read receipt location at. This is
* equivalent to calling ``/receipt/m.read/$elsewhere:example.org``
diff --git a/lib/csapi/receipts.cpp b/lib/csapi/receipts.cpp
index 87264074..00d1c28a 100644
--- a/lib/csapi/receipts.cpp
+++ b/lib/csapi/receipts.cpp
@@ -4,20 +4,16 @@
#include "receipts.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
PostReceiptJob::PostReceiptJob(const QString& roomId, const QString& receiptType,
const QString& eventId,
const QJsonObject& receipt)
: BaseJob(HttpVerb::Post, QStringLiteral("PostReceiptJob"),
- basePath % "/rooms/" % roomId % "/receipt/" % receiptType % "/"
- % eventId)
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/receipt/" % receiptType % "/" % eventId)
{
setRequestData(Data(toJson(receipt)));
}
diff --git a/lib/csapi/receipts.h b/lib/csapi/receipts.h
index eb82fc28..fdec3b88 100644
--- a/lib/csapi/receipts.h
+++ b/lib/csapi/receipts.h
@@ -6,12 +6,8 @@
#include "jobs/basejob.h"
-#include <QtCore/QJsonObject>
-
namespace Quotient {
-// Operations
-
/*! \brief Send a receipt for the given event ID.
*
* This API updates the marker for the given receipt type to the event ID
@@ -21,12 +17,16 @@ class PostReceiptJob : public BaseJob {
public:
/*! \brief Send a receipt for the given event ID.
*
+ *
* \param roomId
* The room in which to send the event.
+ *
* \param receiptType
* The type of receipt to send.
+ *
* \param eventId
* The event ID to acknowledge up to.
+ *
* \param receipt
* Extra receipt information to attach to ``content`` if any. The
* server will automatically set the ``ts`` field.
diff --git a/lib/csapi/redaction.cpp b/lib/csapi/redaction.cpp
index 2b6417ea..91497064 100644
--- a/lib/csapi/redaction.cpp
+++ b/lib/csapi/redaction.cpp
@@ -4,38 +4,17 @@
#include "redaction.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-class RedactEventJob::Private {
-public:
- QString eventId;
-};
-
RedactEventJob::RedactEventJob(const QString& roomId, const QString& eventId,
const QString& txnId, const QString& reason)
: BaseJob(HttpVerb::Put, QStringLiteral("RedactEventJob"),
- basePath % "/rooms/" % roomId % "/redact/" % eventId % "/" % txnId)
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/redact/" % eventId % "/" % txnId)
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("reason"), reason);
- setRequestData(_data);
-}
-
-RedactEventJob::~RedactEventJob() = default;
-
-const QString& RedactEventJob::eventId() const { return d->eventId; }
-
-BaseJob::Status RedactEventJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("event_id"_ls), d->eventId);
-
- return Success;
+ setRequestData(std::move(_data));
}
diff --git a/lib/csapi/redaction.h b/lib/csapi/redaction.h
index 0e9095d1..c737de41 100644
--- a/lib/csapi/redaction.h
+++ b/lib/csapi/redaction.h
@@ -8,8 +8,6 @@
namespace Quotient {
-// Operations
-
/*! \brief Strips all non-integrity-critical information out of an event.
*
* Strips all information out of an event which isn't critical to the
@@ -18,38 +16,35 @@ namespace Quotient {
* This cannot be undone.
*
* Users may redact their own events, and any user with a power level
- * greater than or equal to the `redact` power level of the room may
+ * greater than or equal to the ``redact`` power level of the room may
* redact events there.
*/
class RedactEventJob : public BaseJob {
public:
/*! \brief Strips all non-integrity-critical information out of an event.
*
+ *
* \param roomId
* The room from which to redact the event.
+ *
* \param eventId
* The ID of the event to redact
+ *
* \param txnId
* The transaction ID for this event. Clients should generate a
* unique ID; it will be used by the server to ensure idempotency of
- * requests. \param reason The reason for the event being redacted.
+ * requests.
+ *
+ * \param reason
+ * The reason for the event being redacted.
*/
explicit RedactEventJob(const QString& roomId, const QString& eventId,
const QString& txnId, const QString& reason = {});
- ~RedactEventJob() override;
-
// Result properties
/// A unique identifier for the event.
- const QString& eventId() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QString eventId() const { return loadFromJson<QString>("event_id"_ls); }
};
} // namespace Quotient
diff --git a/lib/csapi/registration.cpp b/lib/csapi/registration.cpp
index 768617cc..9f88ef28 100644
--- a/lib/csapi/registration.cpp
+++ b/lib/csapi/registration.cpp
@@ -4,23 +4,11 @@
#include "registration.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-class RegisterJob::Private {
-public:
- QString userId;
- QString accessToken;
- QString homeServer;
- QString deviceId;
-};
-
-BaseJob::Query queryToRegister(const QString& kind)
+auto queryToRegister(const QString& kind)
{
BaseJob::Query _q;
addParam<IfNotEmpty>(_q, QStringLiteral("kind"), kind);
@@ -29,220 +17,94 @@ BaseJob::Query queryToRegister(const QString& kind)
RegisterJob::RegisterJob(const QString& kind,
const Omittable<AuthenticationData>& auth,
- Omittable<bool> bindEmail, const QString& username,
- const QString& password, const QString& deviceId,
+ const QString& username, const QString& password,
+ const QString& deviceId,
const QString& initialDeviceDisplayName,
Omittable<bool> inhibitLogin)
: BaseJob(HttpVerb::Post, QStringLiteral("RegisterJob"),
- basePath % "/register", queryToRegister(kind), {}, false)
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/register",
+ queryToRegister(kind), {}, false)
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("auth"), auth);
- addParam<IfNotEmpty>(_data, QStringLiteral("bind_email"), bindEmail);
addParam<IfNotEmpty>(_data, QStringLiteral("username"), username);
addParam<IfNotEmpty>(_data, QStringLiteral("password"), password);
addParam<IfNotEmpty>(_data, QStringLiteral("device_id"), deviceId);
addParam<IfNotEmpty>(_data, QStringLiteral("initial_device_display_name"),
initialDeviceDisplayName);
addParam<IfNotEmpty>(_data, QStringLiteral("inhibit_login"), inhibitLogin);
- setRequestData(_data);
-}
-
-RegisterJob::~RegisterJob() = default;
-
-const QString& RegisterJob::userId() const { return d->userId; }
-
-const QString& RegisterJob::accessToken() const { return d->accessToken; }
-
-const QString& RegisterJob::homeServer() const { return d->homeServer; }
-
-const QString& RegisterJob::deviceId() const { return d->deviceId; }
-
-BaseJob::Status RegisterJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- if (!json.contains("user_id"_ls))
- return { IncorrectResponse,
- "The key 'user_id' not found in the response" };
- 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;
+ setRequestData(std::move(_data));
+ addExpectedKey("user_id");
}
-class RequestTokenToRegisterEmailJob::Private {
-public:
- Sid data;
-};
-
RequestTokenToRegisterEmailJob::RequestTokenToRegisterEmailJob(
- const QString& clientSecret, const QString& email, int sendAttempt,
- const QString& idServer, const QString& nextLink)
+ const EmailValidationData& body)
: BaseJob(HttpVerb::Post, QStringLiteral("RequestTokenToRegisterEmailJob"),
- basePath % "/register/email/requestToken", false)
- , d(new Private)
-{
- QJsonObject _data;
- addParam<>(_data, QStringLiteral("client_secret"), clientSecret);
- addParam<>(_data, QStringLiteral("email"), email);
- addParam<>(_data, QStringLiteral("send_attempt"), sendAttempt);
- addParam<IfNotEmpty>(_data, QStringLiteral("next_link"), nextLink);
- addParam<>(_data, QStringLiteral("id_server"), idServer);
- setRequestData(_data);
-}
-
-RequestTokenToRegisterEmailJob::~RequestTokenToRegisterEmailJob() = default;
-
-const Sid& RequestTokenToRegisterEmailJob::data() const { return d->data; }
-
-BaseJob::Status
-RequestTokenToRegisterEmailJob::parseJson(const QJsonDocument& data)
+ QStringLiteral("/_matrix/client/r0")
+ % "/register/email/requestToken",
+ false)
{
- fromJson(data, d->data);
-
- return Success;
+ setRequestData(Data(toJson(body)));
}
-class RequestTokenToRegisterMSISDNJob::Private {
-public:
- Sid data;
-};
-
RequestTokenToRegisterMSISDNJob::RequestTokenToRegisterMSISDNJob(
- const QString& clientSecret, const QString& country,
- const QString& phoneNumber, int sendAttempt, const QString& idServer,
- const QString& nextLink)
+ const MsisdnValidationData& body)
: BaseJob(HttpVerb::Post, QStringLiteral("RequestTokenToRegisterMSISDNJob"),
- basePath % "/register/msisdn/requestToken", false)
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0")
+ % "/register/msisdn/requestToken",
+ false)
{
- QJsonObject _data;
- addParam<>(_data, QStringLiteral("client_secret"), clientSecret);
- addParam<>(_data, QStringLiteral("country"), country);
- addParam<>(_data, QStringLiteral("phone_number"), phoneNumber);
- addParam<>(_data, QStringLiteral("send_attempt"), sendAttempt);
- addParam<IfNotEmpty>(_data, QStringLiteral("next_link"), nextLink);
- addParam<>(_data, QStringLiteral("id_server"), idServer);
- setRequestData(_data);
-}
-
-RequestTokenToRegisterMSISDNJob::~RequestTokenToRegisterMSISDNJob() = default;
-
-const Sid& RequestTokenToRegisterMSISDNJob::data() const { return d->data; }
-
-BaseJob::Status
-RequestTokenToRegisterMSISDNJob::parseJson(const QJsonDocument& data)
-{
- fromJson(data, d->data);
-
- return Success;
+ setRequestData(Data(toJson(body)));
}
ChangePasswordJob::ChangePasswordJob(const QString& newPassword,
+ Omittable<bool> logoutDevices,
const Omittable<AuthenticationData>& auth)
: BaseJob(HttpVerb::Post, QStringLiteral("ChangePasswordJob"),
- basePath % "/account/password")
+ QStringLiteral("/_matrix/client/r0") % "/account/password")
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("new_password"), newPassword);
+ addParam<IfNotEmpty>(_data, QStringLiteral("logout_devices"), logoutDevices);
addParam<IfNotEmpty>(_data, QStringLiteral("auth"), auth);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
-class RequestTokenToResetPasswordEmailJob::Private {
-public:
- Sid data;
-};
-
RequestTokenToResetPasswordEmailJob::RequestTokenToResetPasswordEmailJob(
- const QString& clientSecret, const QString& email, int sendAttempt,
- const QString& idServer, const QString& nextLink)
+ const EmailValidationData& body)
: BaseJob(HttpVerb::Post,
QStringLiteral("RequestTokenToResetPasswordEmailJob"),
- basePath % "/account/password/email/requestToken", false)
- , d(new Private)
-{
- QJsonObject _data;
- addParam<>(_data, QStringLiteral("client_secret"), clientSecret);
- addParam<>(_data, QStringLiteral("email"), email);
- addParam<>(_data, QStringLiteral("send_attempt"), sendAttempt);
- addParam<IfNotEmpty>(_data, QStringLiteral("next_link"), nextLink);
- addParam<>(_data, QStringLiteral("id_server"), idServer);
- setRequestData(_data);
-}
-
-RequestTokenToResetPasswordEmailJob::~RequestTokenToResetPasswordEmailJob() =
- default;
-
-const Sid& RequestTokenToResetPasswordEmailJob::data() const { return d->data; }
-
-BaseJob::Status
-RequestTokenToResetPasswordEmailJob::parseJson(const QJsonDocument& data)
+ QStringLiteral("/_matrix/client/r0")
+ % "/account/password/email/requestToken",
+ false)
{
- fromJson(data, d->data);
-
- return Success;
+ setRequestData(Data(toJson(body)));
}
-class RequestTokenToResetPasswordMSISDNJob::Private {
-public:
- Sid data;
-};
-
RequestTokenToResetPasswordMSISDNJob::RequestTokenToResetPasswordMSISDNJob(
- const QString& clientSecret, const QString& country,
- const QString& phoneNumber, int sendAttempt, const QString& idServer,
- const QString& nextLink)
+ const RequestMsisdnValidation& body)
: BaseJob(HttpVerb::Post,
QStringLiteral("RequestTokenToResetPasswordMSISDNJob"),
- basePath % "/account/password/msisdn/requestToken", false)
- , d(new Private)
-{
- QJsonObject _data;
- addParam<>(_data, QStringLiteral("client_secret"), clientSecret);
- addParam<>(_data, QStringLiteral("country"), country);
- addParam<>(_data, QStringLiteral("phone_number"), phoneNumber);
- addParam<>(_data, QStringLiteral("send_attempt"), sendAttempt);
- addParam<IfNotEmpty>(_data, QStringLiteral("next_link"), nextLink);
- addParam<>(_data, QStringLiteral("id_server"), idServer);
- setRequestData(_data);
-}
-
-RequestTokenToResetPasswordMSISDNJob::~RequestTokenToResetPasswordMSISDNJob() =
- default;
-
-const Sid& RequestTokenToResetPasswordMSISDNJob::data() const
+ QStringLiteral("/_matrix/client/r0")
+ % "/account/password/msisdn/requestToken",
+ false)
{
- return d->data;
-}
-
-BaseJob::Status
-RequestTokenToResetPasswordMSISDNJob::parseJson(const QJsonDocument& data)
-{
- fromJson(data, d->data);
-
- return Success;
+ setRequestData(Data(toJson(body)));
}
DeactivateAccountJob::DeactivateAccountJob(
- const Omittable<AuthenticationData>& auth)
+ const Omittable<AuthenticationData>& auth, const QString& idServer)
: BaseJob(HttpVerb::Post, QStringLiteral("DeactivateAccountJob"),
- basePath % "/account/deactivate")
+ QStringLiteral("/_matrix/client/r0") % "/account/deactivate")
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("auth"), auth);
- setRequestData(_data);
+ addParam<IfNotEmpty>(_data, QStringLiteral("id_server"), idServer);
+ setRequestData(std::move(_data));
+ addExpectedKey("id_server_unbind_result");
}
-class CheckUsernameAvailabilityJob::Private {
-public:
- Omittable<bool> available;
-};
-
-BaseJob::Query queryToCheckUsernameAvailability(const QString& username)
+auto queryToCheckUsernameAvailability(const QString& username)
{
BaseJob::Query _q;
addParam<>(_q, QStringLiteral("username"), username);
@@ -253,28 +115,13 @@ QUrl CheckUsernameAvailabilityJob::makeRequestUrl(QUrl baseUrl,
const QString& username)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/register/available",
+ QStringLiteral("/_matrix/client/r0")
+ % "/register/available",
queryToCheckUsernameAvailability(username));
}
CheckUsernameAvailabilityJob::CheckUsernameAvailabilityJob(const QString& username)
: BaseJob(HttpVerb::Get, QStringLiteral("CheckUsernameAvailabilityJob"),
- basePath % "/register/available",
+ QStringLiteral("/_matrix/client/r0") % "/register/available",
queryToCheckUsernameAvailability(username), {}, false)
- , d(new Private)
{}
-
-CheckUsernameAvailabilityJob::~CheckUsernameAvailabilityJob() = default;
-
-Omittable<bool> CheckUsernameAvailabilityJob::available() const
-{
- return d->available;
-}
-
-BaseJob::Status CheckUsernameAvailabilityJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("available"_ls), d->available);
-
- return Success;
-}
diff --git a/lib/csapi/registration.h b/lib/csapi/registration.h
index 2619dd87..9d96db32 100644
--- a/lib/csapi/registration.h
+++ b/lib/csapi/registration.h
@@ -4,20 +4,20 @@
#pragma once
-#include "converters.h"
-
-#include "csapi/../identity/definitions/sid.h"
+#include "csapi/../identity/definitions/request_msisdn_validation.h"
+#include "csapi/./definitions/request_email_validation.h"
+#include "csapi/./definitions/request_msisdn_validation.h"
#include "csapi/definitions/auth_data.h"
+#include "csapi/definitions/request_token_response.h"
#include "jobs/basejob.h"
namespace Quotient {
-// Operations
-
/*! \brief Register for an account on this homeserver.
*
- * This API endpoint uses the `User-Interactive Authentication API`_.
+ * This API endpoint uses the `User-Interactive Authentication API`_, except in
+ * the cases where a guest account is being registered.
*
* Register for an account on this homeserver.
*
@@ -49,36 +49,46 @@ namespace Quotient {
* supplied by the client or generated by the server. The server may
* invalidate any access token previously associated with that device. See
* `Relationship between access tokens and devices`_.
+ *
+ * When registering a guest account, all parameters in the request body
+ * with the exception of ``initial_device_display_name`` MUST BE ignored
+ * by the server. The server MUST pick a ``device_id`` for the account
+ * regardless of input.
+ *
+ * Any user ID returned by this API must conform to the grammar given in the
+ * `Matrix specification <../appendices.html#user-identifiers>`_.
*/
class RegisterJob : public BaseJob {
public:
/*! \brief Register for an account on this homeserver.
*
+ *
* \param kind
- * The kind of account to register. Defaults to `user`.
+ * The kind of account to register. Defaults to ``user``.
+ *
* \param auth
* Additional authentication information for the
* user-interactive authentication API. Note that this
* information is *not* used to define how the registered user
* should be authenticated, but is instead used to
- * authenticate the ``register`` call itself. It should be
- * left empty, or omitted, unless an earlier call returned an
- * response with status code 401.
- * \param bindEmail
- * If true, the server binds the email used for authentication to
- * the Matrix ID with the identity server.
+ * authenticate the ``register`` call itself.
+ *
* \param username
* The basis for the localpart of the desired Matrix ID. If omitted,
* the homeserver MUST generate a Matrix ID local part.
+ *
* \param password
* The desired password for the account.
+ *
* \param deviceId
* ID of the client device. If this does not correspond to a
* known client device, a new device will be created. The server
* will auto-generate a device_id if this is not specified.
+ *
* \param initialDeviceDisplayName
* A display name to assign to the newly-created device. Ignored
* if ``device_id`` corresponds to a known device.
+ *
* \param inhibitLogin
* If true, an ``access_token`` and ``device_id`` should not be
* returned from this call, therefore preventing an automatic
@@ -86,28 +96,27 @@ public:
*/
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
/// The fully-qualified Matrix user ID (MXID) that has been registered.
///
/// Any user ID returned by this API must conform to the grammar given in
- /// the `Matrix specification
- /// <https://matrix.org/docs/spec/appendices.html#user-identifiers>`_.
- const QString& userId() const;
+ /// the `Matrix specification <../appendices.html#user-identifiers>`_.
+ QString userId() const { return loadFromJson<QString>("user_id"_ls); }
/// An access token for the account.
/// This access token can then be used to authorize other requests.
/// Required if the ``inhibit_login`` option is false.
- const QString& accessToken() const;
+ QString accessToken() const
+ {
+ return loadFromJson<QString>("access_token"_ls);
+ }
/// The server_name of the homeserver on which the account has
/// been registered.
@@ -115,180 +124,141 @@ public:
/// **Deprecated**. Clients should extract the server_name from
/// ``user_id`` (by splitting at the first colon) if they require
/// it. Note also that ``homeserver`` is not spelt this way.
- const QString& homeServer() const;
+ QString homeServer() const
+ {
+ return loadFromJson<QString>("home_server"_ls);
+ }
/// ID of the registered device. Will be the same as the
/// corresponding parameter in the request, if one was specified.
/// Required if the ``inhibit_login`` option is false.
- const QString& deviceId() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QString deviceId() const { return loadFromJson<QString>("device_id"_ls); }
};
/*! \brief Begins the validation process for an email to be used during
* registration.
*
- * Proxies the Identity Service API ``validate/email/requestToken``, but
- * first checks that the given email address is not already associated
- * with an account on this homeserver. See the Identity Service API for
- * further information.
+ * The homeserver must check that the given email address is **not**
+ * already associated with an account on this homeserver. The homeserver
+ * should validate the email itself, either by sending a validation email
+ * itself or by using a service it has control over.
*/
class RequestTokenToRegisterEmailJob : public BaseJob {
public:
/*! \brief Begins the validation process for an email to be used during
* registration.
*
- * \param clientSecret
- * A unique string generated by the client, and used to identify the
- * validation attempt. It must be a string consisting of the characters
- * ``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters and it
- * must not be empty.
- * \param email
- * The email address to validate.
- * \param sendAttempt
- * The server will only send an email if the ``send_attempt``
- * is a number greater than the most recent one which it has seen,
- * scoped to that ``email`` + ``client_secret`` pair. This is to
- * avoid repeatedly sending the same email in the case of request
- * retries between the POSTing user and the identity server.
- * The client should increment this value if they desire a new
- * email (e.g. a reminder) to be sent.
- * \param idServer
- * The hostname of the identity server to communicate with. May
- * optionally include a port.
- * \param nextLink
- * Optional. When the validation is completed, the identity
- * server will redirect the user to this URL.
+ *
+ * \param body
+ * The homeserver must check that the given email address is **not**
+ * already associated with an account on this homeserver. The homeserver
+ * should validate the email itself, either by sending a validation email
+ * itself or by using a service it has control over.
*/
- explicit RequestTokenToRegisterEmailJob(const QString& clientSecret,
- const QString& email,
- int sendAttempt,
- const QString& idServer,
- const QString& nextLink = {});
-
- ~RequestTokenToRegisterEmailJob() override;
+ explicit RequestTokenToRegisterEmailJob(const EmailValidationData& body);
// Result properties
- /// An email has been sent to the specified address.
- /// Note that this may be an email containing the validation token or it may
- /// be informing the user of an error.
- const Sid& data() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ /// An email has been sent to the specified address. Note that this
+ /// may be an email containing the validation token or it may be
+ /// informing the user of an error.
+ RequestTokenResponse data() const
+ {
+ return fromJson<RequestTokenResponse>(jsonData());
+ }
};
/*! \brief Requests a validation token be sent to the given phone number for the
* purpose of registering an account
*
- * Proxies the Identity Service API ``validate/msisdn/requestToken``, but
- * first checks that the given phone number is not already associated
- * with an account on this homeserver. See the Identity Service API for
- * further information.
+ * The homeserver must check that the given phone number is **not**
+ * already associated with an account on this homeserver. The homeserver
+ * should validate the phone number itself, either by sending a validation
+ * message itself or by using a service it has control over.
*/
class RequestTokenToRegisterMSISDNJob : public BaseJob {
public:
/*! \brief Requests a validation token be sent to the given phone number for
* the purpose of registering an account
*
- * \param clientSecret
- * A unique string generated by the client, and used to identify the
- * validation attempt. It must be a string consisting of the characters
- * ``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters and it
- * must not be empty.
- * \param country
- * The two-letter uppercase ISO country code that the number in
- * ``phone_number`` should be parsed as if it were dialled from.
- * \param phoneNumber
- * The phone number to validate.
- * \param sendAttempt
- * The server will only send an SMS if the ``send_attempt`` is a
- * number greater than the most recent one which it has seen,
- * scoped to that ``country`` + ``phone_number`` + ``client_secret``
- * triple. This is to avoid repeatedly sending the same SMS in
- * the case of request retries between the POSTing user and the
- * identity server. The client should increment this value if
- * they desire a new SMS (e.g. a reminder) to be sent.
- * \param idServer
- * The hostname of the identity server to communicate with. May
- * optionally include a port.
- * \param nextLink
- * Optional. When the validation is completed, the identity
- * server will redirect the user to this URL.
+ *
+ * \param body
+ * The homeserver must check that the given phone number is **not**
+ * already associated with an account on this homeserver. The homeserver
+ * should validate the phone number itself, either by sending a validation
+ * message itself or by using a service it has control over.
*/
- explicit RequestTokenToRegisterMSISDNJob(const QString& clientSecret,
- const QString& country,
- const QString& phoneNumber,
- int sendAttempt,
- const QString& idServer,
- const QString& nextLink = {});
-
- ~RequestTokenToRegisterMSISDNJob() override;
+ explicit RequestTokenToRegisterMSISDNJob(const MsisdnValidationData& body);
// Result properties
- /// An SMS message has been sent to the specified phone number.
- /// Note that this may be an SMS message containing the validation token or
+ /// An SMS message has been sent to the specified phone number. Note
+ /// that this may be an SMS message containing the validation token or
/// it may be informing the user of an error.
- const Sid& data() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ RequestTokenResponse data() const
+ {
+ return fromJson<RequestTokenResponse>(jsonData());
+ }
};
/*! \brief Changes a user's password.
*
* Changes the password for an account on this homeserver.
*
- * This API endpoint uses the `User-Interactive Authentication API`_.
+ * This API endpoint uses the `User-Interactive Authentication API`_ to
+ * ensure the user changing the password is actually the owner of the
+ * account.
*
* An access token should be submitted to this endpoint if the client has
* an active session.
*
* The homeserver may change the flows available depending on whether a
- * valid access token is provided.
+ * valid access token is provided. The homeserver SHOULD NOT revoke the
+ * access token provided in the request. Whether other access tokens for
+ * the user are revoked depends on the request parameters.
*/
class ChangePasswordJob : public BaseJob {
public:
/*! \brief Changes a user's password.
*
+ *
* \param newPassword
* The new password for the account.
+ *
+ * \param logoutDevices
+ * Whether the user's other access tokens, and their associated devices,
+ * should be revoked if the request succeeds. Defaults to true.
+ *
+ * When ``false``, the server can still take advantage of `the soft logout
+ * method <#soft-logout>`_ for the user's remaining devices.
+ *
* \param auth
* Additional authentication information for the user-interactive
* authentication API.
*/
explicit ChangePasswordJob(const QString& newPassword,
+ Omittable<bool> logoutDevices = none,
const Omittable<AuthenticationData>& auth = none);
};
/*! \brief Requests a validation token be sent to the given email address for
* the purpose of resetting a user's password
*
- * Proxies the Identity Service API ``validate/email/requestToken``, but
- * first checks that the given email address **is** associated with an account
- * on this homeserver. This API should be used to request
- * validation tokens when authenticating for the
- * `account/password` endpoint. This API's parameters and response are
- * identical to that of the HS API |/register/email/requestToken|_ except that
- * `M_THREEPID_NOT_FOUND` may be returned if no account matching the
+ * The homeserver must check that the given email address **is
+ * associated** with an account on this homeserver. This API should be
+ * used to request validation tokens when authenticating for the
+ * ``/account/password`` endpoint.
+ *
+ * This API's parameters and response are identical to that of the
+ * |/register/email/requestToken|_ endpoint, except that
+ * ``M_THREEPID_NOT_FOUND`` may be returned if no account matching the
* given email address could be found. The server may instead send an
* email to the given address prompting the user to create an account.
- * `M_THREEPID_IN_USE` may not be returned.
+ * ``M_THREEPID_IN_USE`` may not be returned.
+ *
+ * The homeserver should validate the email itself, either by sending a
+ * validation email itself or by using a service it has control over.
+ *
*
* .. |/register/email/requestToken| replace:: ``/register/email/requestToken``
*
@@ -300,62 +270,58 @@ public:
/*! \brief Requests a validation token be sent to the given email address
* for the purpose of resetting a user's password
*
- * \param clientSecret
- * A unique string generated by the client, and used to identify the
- * validation attempt. It must be a string consisting of the characters
- * ``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters and it
- * must not be empty.
- * \param email
- * The email address to validate.
- * \param sendAttempt
- * The server will only send an email if the ``send_attempt``
- * is a number greater than the most recent one which it has seen,
- * scoped to that ``email`` + ``client_secret`` pair. This is to
- * avoid repeatedly sending the same email in the case of request
- * retries between the POSTing user and the identity server.
- * The client should increment this value if they desire a new
- * email (e.g. a reminder) to be sent.
- * \param idServer
- * The hostname of the identity server to communicate with. May
- * optionally include a port.
- * \param nextLink
- * Optional. When the validation is completed, the identity
- * server will redirect the user to this URL.
+ *
+ * \param body
+ * The homeserver must check that the given email address **is
+ * associated** with an account on this homeserver. This API should be
+ * used to request validation tokens when authenticating for the
+ * ``/account/password`` endpoint.
+ *
+ * This API's parameters and response are identical to that of the
+ * |/register/email/requestToken|_ endpoint, except that
+ * ``M_THREEPID_NOT_FOUND`` may be returned if no account matching the
+ * given email address could be found. The server may instead send an
+ * email to the given address prompting the user to create an account.
+ * ``M_THREEPID_IN_USE`` may not be returned.
+ *
+ * The homeserver should validate the email itself, either by sending a
+ * validation email itself or by using a service it has control over.
+ *
+ *
+ * .. |/register/email/requestToken| replace::
+ * ``/register/email/requestToken``
+ *
+ * .. _/register/email/requestToken:
+ * #post-matrix-client-r0-register-email-requesttoken
*/
- explicit RequestTokenToResetPasswordEmailJob(const QString& clientSecret,
- const QString& email,
- int sendAttempt,
- const QString& idServer,
- const QString& nextLink = {});
-
- ~RequestTokenToResetPasswordEmailJob() override;
+ explicit RequestTokenToResetPasswordEmailJob(const EmailValidationData& body);
// Result properties
/// An email was sent to the given address.
- const Sid& data() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ RequestTokenResponse data() const
+ {
+ return fromJson<RequestTokenResponse>(jsonData());
+ }
};
/*! \brief Requests a validation token be sent to the given phone number for the
* purpose of resetting a user's password.
*
- * Proxies the Identity Service API ``validate/msisdn/requestToken``, but
- * first checks that the given phone number **is** associated with an account
- * on this homeserver. This API should be used to request
- * validation tokens when authenticating for the
- * `account/password` endpoint. This API's parameters and response are
- * identical to that of the HS API |/register/msisdn/requestToken|_ except that
- * `M_THREEPID_NOT_FOUND` may be returned if no account matching the
- * given phone number could be found. The server may instead send an
- * SMS message to the given address prompting the user to create an account.
- * `M_THREEPID_IN_USE` may not be returned.
+ * The homeserver must check that the given phone number **is
+ * associated** with an account on this homeserver. This API should be
+ * used to request validation tokens when authenticating for the
+ * ``/account/password`` endpoint.
+ *
+ * This API's parameters and response are identical to that of the
+ * |/register/msisdn/requestToken|_ endpoint, except that
+ * ``M_THREEPID_NOT_FOUND`` may be returned if no account matching the
+ * given phone number could be found. The server may instead send the SMS
+ * to the given phone number prompting the user to create an account.
+ * ``M_THREEPID_IN_USE`` may not be returned.
+ *
+ * The homeserver should validate the phone number itself, either by sending a
+ * validation message itself or by using a service it has control over.
*
* .. |/register/msisdn/requestToken| replace:: ``/register/msisdn/requestToken``
*
@@ -367,51 +333,39 @@ public:
/*! \brief Requests a validation token be sent to the given phone number for
* the purpose of resetting a user's password.
*
- * \param clientSecret
- * A unique string generated by the client, and used to identify the
- * validation attempt. It must be a string consisting of the characters
- * ``[0-9a-zA-Z.=_-]``. Its length must not exceed 255 characters and it
- * must not be empty.
- * \param country
- * The two-letter uppercase ISO country code that the number in
- * ``phone_number`` should be parsed as if it were dialled from.
- * \param phoneNumber
- * The phone number to validate.
- * \param sendAttempt
- * The server will only send an SMS if the ``send_attempt`` is a
- * number greater than the most recent one which it has seen,
- * scoped to that ``country`` + ``phone_number`` + ``client_secret``
- * triple. This is to avoid repeatedly sending the same SMS in
- * the case of request retries between the POSTing user and the
- * identity server. The client should increment this value if
- * they desire a new SMS (e.g. a reminder) to be sent.
- * \param idServer
- * The hostname of the identity server to communicate with. May
- * optionally include a port.
- * \param nextLink
- * Optional. When the validation is completed, the identity
- * server will redirect the user to this URL.
+ *
+ * \param body
+ * The homeserver must check that the given phone number **is
+ * associated** with an account on this homeserver. This API should be
+ * used to request validation tokens when authenticating for the
+ * ``/account/password`` endpoint.
+ *
+ * This API's parameters and response are identical to that of the
+ * |/register/msisdn/requestToken|_ endpoint, except that
+ * ``M_THREEPID_NOT_FOUND`` may be returned if no account matching the
+ * given phone number could be found. The server may instead send the SMS
+ * to the given phone number prompting the user to create an account.
+ * ``M_THREEPID_IN_USE`` may not be returned.
+ *
+ * The homeserver should validate the phone number itself, either by sending
+ * a validation message itself or by using a service it has control over.
+ *
+ * .. |/register/msisdn/requestToken| replace::
+ * ``/register/msisdn/requestToken``
+ *
+ * .. _/register/msisdn/requestToken:
+ * #post-matrix-client-r0-register-email-requesttoken
*/
- explicit RequestTokenToResetPasswordMSISDNJob(const QString& clientSecret,
- const QString& country,
- const QString& phoneNumber,
- int sendAttempt,
- const QString& idServer,
- const QString& nextLink = {});
-
- ~RequestTokenToResetPasswordMSISDNJob() override;
+ explicit RequestTokenToResetPasswordMSISDNJob(
+ const RequestMsisdnValidation& body);
// Result properties
/// An SMS message was sent to the given phone number.
- const Sid& data() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ RequestTokenResponse data() const
+ {
+ return fromJson<RequestTokenResponse>(jsonData());
+ }
};
/*! \brief Deactivate a user's account.
@@ -426,17 +380,45 @@ private:
*
* The homeserver may change the flows available depending on whether a
* valid access token is provided.
+ *
+ * Unlike other endpoints, this endpoint does not take an ``id_access_token``
+ * parameter because the homeserver is expected to sign the request to the
+ * identity server instead.
*/
class DeactivateAccountJob : public BaseJob {
public:
/*! \brief Deactivate a user's account.
*
+ *
* \param auth
* Additional authentication information for the user-interactive
* authentication API.
+ *
+ * \param idServer
+ * The identity server to unbind all of the user's 3PIDs from.
+ * If not provided, the homeserver MUST use the ``id_server``
+ * that was originally use to bind each identifier. If the
+ * homeserver does not know which ``id_server`` that was,
+ * it must return an ``id_server_unbind_result`` of
+ * ``no-support``.
*/
- explicit DeactivateAccountJob(
- const Omittable<AuthenticationData>& auth = none);
+ explicit DeactivateAccountJob(const Omittable<AuthenticationData>& auth = none,
+ const QString& idServer = {});
+
+ // Result properties
+
+ /// An indicator as to whether or not the homeserver was able to unbind
+ /// the user's 3PIDs from the identity server(s). ``success`` indicates
+ /// that all identifiers have been unbound from the identity server while
+ /// ``no-support`` indicates that one or more identifiers failed to unbind
+ /// due to the identity server refusing the request or the homeserver
+ /// being unable to determine an identity server to unbind from. This
+ /// must be ``success`` if the homeserver has no identifiers to unbind
+ /// for the user.
+ QString idServerUnbindResult() const
+ {
+ return loadFromJson<QString>("id_server_unbind_result"_ls);
+ }
};
/*! \brief Checks to see if a username is available on the server.
@@ -458,6 +440,7 @@ class CheckUsernameAvailabilityJob : public BaseJob {
public:
/*! \brief Checks to see if a username is available on the server.
*
+ *
* \param username
* The username to check the availability of.
*/
@@ -469,20 +452,15 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& username);
- ~CheckUsernameAvailabilityJob() override;
// Result properties
/// A flag to indicate that the username is available. This should always
/// be ``true`` when the server replies with 200 OK.
- Omittable<bool> available() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ Omittable<bool> available() const
+ {
+ return loadFromJson<Omittable<bool>>("available"_ls);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/report_content.cpp b/lib/csapi/report_content.cpp
index f38b7a9a..0a41625f 100644
--- a/lib/csapi/report_content.cpp
+++ b/lib/csapi/report_content.cpp
@@ -4,21 +4,18 @@
#include "report_content.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
ReportContentJob::ReportContentJob(const QString& roomId, const QString& eventId,
int score, const QString& reason)
: BaseJob(HttpVerb::Post, QStringLiteral("ReportContentJob"),
- basePath % "/rooms/" % roomId % "/report/" % eventId)
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/report/" % eventId)
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("score"), score);
addParam<>(_data, QStringLiteral("reason"), reason);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
diff --git a/lib/csapi/report_content.h b/lib/csapi/report_content.h
index 0f3cc3d5..13dc9138 100644
--- a/lib/csapi/report_content.h
+++ b/lib/csapi/report_content.h
@@ -4,14 +4,10 @@
#pragma once
-#include "converters.h"
-
#include "jobs/basejob.h"
namespace Quotient {
-// Operations
-
/*! \brief Reports an event as inappropriate.
*
* Reports an event as inappropriate to the server, which may then notify
@@ -21,13 +17,17 @@ class ReportContentJob : public BaseJob {
public:
/*! \brief Reports an event as inappropriate.
*
+ *
* \param roomId
* The room in which the event being reported is located.
+ *
* \param eventId
* The event to report.
+ *
* \param score
* The score to rate this content as where -100 is most offensive
* and 0 is inoffensive.
+ *
* \param reason
* The reason the content is being reported. May be blank.
*/
diff --git a/lib/csapi/room_send.cpp b/lib/csapi/room_send.cpp
index d278433b..63986c56 100644
--- a/lib/csapi/room_send.cpp
+++ b/lib/csapi/room_send.cpp
@@ -4,36 +4,16 @@
#include "room_send.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-class SendMessageJob::Private {
-public:
- QString eventId;
-};
-
SendMessageJob::SendMessageJob(const QString& roomId, const QString& eventType,
const QString& txnId, const QJsonObject& body)
: BaseJob(HttpVerb::Put, QStringLiteral("SendMessageJob"),
- basePath % "/rooms/" % roomId % "/send/" % eventType % "/" % txnId)
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/send/" % eventType % "/" % txnId)
{
setRequestData(Data(toJson(body)));
-}
-
-SendMessageJob::~SendMessageJob() = default;
-
-const QString& SendMessageJob::eventId() const { return d->eventId; }
-
-BaseJob::Status SendMessageJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("event_id"_ls), d->eventId);
-
- return Success;
+ addExpectedKey("event_id");
}
diff --git a/lib/csapi/room_send.h b/lib/csapi/room_send.h
index 96b111ff..b1905e53 100644
--- a/lib/csapi/room_send.h
+++ b/lib/csapi/room_send.h
@@ -6,12 +6,8 @@
#include "jobs/basejob.h"
-#include <QtCore/QJsonObject>
-
namespace Quotient {
-// Operations
-
/*! \brief Send a message event to the given room.
*
* This endpoint is used to send a message event to a room. Message events
@@ -26,14 +22,18 @@ class SendMessageJob : public BaseJob {
public:
/*! \brief Send a message event to the given room.
*
+ *
* \param roomId
* The room to send the event to.
+ *
* \param eventType
* The type of event to send.
+ *
* \param txnId
* The transaction ID for this event. Clients should generate an
* ID unique across requests with the same access token; it will be
* used by the server to ensure idempotency of requests.
+ *
* \param body
* This endpoint is used to send a message event to a room. Message events
* allow access to historical events and pagination, making them suited
@@ -46,19 +46,10 @@ public:
explicit SendMessageJob(const QString& roomId, const QString& eventType,
const QString& txnId, const QJsonObject& body = {});
- ~SendMessageJob() override;
-
// Result properties
/// A unique identifier for the event.
- const QString& eventId() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QString eventId() const { return loadFromJson<QString>("event_id"_ls); }
};
} // namespace Quotient
diff --git a/lib/csapi/room_state.cpp b/lib/csapi/room_state.cpp
index 5973b06b..e18108ac 100644
--- a/lib/csapi/room_state.cpp
+++ b/lib/csapi/room_state.cpp
@@ -4,65 +4,18 @@
#include "room_state.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-class SetRoomStateWithKeyJob::Private {
-public:
- QString eventId;
-};
-
SetRoomStateWithKeyJob::SetRoomStateWithKeyJob(const QString& roomId,
const QString& eventType,
const QString& stateKey,
const QJsonObject& body)
: BaseJob(HttpVerb::Put, QStringLiteral("SetRoomStateWithKeyJob"),
- basePath % "/rooms/" % roomId % "/state/" % eventType % "/"
- % stateKey)
- , d(new Private)
-{
- setRequestData(Data(toJson(body)));
-}
-
-SetRoomStateWithKeyJob::~SetRoomStateWithKeyJob() = default;
-
-const QString& SetRoomStateWithKeyJob::eventId() const { return d->eventId; }
-
-BaseJob::Status SetRoomStateWithKeyJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("event_id"_ls), d->eventId);
-
- return Success;
-}
-
-class SetRoomStateJob::Private {
-public:
- QString eventId;
-};
-
-SetRoomStateJob::SetRoomStateJob(const QString& roomId, const QString& eventType,
- const QJsonObject& body)
- : BaseJob(HttpVerb::Put, QStringLiteral("SetRoomStateJob"),
- basePath % "/rooms/" % roomId % "/state/" % eventType)
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/state/" % eventType % "/" % stateKey)
{
setRequestData(Data(toJson(body)));
-}
-
-SetRoomStateJob::~SetRoomStateJob() = default;
-
-const QString& SetRoomStateJob::eventId() const { return d->eventId; }
-
-BaseJob::Status SetRoomStateJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("event_id"_ls), d->eventId);
-
- return Success;
+ addExpectedKey("event_id");
}
diff --git a/lib/csapi/room_state.h b/lib/csapi/room_state.h
index 7843cff4..eeb2b33c 100644
--- a/lib/csapi/room_state.h
+++ b/lib/csapi/room_state.h
@@ -6,14 +6,13 @@
#include "jobs/basejob.h"
-#include <QtCore/QJsonObject>
-
namespace Quotient {
-// Operations
-
/*! \brief Send a state event to the given room.
*
+ * .. For backwards compatibility with older links...
+ * .. _`put-matrix-client-r0-rooms-roomid-state-eventtype`:
+ *
* State events can be sent using this endpoint. These events will be
* overwritten if ``<room id>``, ``<event type>`` and ``<state key>`` all
* match.
@@ -25,18 +24,32 @@ namespace Quotient {
* The body of the request should be the content object of the event; the
* fields in this object will vary depending on the type of event. See
* `Room Events`_ for the ``m.`` event specification.
+ *
+ * If the event type being sent is ``m.room.canonical_alias`` servers
+ * SHOULD ensure that any new aliases being listed in the event are valid
+ * per their grammar/syntax and that they point to the room ID where the
+ * state event is to be sent. Servers do not validate aliases which are
+ * being removed or are already present in the state event.
*/
class SetRoomStateWithKeyJob : public BaseJob {
public:
/*! \brief Send a state event to the given room.
*
+ *
* \param roomId
* The room to set the state in
+ *
* \param eventType
* The type of event to send.
+ *
* \param stateKey
- * The state_key for the state to send. Defaults to the empty string.
+ * The state_key for the state to send. Defaults to the empty string. When
+ * an empty string, the trailing slash on this endpoint is optional.
+ *
* \param body
+ * .. For backwards compatibility with older links...
+ * .. _`put-matrix-client-r0-rooms-roomid-state-eventtype`:
+ *
* State events can be sent using this endpoint. These events will be
* overwritten if ``<room id>``, ``<event type>`` and ``<state key>`` all
* match.
@@ -48,81 +61,22 @@ public:
* The body of the request should be the content object of the event; the
* fields in this object will vary depending on the type of event. See
* `Room Events`_ for the ``m.`` event specification.
+ *
+ * If the event type being sent is ``m.room.canonical_alias`` servers
+ * SHOULD ensure that any new aliases being listed in the event are valid
+ * per their grammar/syntax and that they point to the room ID where the
+ * state event is to be sent. Servers do not validate aliases which are
+ * being removed or are already present in the state event.
*/
explicit SetRoomStateWithKeyJob(const QString& roomId,
const QString& eventType,
const QString& stateKey,
const QJsonObject& body = {});
- ~SetRoomStateWithKeyJob() override;
-
- // Result properties
-
- /// A unique identifier for the event.
- const QString& eventId() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
-};
-
-/*! \brief Send a state event to the given room.
- *
- * State events can be sent using this endpoint. This endpoint is
- * equivalent to calling `/rooms/{roomId}/state/{eventType}/{stateKey}`
- * with an empty `stateKey`. Previous state events with matching
- * `<roomId>` and `<eventType>`, and empty `<stateKey>`, will be overwritten.
- *
- * Requests to this endpoint **cannot use transaction IDs**
- * like other ``PUT`` paths because they cannot be differentiated from the
- * ``state_key``. Furthermore, ``POST`` is unsupported on state paths.
- *
- * The body of the request should be the content object of the event; the
- * fields in this object will vary depending on the type of event. See
- * `Room Events`_ for the ``m.`` event specification.
- */
-class SetRoomStateJob : public BaseJob {
-public:
- /*! \brief Send a state event to the given room.
- *
- * \param roomId
- * The room to set the state in
- * \param eventType
- * The type of event to send.
- * \param body
- * State events can be sent using this endpoint. This endpoint is
- * equivalent to calling `/rooms/{roomId}/state/{eventType}/{stateKey}`
- * with an empty `stateKey`. Previous state events with matching
- * `<roomId>` and `<eventType>`, and empty `<stateKey>`, will be
- * overwritten.
- *
- * Requests to this endpoint **cannot use transaction IDs**
- * like other ``PUT`` paths because they cannot be differentiated from the
- * ``state_key``. Furthermore, ``POST`` is unsupported on state paths.
- *
- * The body of the request should be the content object of the event; the
- * fields in this object will vary depending on the type of event. See
- * `Room Events`_ for the ``m.`` event specification.
- */
- explicit SetRoomStateJob(const QString& roomId, const QString& eventType,
- const QJsonObject& body = {});
-
- ~SetRoomStateJob() override;
-
// Result properties
/// A unique identifier for the event.
- const QString& eventId() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QString eventId() const { return loadFromJson<QString>("event_id"_ls); }
};
} // namespace Quotient
diff --git a/lib/csapi/room_upgrades.cpp b/lib/csapi/room_upgrades.cpp
index 244f5b74..e3791b08 100644
--- a/lib/csapi/room_upgrades.cpp
+++ b/lib/csapi/room_upgrades.cpp
@@ -4,43 +4,17 @@
#include "room_upgrades.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-class UpgradeRoomJob::Private {
-public:
- QString replacementRoom;
-};
-
UpgradeRoomJob::UpgradeRoomJob(const QString& roomId, const QString& newVersion)
: BaseJob(HttpVerb::Post, QStringLiteral("UpgradeRoomJob"),
- basePath % "/rooms/" % roomId % "/upgrade")
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/upgrade")
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("new_version"), newVersion);
- setRequestData(_data);
-}
-
-UpgradeRoomJob::~UpgradeRoomJob() = default;
-
-const QString& UpgradeRoomJob::replacementRoom() const
-{
- return d->replacementRoom;
-}
-
-BaseJob::Status UpgradeRoomJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- if (!json.contains("replacement_room"_ls))
- return { IncorrectResponse,
- "The key 'replacement_room' not found in the response" };
- fromJson(json.value("replacement_room"_ls), d->replacementRoom);
-
- return Success;
+ setRequestData(std::move(_data));
+ addExpectedKey("replacement_room");
}
diff --git a/lib/csapi/room_upgrades.h b/lib/csapi/room_upgrades.h
index f13a9af4..53601816 100644
--- a/lib/csapi/room_upgrades.h
+++ b/lib/csapi/room_upgrades.h
@@ -8,8 +8,6 @@
namespace Quotient {
-// Operations
-
/*! \brief Upgrades a room to a new room version.
*
* Upgrades the given room to a particular room version.
@@ -18,26 +16,22 @@ class UpgradeRoomJob : public BaseJob {
public:
/*! \brief Upgrades a room to a new room version.
*
+ *
* \param roomId
* The ID of the room to upgrade.
+ *
* \param newVersion
* The new version for the room.
*/
explicit UpgradeRoomJob(const QString& roomId, const QString& newVersion);
- ~UpgradeRoomJob() override;
-
// Result properties
/// The ID of the new room.
- const QString& replacementRoom() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QString replacementRoom() const
+ {
+ return loadFromJson<QString>("replacement_room"_ls);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/rooms.cpp b/lib/csapi/rooms.cpp
index 234e33df..724d941f 100644
--- a/lib/csapi/rooms.cpp
+++ b/lib/csapi/rooms.cpp
@@ -4,51 +4,33 @@
#include "rooms.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-class GetOneRoomEventJob::Private {
-public:
- EventPtr data;
-};
-
QUrl GetOneRoomEventJob::makeRequestUrl(QUrl baseUrl, const QString& roomId,
const QString& eventId)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/rooms/"
- % roomId % "/event/"
- % eventId);
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ QStringLiteral("/_matrix/client/r0")
+ % "/rooms/" % roomId % "/event/"
+ % eventId);
}
GetOneRoomEventJob::GetOneRoomEventJob(const QString& roomId,
const QString& eventId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetOneRoomEventJob"),
- basePath % "/rooms/" % roomId % "/event/" % eventId)
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/event/" % eventId)
{}
-GetOneRoomEventJob::~GetOneRoomEventJob() = default;
-
-EventPtr&& GetOneRoomEventJob::data() { return std::move(d->data); }
-
-BaseJob::Status GetOneRoomEventJob::parseJson(const QJsonDocument& data)
-{
- fromJson(data, d->data);
-
- return Success;
-}
-
QUrl GetRoomStateWithKeyJob::makeRequestUrl(QUrl baseUrl, const QString& roomId,
const QString& eventType,
const QString& stateKey)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/rooms/" % roomId % "/state/"
+ QStringLiteral("/_matrix/client/r0")
+ % "/rooms/" % roomId % "/state/"
% eventType % "/" % stateKey);
}
@@ -56,60 +38,25 @@ GetRoomStateWithKeyJob::GetRoomStateWithKeyJob(const QString& roomId,
const QString& eventType,
const QString& stateKey)
: BaseJob(HttpVerb::Get, QStringLiteral("GetRoomStateWithKeyJob"),
- basePath % "/rooms/" % roomId % "/state/" % eventType % "/"
- % stateKey)
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/state/" % eventType % "/" % stateKey)
{}
-QUrl GetRoomStateByTypeJob::makeRequestUrl(QUrl baseUrl, const QString& roomId,
- const QString& eventType)
-{
- return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/rooms/"
- % roomId % "/state/"
- % eventType);
-}
-
-GetRoomStateByTypeJob::GetRoomStateByTypeJob(const QString& roomId,
- const QString& eventType)
- : BaseJob(HttpVerb::Get, QStringLiteral("GetRoomStateByTypeJob"),
- basePath % "/rooms/" % roomId % "/state/" % eventType)
-{}
-
-class GetRoomStateJob::Private {
-public:
- StateEvents data;
-};
-
QUrl GetRoomStateJob::makeRequestUrl(QUrl baseUrl, const QString& roomId)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/rooms/" % roomId % "/state");
+ QStringLiteral("/_matrix/client/r0")
+ % "/rooms/" % roomId % "/state");
}
GetRoomStateJob::GetRoomStateJob(const QString& roomId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetRoomStateJob"),
- basePath % "/rooms/" % roomId % "/state")
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/state")
{}
-GetRoomStateJob::~GetRoomStateJob() = default;
-
-StateEvents&& GetRoomStateJob::data() { return std::move(d->data); }
-
-BaseJob::Status GetRoomStateJob::parseJson(const QJsonDocument& data)
-{
- fromJson(data, d->data);
-
- return Success;
-}
-
-class GetMembersByRoomJob::Private {
-public:
- EventsArray<RoomMemberEvent> chunk;
-};
-
-BaseJob::Query queryToGetMembersByRoom(const QString& at,
- const QString& membership,
- const QString& notMembership)
+auto queryToGetMembersByRoom(const QString& at, const QString& membership,
+ const QString& notMembership)
{
BaseJob::Query _q;
addParam<IfNotEmpty>(_q, QStringLiteral("at"), at);
@@ -123,10 +70,10 @@ QUrl GetMembersByRoomJob::makeRequestUrl(QUrl baseUrl, const QString& roomId,
const QString& membership,
const QString& notMembership)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/rooms/" % roomId % "/members",
- queryToGetMembersByRoom(at, membership,
- notMembership));
+ return BaseJob::makeRequestUrl(
+ std::move(baseUrl),
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId % "/members",
+ queryToGetMembersByRoom(at, membership, notMembership));
}
GetMembersByRoomJob::GetMembersByRoomJob(const QString& roomId,
@@ -134,72 +81,21 @@ GetMembersByRoomJob::GetMembersByRoomJob(const QString& roomId,
const QString& membership,
const QString& notMembership)
: BaseJob(HttpVerb::Get, QStringLiteral("GetMembersByRoomJob"),
- basePath % "/rooms/" % roomId % "/members",
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/members",
queryToGetMembersByRoom(at, membership, notMembership))
- , d(new Private)
{}
-GetMembersByRoomJob::~GetMembersByRoomJob() = default;
-
-EventsArray<RoomMemberEvent>&& GetMembersByRoomJob::chunk()
-{
- return std::move(d->chunk);
-}
-
-BaseJob::Status GetMembersByRoomJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("chunk"_ls), d->chunk);
-
- return Success;
-}
-
-// Converters
-namespace Quotient {
-
-template <>
-struct JsonObjectConverter<GetJoinedMembersByRoomJob::RoomMember> {
- static void fillFrom(const QJsonObject& jo,
- GetJoinedMembersByRoomJob::RoomMember& result)
- {
- fromJson(jo.value("display_name"_ls), result.displayName);
- fromJson(jo.value("avatar_url"_ls), result.avatarUrl);
- }
-};
-
-} // namespace Quotient
-
-class GetJoinedMembersByRoomJob::Private {
-public:
- QHash<QString, RoomMember> joined;
-};
-
QUrl GetJoinedMembersByRoomJob::makeRequestUrl(QUrl baseUrl,
const QString& roomId)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/rooms/"
- % roomId
- % "/joined_members");
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ QStringLiteral("/_matrix/client/r0")
+ % "/rooms/" % roomId % "/joined_members");
}
GetJoinedMembersByRoomJob::GetJoinedMembersByRoomJob(const QString& roomId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetJoinedMembersByRoomJob"),
- basePath % "/rooms/" % roomId % "/joined_members")
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/joined_members")
{}
-
-GetJoinedMembersByRoomJob::~GetJoinedMembersByRoomJob() = default;
-
-const QHash<QString, GetJoinedMembersByRoomJob::RoomMember>&
-GetJoinedMembersByRoomJob::joined() const
-{
- return d->joined;
-}
-
-BaseJob::Status GetJoinedMembersByRoomJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("joined"_ls), d->joined);
-
- return Success;
-}
diff --git a/lib/csapi/rooms.h b/lib/csapi/rooms.h
index 05c5b82a..6137bcbd 100644
--- a/lib/csapi/rooms.h
+++ b/lib/csapi/rooms.h
@@ -4,18 +4,12 @@
#pragma once
-#include "converters.h"
-
#include "events/eventloader.h"
#include "events/roommemberevent.h"
#include "jobs/basejob.h"
-#include <QtCore/QHash>
-
namespace Quotient {
-// Operations
-
/*! \brief Get a single event by event ID.
*
* Get a single event based on ``roomId/eventId``. You must have permission to
@@ -25,8 +19,10 @@ class GetOneRoomEventJob : public BaseJob {
public:
/*! \brief Get a single event by event ID.
*
+ *
* \param roomId
* The ID of the room the event is in.
+ *
* \param eventId
* The event ID to get.
*/
@@ -39,23 +35,18 @@ public:
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId,
const QString& eventId);
- ~GetOneRoomEventJob() override;
// Result properties
/// The full event.
- EventPtr&& data();
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ EventPtr data() { return fromJson<EventPtr>(jsonData()); }
};
/*! \brief Get the state identified by the type and key.
*
+ * .. For backwards compatibility with older links...
+ * .. _`get-matrix-client-r0-rooms-roomid-state-eventtype`:
+ *
* Looks up the contents of a state event in a room. If the user is
* joined to the room then the state is taken from the current
* state of the room. If the user has left the room then the state is
@@ -65,12 +56,16 @@ class GetRoomStateWithKeyJob : public BaseJob {
public:
/*! \brief Get the state identified by the type and key.
*
+ *
* \param roomId
* The room to look up the state in.
+ *
* \param eventType
* The type of state to look up.
+ *
* \param stateKey
- * The key of the state to look up.
+ * The key of the state to look up. Defaults to an empty string. When
+ * an empty string, the trailing slash on this endpoint is optional.
*/
explicit GetRoomStateWithKeyJob(const QString& roomId,
const QString& eventType,
@@ -86,36 +81,6 @@ public:
const QString& stateKey);
};
-/*! \brief Get the state identified by the type, with the empty state key.
- *
- * Looks up the contents of a state event in a room. If the user is
- * joined to the room then the state is taken from the current
- * state of the room. If the user has left the room then the state is
- * taken from the state of the room when they left.
- *
- * This looks up the state event with the empty state key.
- */
-class GetRoomStateByTypeJob : public BaseJob {
-public:
- /*! \brief Get the state identified by the type, with the empty state key.
- *
- * \param roomId
- * The room to look up the state in.
- * \param eventType
- * The type of state to look up.
- */
- explicit GetRoomStateByTypeJob(const QString& roomId,
- const QString& eventType);
-
- /*! \brief Construct a URL without creating a full-fledged job object
- *
- * This function can be used when a URL for GetRoomStateByTypeJob
- * is necessary but the job itself isn't.
- */
- static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId,
- const QString& eventType);
-};
-
/*! \brief Get all state events in the current state of a room.
*
* Get the state events for the current state of a room.
@@ -124,6 +89,7 @@ class GetRoomStateJob : public BaseJob {
public:
/*! \brief Get all state events in the current state of a room.
*
+ *
* \param roomId
* The room to look up the state for.
*/
@@ -135,22 +101,11 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId);
- ~GetRoomStateJob() override;
// Result properties
- /// If the user is a member of the room this will be the
- /// current state of the room as a list of events. If the user
- /// has left the room then this will be the state of the room
- /// when they left as a list of events.
- StateEvents&& data();
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ /// The current state of the room
+ StateEvents data() { return fromJson<StateEvents>(jsonData()); }
};
/*! \brief Get the m.room.member events for the room.
@@ -161,17 +116,26 @@ class GetMembersByRoomJob : public BaseJob {
public:
/*! \brief 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.
+ * The point in time (pagination token) to return members for in the room.
+ * This token can be obtained from a ``prev_batch`` token returned for
+ * each room by the sync API. Defaults to the current state of the room,
+ * as determined by the server.
+ *
* \param membership
- * Only return users with the specified membership
+ * The kind of membership to filter for. Defaults to no filtering if
+ * unspecified. When specified alongside ``not_membership``, the two
+ * parameters create an 'or' condition: either the membership *is*
+ * the same as ``membership`` **or** *is not* the same as
+ * ``not_membership``.
+ *
* \param notMembership
- * Only return users with membership state other than specified
+ * The kind of membership to exclude from the results. Defaults to no
+ * filtering if unspecified.
*/
explicit GetMembersByRoomJob(const QString& roomId, const QString& at = {},
const QString& membership = {},
@@ -186,19 +150,14 @@ public:
const QString& at = {},
const QString& membership = {},
const QString& notMembership = {});
- ~GetMembersByRoomJob() override;
// Result properties
/// Get the list of members for this room.
- EventsArray<RoomMemberEvent>&& chunk();
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ EventsArray<RoomMemberEvent> chunk()
+ {
+ return takeFromJson<EventsArray<RoomMemberEvent>>("chunk"_ls);
+ }
};
/*! \brief Gets the list of currently joined users and their profile data.
@@ -231,6 +190,7 @@ public:
/*! \brief Gets the list of currently joined users and their profile data.
*
+ *
* \param roomId
* The room to get the members of.
*/
@@ -242,19 +202,24 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId);
- ~GetJoinedMembersByRoomJob() override;
// Result properties
/// A map from user ID to a RoomMember object.
- const QHash<QString, RoomMember>& joined() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
+ QHash<QString, RoomMember> joined() const
+ {
+ return loadFromJson<QHash<QString, RoomMember>>("joined"_ls);
+ }
+};
-private:
- class Private;
- QScopedPointer<Private> d;
+template <>
+struct JsonObjectConverter<GetJoinedMembersByRoomJob::RoomMember> {
+ static void fillFrom(const QJsonObject& jo,
+ GetJoinedMembersByRoomJob::RoomMember& result)
+ {
+ fromJson(jo.value("display_name"_ls), result.displayName);
+ fromJson(jo.value("avatar_url"_ls), result.avatarUrl);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/sso_login_redirect.cpp b/lib/csapi/sso_login_redirect.cpp
index 21fe646e..85a18560 100644
--- a/lib/csapi/sso_login_redirect.cpp
+++ b/lib/csapi/sso_login_redirect.cpp
@@ -4,15 +4,11 @@
#include "sso_login_redirect.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-BaseJob::Query queryToRedirectToSSO(const QString& redirectUrl)
+auto queryToRedirectToSSO(const QString& redirectUrl)
{
BaseJob::Query _q;
addParam<>(_q, QStringLiteral("redirectUrl"), redirectUrl);
@@ -22,13 +18,13 @@ BaseJob::Query queryToRedirectToSSO(const QString& redirectUrl)
QUrl RedirectToSSOJob::makeRequestUrl(QUrl baseUrl, const QString& redirectUrl)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/login/sso/redirect",
+ QStringLiteral("/_matrix/client/r0")
+ % "/login/sso/redirect",
queryToRedirectToSSO(redirectUrl));
}
RedirectToSSOJob::RedirectToSSOJob(const QString& redirectUrl)
: BaseJob(HttpVerb::Get, QStringLiteral("RedirectToSSOJob"),
- basePath % "/login/sso/redirect",
+ QStringLiteral("/_matrix/client/r0") % "/login/sso/redirect",
queryToRedirectToSSO(redirectUrl), {}, false)
-
{}
diff --git a/lib/csapi/sso_login_redirect.h b/lib/csapi/sso_login_redirect.h
index 8978c7f7..20f33da2 100644
--- a/lib/csapi/sso_login_redirect.h
+++ b/lib/csapi/sso_login_redirect.h
@@ -8,8 +8,6 @@
namespace Quotient {
-// Operations
-
/*! \brief Redirect the user's browser to the SSO interface.
*
* A web-based Matrix client should instruct the user's browser to
@@ -21,6 +19,7 @@ class RedirectToSSOJob : public BaseJob {
public:
/*! \brief Redirect the user's browser to the SSO interface.
*
+ *
* \param redirectUrl
* URI to which the user will be redirected after the homeserver has
* authenticated the user with SSO.
diff --git a/lib/csapi/tags.cpp b/lib/csapi/tags.cpp
index 0e2d122a..dc22dc18 100644
--- a/lib/csapi/tags.cpp
+++ b/lib/csapi/tags.cpp
@@ -4,82 +4,49 @@
#include "tags.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-// Converters
-namespace Quotient {
-
-template <>
-struct JsonObjectConverter<GetRoomTagsJob::Tag> {
- static void fillFrom(QJsonObject jo, GetRoomTagsJob::Tag& result)
- {
- fromJson(jo.take("order"_ls), result.order);
- fromJson(jo, result.additionalProperties);
- }
-};
-
-} // namespace Quotient
-
-class GetRoomTagsJob::Private {
-public:
- QHash<QString, Tag> tags;
-};
-
QUrl GetRoomTagsJob::makeRequestUrl(QUrl baseUrl, const QString& userId,
const QString& roomId)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/user/"
- % userId % "/rooms/"
- % roomId % "/tags");
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ QStringLiteral("/_matrix/client/r0") % "/user/"
+ % userId % "/rooms/" % roomId % "/tags");
}
GetRoomTagsJob::GetRoomTagsJob(const QString& userId, const QString& roomId)
: BaseJob(HttpVerb::Get, QStringLiteral("GetRoomTagsJob"),
- basePath % "/user/" % userId % "/rooms/" % roomId % "/tags")
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/user/" % userId
+ % "/rooms/" % roomId % "/tags")
{}
-GetRoomTagsJob::~GetRoomTagsJob() = default;
-
-const QHash<QString, GetRoomTagsJob::Tag>& GetRoomTagsJob::tags() const
-{
- return d->tags;
-}
-
-BaseJob::Status GetRoomTagsJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- fromJson(json.value("tags"_ls), d->tags);
-
- return Success;
-}
-
SetRoomTagJob::SetRoomTagJob(const QString& userId, const QString& roomId,
- const QString& tag, Omittable<float> order)
+ const QString& tag, Omittable<float> order,
+ const QVariantHash& additionalProperties)
: BaseJob(HttpVerb::Put, QStringLiteral("SetRoomTagJob"),
- basePath % "/user/" % userId % "/rooms/" % roomId % "/tags/" % tag)
+ QStringLiteral("/_matrix/client/r0") % "/user/" % userId
+ % "/rooms/" % roomId % "/tags/" % tag)
{
QJsonObject _data;
+ fillJson(_data, additionalProperties);
addParam<IfNotEmpty>(_data, QStringLiteral("order"), order);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
QUrl DeleteRoomTagJob::makeRequestUrl(QUrl baseUrl, const QString& userId,
const QString& roomId, const QString& tag)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/user/" % userId % "/rooms/"
- % roomId % "/tags/" % tag);
+ QStringLiteral("/_matrix/client/r0")
+ % "/user/" % userId % "/rooms/" % roomId
+ % "/tags/" % tag);
}
DeleteRoomTagJob::DeleteRoomTagJob(const QString& userId, const QString& roomId,
const QString& tag)
: BaseJob(HttpVerb::Delete, QStringLiteral("DeleteRoomTagJob"),
- basePath % "/user/" % userId % "/rooms/" % roomId % "/tags/" % tag)
+ QStringLiteral("/_matrix/client/r0") % "/user/" % userId
+ % "/rooms/" % roomId % "/tags/" % tag)
{}
diff --git a/lib/csapi/tags.h b/lib/csapi/tags.h
index 1ffb0f81..e6eb9dda 100644
--- a/lib/csapi/tags.h
+++ b/lib/csapi/tags.h
@@ -4,17 +4,10 @@
#pragma once
-#include "converters.h"
-
#include "jobs/basejob.h"
-#include <QtCore/QHash>
-#include <QtCore/QVariant>
-
namespace Quotient {
-// Operations
-
/*! \brief List the tags for a room.
*
* List the tags set by a user on a room.
@@ -36,9 +29,11 @@ public:
/*! \brief List the tags for a room.
*
+ *
* \param userId
* The id of the user to get tags for. The access token must be
* authorized to make requests for this user ID.
+ *
* \param roomId
* The ID of the room to get tags for.
*/
@@ -51,19 +46,23 @@ public:
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId,
const QString& roomId);
- ~GetRoomTagsJob() override;
// Result properties
/// List the tags set by a user on a room.
- const QHash<QString, Tag>& tags() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
+ QHash<QString, Tag> tags() const
+ {
+ return loadFromJson<QHash<QString, Tag>>("tags"_ls);
+ }
+};
-private:
- class Private;
- QScopedPointer<Private> d;
+template <>
+struct JsonObjectConverter<GetRoomTagsJob::Tag> {
+ static void fillFrom(QJsonObject jo, GetRoomTagsJob::Tag& result)
+ {
+ fromJson(jo.take("order"_ls), result.order);
+ fromJson(jo, result.additionalProperties);
+ }
};
/*! \brief Add a tag to a room.
@@ -74,19 +73,27 @@ class SetRoomTagJob : public BaseJob {
public:
/*! \brief Add a tag to a room.
*
+ *
* \param userId
* The id of the user to add a tag for. The access token must be
* authorized to make requests for this user ID.
+ *
* \param roomId
* The ID of the room to add a tag to.
+ *
* \param tag
* The tag to add.
+ *
* \param order
* A number in a range ``[0,1]`` describing a relative
* position of the room under the given tag.
+ *
+ * \param additionalProperties
+ * Add a tag to the room.
*/
explicit SetRoomTagJob(const QString& userId, const QString& roomId,
- const QString& tag, Omittable<float> order = none);
+ const QString& tag, Omittable<float> order = none,
+ const QVariantHash& additionalProperties = {});
};
/*! \brief Remove a tag from the room.
@@ -97,11 +104,14 @@ class DeleteRoomTagJob : public BaseJob {
public:
/*! \brief Remove a tag from the room.
*
+ *
* \param userId
* The id of the user to remove a tag for. The access token must be
* authorized to make requests for this user ID.
+ *
* \param roomId
* The ID of the room to remove a tag from.
+ *
* \param tag
* The tag to remove.
*/
diff --git a/lib/csapi/third_party_lookup.cpp b/lib/csapi/third_party_lookup.cpp
index 9d92e407..baf1fab5 100644
--- a/lib/csapi/third_party_lookup.cpp
+++ b/lib/csapi/third_party_lookup.cpp
@@ -4,83 +4,37 @@
#include "third_party_lookup.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-class GetProtocolsJob::Private {
-public:
- QHash<QString, ThirdPartyProtocol> data;
-};
-
QUrl GetProtocolsJob::makeRequestUrl(QUrl baseUrl)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/thirdparty/protocols");
+ QStringLiteral("/_matrix/client/r0")
+ % "/thirdparty/protocols");
}
GetProtocolsJob::GetProtocolsJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetProtocolsJob"),
- basePath % "/thirdparty/protocols")
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/thirdparty/protocols")
{}
-GetProtocolsJob::~GetProtocolsJob() = default;
-
-const QHash<QString, ThirdPartyProtocol>& GetProtocolsJob::data() const
-{
- return d->data;
-}
-
-BaseJob::Status GetProtocolsJob::parseJson(const QJsonDocument& data)
-{
- fromJson(data, d->data);
-
- return Success;
-}
-
-class GetProtocolMetadataJob::Private {
-public:
- ThirdPartyProtocol data;
-};
-
QUrl GetProtocolMetadataJob::makeRequestUrl(QUrl baseUrl,
const QString& protocol)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/thirdparty/protocol/" % protocol);
+ QStringLiteral("/_matrix/client/r0")
+ % "/thirdparty/protocol/" % protocol);
}
GetProtocolMetadataJob::GetProtocolMetadataJob(const QString& protocol)
: BaseJob(HttpVerb::Get, QStringLiteral("GetProtocolMetadataJob"),
- basePath % "/thirdparty/protocol/" % protocol)
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/thirdparty/protocol/"
+ % protocol)
{}
-GetProtocolMetadataJob::~GetProtocolMetadataJob() = default;
-
-const ThirdPartyProtocol& GetProtocolMetadataJob::data() const
-{
- return d->data;
-}
-
-BaseJob::Status GetProtocolMetadataJob::parseJson(const QJsonDocument& data)
-{
- fromJson(data, d->data);
-
- return Success;
-}
-
-class QueryLocationByProtocolJob::Private {
-public:
- QVector<ThirdPartyLocation> data;
-};
-
-BaseJob::Query queryToQueryLocationByProtocol(const QString& searchFields)
+auto queryToQueryLocationByProtocol(const QString& searchFields)
{
BaseJob::Query _q;
addParam<IfNotEmpty>(_q, QStringLiteral("searchFields"), searchFields);
@@ -92,38 +46,20 @@ QUrl QueryLocationByProtocolJob::makeRequestUrl(QUrl baseUrl,
const QString& searchFields)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/thirdparty/location/" % protocol,
+ QStringLiteral("/_matrix/client/r0")
+ % "/thirdparty/location/" % protocol,
queryToQueryLocationByProtocol(searchFields));
}
QueryLocationByProtocolJob::QueryLocationByProtocolJob(
const QString& protocol, const QString& searchFields)
: BaseJob(HttpVerb::Get, QStringLiteral("QueryLocationByProtocolJob"),
- basePath % "/thirdparty/location/" % protocol,
+ QStringLiteral("/_matrix/client/r0") % "/thirdparty/location/"
+ % protocol,
queryToQueryLocationByProtocol(searchFields))
- , d(new Private)
{}
-QueryLocationByProtocolJob::~QueryLocationByProtocolJob() = default;
-
-const QVector<ThirdPartyLocation>& QueryLocationByProtocolJob::data() const
-{
- return d->data;
-}
-
-BaseJob::Status QueryLocationByProtocolJob::parseJson(const QJsonDocument& data)
-{
- fromJson(data, d->data);
-
- return Success;
-}
-
-class QueryUserByProtocolJob::Private {
-public:
- QVector<ThirdPartyUser> data;
-};
-
-BaseJob::Query queryToQueryUserByProtocol(const QString& fields)
+auto queryToQueryUserByProtocol(const QString& fields)
{
BaseJob::Query _q;
addParam<IfNotEmpty>(_q, QStringLiteral("fields..."), fields);
@@ -135,38 +71,20 @@ QUrl QueryUserByProtocolJob::makeRequestUrl(QUrl baseUrl,
const QString& fields)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/thirdparty/user/" % protocol,
+ QStringLiteral("/_matrix/client/r0")
+ % "/thirdparty/user/" % protocol,
queryToQueryUserByProtocol(fields));
}
QueryUserByProtocolJob::QueryUserByProtocolJob(const QString& protocol,
const QString& fields)
: BaseJob(HttpVerb::Get, QStringLiteral("QueryUserByProtocolJob"),
- basePath % "/thirdparty/user/" % protocol,
+ QStringLiteral("/_matrix/client/r0") % "/thirdparty/user/"
+ % protocol,
queryToQueryUserByProtocol(fields))
- , d(new Private)
{}
-QueryUserByProtocolJob::~QueryUserByProtocolJob() = default;
-
-const QVector<ThirdPartyUser>& QueryUserByProtocolJob::data() const
-{
- return d->data;
-}
-
-BaseJob::Status QueryUserByProtocolJob::parseJson(const QJsonDocument& data)
-{
- fromJson(data, d->data);
-
- return Success;
-}
-
-class QueryLocationByAliasJob::Private {
-public:
- QVector<ThirdPartyLocation> data;
-};
-
-BaseJob::Query queryToQueryLocationByAlias(const QString& alias)
+auto queryToQueryLocationByAlias(const QString& alias)
{
BaseJob::Query _q;
addParam<>(_q, QStringLiteral("alias"), alias);
@@ -176,37 +94,18 @@ BaseJob::Query queryToQueryLocationByAlias(const QString& alias)
QUrl QueryLocationByAliasJob::makeRequestUrl(QUrl baseUrl, const QString& alias)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/thirdparty/location",
+ QStringLiteral("/_matrix/client/r0")
+ % "/thirdparty/location",
queryToQueryLocationByAlias(alias));
}
QueryLocationByAliasJob::QueryLocationByAliasJob(const QString& alias)
: BaseJob(HttpVerb::Get, QStringLiteral("QueryLocationByAliasJob"),
- basePath % "/thirdparty/location",
+ QStringLiteral("/_matrix/client/r0") % "/thirdparty/location",
queryToQueryLocationByAlias(alias))
- , d(new Private)
{}
-QueryLocationByAliasJob::~QueryLocationByAliasJob() = default;
-
-const QVector<ThirdPartyLocation>& QueryLocationByAliasJob::data() const
-{
- return d->data;
-}
-
-BaseJob::Status QueryLocationByAliasJob::parseJson(const QJsonDocument& data)
-{
- fromJson(data, d->data);
-
- return Success;
-}
-
-class QueryUserByIDJob::Private {
-public:
- QVector<ThirdPartyUser> data;
-};
-
-BaseJob::Query queryToQueryUserByID(const QString& userid)
+auto queryToQueryUserByID(const QString& userid)
{
BaseJob::Query _q;
addParam<>(_q, QStringLiteral("userid"), userid);
@@ -216,26 +115,13 @@ BaseJob::Query queryToQueryUserByID(const QString& userid)
QUrl QueryUserByIDJob::makeRequestUrl(QUrl baseUrl, const QString& userid)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/thirdparty/user",
+ QStringLiteral("/_matrix/client/r0")
+ % "/thirdparty/user",
queryToQueryUserByID(userid));
}
QueryUserByIDJob::QueryUserByIDJob(const QString& userid)
: BaseJob(HttpVerb::Get, QStringLiteral("QueryUserByIDJob"),
- basePath % "/thirdparty/user", queryToQueryUserByID(userid))
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/thirdparty/user",
+ queryToQueryUserByID(userid))
{}
-
-QueryUserByIDJob::~QueryUserByIDJob() = default;
-
-const QVector<ThirdPartyUser>& QueryUserByIDJob::data() const
-{
- return d->data;
-}
-
-BaseJob::Status QueryUserByIDJob::parseJson(const QJsonDocument& data)
-{
- fromJson(data, d->data);
-
- return Success;
-}
diff --git a/lib/csapi/third_party_lookup.h b/lib/csapi/third_party_lookup.h
index c8ca8cbb..9329b7a7 100644
--- a/lib/csapi/third_party_lookup.h
+++ b/lib/csapi/third_party_lookup.h
@@ -4,21 +4,14 @@
#pragma once
-#include "converters.h"
-
#include "csapi/../application-service/definitions/location.h"
#include "csapi/../application-service/definitions/protocol.h"
#include "csapi/../application-service/definitions/user.h"
#include "jobs/basejob.h"
-#include <QtCore/QHash>
-#include <QtCore/QVector>
-
namespace Quotient {
-// Operations
-
/*! \brief Retrieve metadata about all protocols that a homeserver supports.
*
* Fetches the overall metadata about protocols supported by the
@@ -36,19 +29,14 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl);
- ~GetProtocolsJob() override;
// Result properties
/// The protocols supported by the homeserver.
- const QHash<QString, ThirdPartyProtocol>& data() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QHash<QString, ThirdPartyProtocol> data() const
+ {
+ return fromJson<QHash<QString, ThirdPartyProtocol>>(jsonData());
+ }
};
/*! \brief Retrieve metadata about a specific protocol that the homeserver
@@ -62,6 +50,7 @@ public:
/*! \brief Retrieve metadata about a specific protocol that the homeserver
* supports.
*
+ *
* \param protocol
* The name of the protocol.
*/
@@ -73,19 +62,14 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& protocol);
- ~GetProtocolMetadataJob() override;
// Result properties
/// The protocol was found and metadata returned.
- const ThirdPartyProtocol& data() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ ThirdPartyProtocol data() const
+ {
+ return fromJson<ThirdPartyProtocol>(jsonData());
+ }
};
/*! \brief Retrieve Matrix-side portals rooms leading to a third party location.
@@ -104,8 +88,10 @@ public:
/*! \brief Retrieve Matrix-side portals rooms leading to a third party
* location.
*
+ *
* \param protocol
* The protocol used to communicate to the third party network.
+ *
* \param searchFields
* One or more custom fields to help identify the third party
* location.
@@ -120,19 +106,14 @@ public:
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& protocol,
const QString& searchFields = {});
- ~QueryLocationByProtocolJob() override;
// Result properties
/// At least one portal room was found.
- const QVector<ThirdPartyLocation>& data() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QVector<ThirdPartyLocation> data() const
+ {
+ return fromJson<QVector<ThirdPartyLocation>>(jsonData());
+ }
};
/*! \brief Retrieve the Matrix User ID of a corresponding third party user.
@@ -144,8 +125,10 @@ class QueryUserByProtocolJob : public BaseJob {
public:
/*! \brief Retrieve the Matrix User ID of a corresponding third party user.
*
+ *
* \param protocol
* The name of the protocol.
+ *
* \param fields
* One or more custom fields that are passed to the AS to help identify
* the user.
@@ -160,19 +143,14 @@ public:
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& protocol,
const QString& fields = {});
- ~QueryUserByProtocolJob() override;
// Result properties
/// The Matrix User IDs found with the given parameters.
- const QVector<ThirdPartyUser>& data() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QVector<ThirdPartyUser> data() const
+ {
+ return fromJson<QVector<ThirdPartyUser>>(jsonData());
+ }
};
/*! \brief Reverse-lookup third party locations given a Matrix room alias.
@@ -184,6 +162,7 @@ class QueryLocationByAliasJob : public BaseJob {
public:
/*! \brief Reverse-lookup third party locations given a Matrix room alias.
*
+ *
* \param alias
* The Matrix room alias to look up.
*/
@@ -195,19 +174,14 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& alias);
- ~QueryLocationByAliasJob() override;
// Result properties
/// All found third party locations.
- const QVector<ThirdPartyLocation>& data() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QVector<ThirdPartyLocation> data() const
+ {
+ return fromJson<QVector<ThirdPartyLocation>>(jsonData());
+ }
};
/*! \brief Reverse-lookup third party users given a Matrix User ID.
@@ -218,6 +192,7 @@ class QueryUserByIDJob : public BaseJob {
public:
/*! \brief Reverse-lookup third party users given a Matrix User ID.
*
+ *
* \param userid
* The Matrix User ID to look up.
*/
@@ -229,19 +204,14 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl, const QString& userid);
- ~QueryUserByIDJob() override;
// Result properties
/// An array of third party users.
- const QVector<ThirdPartyUser>& data() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QVector<ThirdPartyUser> data() const
+ {
+ return fromJson<QVector<ThirdPartyUser>>(jsonData());
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/third_party_membership.cpp b/lib/csapi/third_party_membership.cpp
index 15da6b3c..fda772d2 100644
--- a/lib/csapi/third_party_membership.cpp
+++ b/lib/csapi/third_party_membership.cpp
@@ -4,22 +4,21 @@
#include "third_party_membership.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
InviteBy3PIDJob::InviteBy3PIDJob(const QString& roomId, const QString& idServer,
+ const QString& idAccessToken,
const QString& medium, const QString& address)
: BaseJob(HttpVerb::Post, QStringLiteral("InviteBy3PIDJob"),
- basePath % "/rooms/" % roomId % "/invite")
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/invite")
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("id_server"), idServer);
+ addParam<>(_data, QStringLiteral("id_access_token"), idAccessToken);
addParam<>(_data, QStringLiteral("medium"), medium);
addParam<>(_data, QStringLiteral("address"), address);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
diff --git a/lib/csapi/third_party_membership.h b/lib/csapi/third_party_membership.h
index c85e8ab4..f8196f6f 100644
--- a/lib/csapi/third_party_membership.h
+++ b/lib/csapi/third_party_membership.h
@@ -8,8 +8,6 @@
namespace Quotient {
-// Operations
-
/*! \brief Invite a user to participate in a particular room.
*
* .. _invite-by-third-party-id-endpoint:
@@ -61,15 +59,28 @@ class InviteBy3PIDJob : public BaseJob {
public:
/*! \brief Invite a user to participate in a particular room.
*
+ *
* \param roomId
* The room identifier (not alias) to which to invite the user.
+ *
* \param idServer
* The hostname+port of the identity server which should be used for third
- * party identifier lookups. \param medium The kind of address being passed
- * in the address field, for example ``email``. \param address The invitee's
- * third party identifier.
+ * party identifier lookups.
+ *
+ * \param idAccessToken
+ * An access token previously registered with the identity server. Servers
+ * can treat this as optional to distinguish between r0.5-compatible
+ * clients and this specification version.
+ *
+ * \param medium
+ * The kind of address being passed in the address field, for example
+ * ``email``.
+ *
+ * \param address
+ * The invitee's third party identifier.
*/
explicit InviteBy3PIDJob(const QString& roomId, const QString& idServer,
+ const QString& idAccessToken,
const QString& medium, const QString& address);
};
diff --git a/lib/csapi/to_device.cpp b/lib/csapi/to_device.cpp
index e277503c..28c4115a 100644
--- a/lib/csapi/to_device.cpp
+++ b/lib/csapi/to_device.cpp
@@ -4,21 +4,18 @@
#include "to_device.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
SendToDeviceJob::SendToDeviceJob(
const QString& eventType, const QString& txnId,
const QHash<QString, QHash<QString, QJsonObject>>& messages)
: BaseJob(HttpVerb::Put, QStringLiteral("SendToDeviceJob"),
- basePath % "/sendToDevice/" % eventType % "/" % txnId)
+ QStringLiteral("/_matrix/client/r0") % "/sendToDevice/"
+ % eventType % "/" % txnId)
{
QJsonObject _data;
addParam<IfNotEmpty>(_data, QStringLiteral("messages"), messages);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
diff --git a/lib/csapi/to_device.h b/lib/csapi/to_device.h
index 48f0ec83..8c82af45 100644
--- a/lib/csapi/to_device.h
+++ b/lib/csapi/to_device.h
@@ -6,13 +6,8 @@
#include "jobs/basejob.h"
-#include <QtCore/QHash>
-#include <QtCore/QJsonObject>
-
namespace Quotient {
-// Operations
-
/*! \brief Send an event to a given set of devices.
*
* This endpoint is used to send send-to-device events to a set of
@@ -22,12 +17,15 @@ class SendToDeviceJob : public BaseJob {
public:
/*! \brief Send an event to a given set of devices.
*
+ *
* \param eventType
* The type of event to send.
+ *
* \param txnId
* The transaction ID for this event. Clients should generate an
* ID unique across requests with the same access token; it will be
* used by the server to ensure idempotency of requests.
+ *
* \param messages
* The messages to send. A map from user ID, to a map from
* device ID to message body. The device ID may also be `*`,
diff --git a/lib/csapi/typing.cpp b/lib/csapi/typing.cpp
index 261622c4..8e214053 100644
--- a/lib/csapi/typing.cpp
+++ b/lib/csapi/typing.cpp
@@ -4,21 +4,18 @@
#include "typing.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
SetTypingJob::SetTypingJob(const QString& userId, const QString& roomId,
bool typing, Omittable<int> timeout)
: BaseJob(HttpVerb::Put, QStringLiteral("SetTypingJob"),
- basePath % "/rooms/" % roomId % "/typing/" % userId)
+ QStringLiteral("/_matrix/client/r0") % "/rooms/" % roomId
+ % "/typing/" % userId)
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("typing"), typing);
addParam<IfNotEmpty>(_data, QStringLiteral("timeout"), timeout);
- setRequestData(_data);
+ setRequestData(std::move(_data));
}
diff --git a/lib/csapi/typing.h b/lib/csapi/typing.h
index dbf17a3e..f5b67baf 100644
--- a/lib/csapi/typing.h
+++ b/lib/csapi/typing.h
@@ -4,14 +4,10 @@
#pragma once
-#include "converters.h"
-
#include "jobs/basejob.h"
namespace Quotient {
-// Operations
-
/*! \brief Informs the server that the user has started or stopped typing.
*
* This tells the server that the user is typing for the next N
@@ -23,13 +19,17 @@ class SetTypingJob : public BaseJob {
public:
/*! \brief Informs the server that the user has started or stopped typing.
*
+ *
* \param userId
* The user who has started to type.
+ *
* \param roomId
* The room in which the user is typing.
+ *
* \param typing
* Whether the user is typing or not. If ``false``, the ``timeout``
* key can be omitted.
+ *
* \param timeout
* The length of time in milliseconds to mark this user as typing.
*/
diff --git a/lib/csapi/users.cpp b/lib/csapi/users.cpp
index 5d2a6133..a0279d7e 100644
--- a/lib/csapi/users.cpp
+++ b/lib/csapi/users.cpp
@@ -4,68 +4,19 @@
#include "users.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-// Converters
-namespace Quotient {
-
-template <>
-struct JsonObjectConverter<SearchUserDirectoryJob::User> {
- static void fillFrom(const QJsonObject& jo,
- SearchUserDirectoryJob::User& 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 Quotient
-
-class SearchUserDirectoryJob::Private {
-public:
- QVector<User> results;
- bool limited;
-};
-
SearchUserDirectoryJob::SearchUserDirectoryJob(const QString& searchTerm,
Omittable<int> limit)
: BaseJob(HttpVerb::Post, QStringLiteral("SearchUserDirectoryJob"),
- basePath % "/user_directory/search")
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/user_directory/search")
{
QJsonObject _data;
addParam<>(_data, QStringLiteral("search_term"), searchTerm);
addParam<IfNotEmpty>(_data, QStringLiteral("limit"), limit);
- setRequestData(_data);
-}
-
-SearchUserDirectoryJob::~SearchUserDirectoryJob() = default;
-
-const QVector<SearchUserDirectoryJob::User>& SearchUserDirectoryJob::results() const
-{
- return d->results;
-}
-
-bool SearchUserDirectoryJob::limited() const { return d->limited; }
-
-BaseJob::Status SearchUserDirectoryJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- if (!json.contains("results"_ls))
- return { IncorrectResponse,
- "The key 'results' not found in the response" };
- fromJson(json.value("results"_ls), d->results);
- if (!json.contains("limited"_ls))
- return { IncorrectResponse,
- "The key 'limited' not found in the response" };
- fromJson(json.value("limited"_ls), d->limited);
-
- return Success;
+ setRequestData(std::move(_data));
+ addExpectedKey("results");
+ addExpectedKey("limited");
}
diff --git a/lib/csapi/users.h b/lib/csapi/users.h
index de4eb529..adb2a33d 100644
--- a/lib/csapi/users.h
+++ b/lib/csapi/users.h
@@ -4,19 +4,13 @@
#pragma once
-#include "converters.h"
-
#include "jobs/basejob.h"
-#include <QtCore/QVector>
-
namespace Quotient {
-// Operations
-
/*! \brief Searches the user directory.
*
- * Performs a search for users on the homeserver. The homeserver may
+ * Performs a search for users. The homeserver may
* determine which subset of users are searched, however the homeserver
* MUST at a minimum consider the users the requesting user shares a
* room with and those who reside in public rooms (known to the homeserver).
@@ -31,7 +25,7 @@ class SearchUserDirectoryJob : public BaseJob {
public:
// Inner data structures
- /// Performs a search for users on the homeserver. The homeserver may
+ /// Performs a search for users. The homeserver may
/// determine which subset of users are searched, however the homeserver
/// MUST at a minimum consider the users the requesting user shares a
/// room with and those who reside in public rooms (known to the
@@ -41,7 +35,7 @@ public:
/// The search is performed case-insensitively on user IDs and display
/// names preferably using a collation determined based upon the
/// ``Accept-Language`` header provided in the request, if present.
- struct User {
+ struct SearchUserDirectory200ThirdPartyUser {
/// The user's matrix user ID.
QString userId;
/// The display name of the user, if one exists.
@@ -54,30 +48,40 @@ public:
/*! \brief Searches the user directory.
*
+ *
* \param searchTerm
* The term to search for
+ *
* \param limit
* The maximum number of results to return. Defaults to 10.
*/
explicit SearchUserDirectoryJob(const QString& searchTerm,
Omittable<int> limit = none);
- ~SearchUserDirectoryJob() override;
-
// Result properties
/// Ordered by rank and then whether or not profile info is available.
- const QVector<User>& results() const;
+ QVector<SearchUserDirectory200ThirdPartyUser> results() const
+ {
+ return loadFromJson<QVector<SearchUserDirectory200ThirdPartyUser>>(
+ "results"_ls);
+ }
/// Indicates if the result list has been truncated by the limit.
- bool limited() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
+ bool limited() const { return loadFromJson<bool>("limited"_ls); }
+};
-private:
- class Private;
- QScopedPointer<Private> d;
+template <>
+struct JsonObjectConverter<
+ SearchUserDirectoryJob::SearchUserDirectory200ThirdPartyUser> {
+ static void
+ fillFrom(const QJsonObject& jo,
+ SearchUserDirectoryJob::SearchUserDirectory200ThirdPartyUser& 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 Quotient
diff --git a/lib/csapi/versions.cpp b/lib/csapi/versions.cpp
index 8cce03b9..9003e27f 100644
--- a/lib/csapi/versions.cpp
+++ b/lib/csapi/versions.cpp
@@ -4,48 +4,20 @@
#include "versions.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client");
-
-class GetVersionsJob::Private {
-public:
- QStringList versions;
- QHash<QString, bool> unstableFeatures;
-};
-
QUrl GetVersionsJob::makeRequestUrl(QUrl baseUrl)
{
- return BaseJob::makeRequestUrl(std::move(baseUrl), basePath % "/versions");
+ return BaseJob::makeRequestUrl(std::move(baseUrl),
+ QStringLiteral("/_matrix/client")
+ % "/versions");
}
GetVersionsJob::GetVersionsJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetVersionsJob"),
- basePath % "/versions", false)
- , d(new Private)
-{}
-
-GetVersionsJob::~GetVersionsJob() = default;
-
-const QStringList& GetVersionsJob::versions() const { return d->versions; }
-
-const QHash<QString, bool>& GetVersionsJob::unstableFeatures() const
+ QStringLiteral("/_matrix/client") % "/versions", false)
{
- return d->unstableFeatures;
-}
-
-BaseJob::Status GetVersionsJob::parseJson(const QJsonDocument& data)
-{
- auto json = data.object();
- if (!json.contains("versions"_ls))
- return { IncorrectResponse,
- "The key 'versions' not found in the response" };
- fromJson(json.value("versions"_ls), d->versions);
- fromJson(json.value("unstable_features"_ls), d->unstableFeatures);
-
- return Success;
+ addExpectedKey("versions");
}
diff --git a/lib/csapi/versions.h b/lib/csapi/versions.h
index 4c4f8109..828a7eb9 100644
--- a/lib/csapi/versions.h
+++ b/lib/csapi/versions.h
@@ -4,16 +4,10 @@
#pragma once
-#include "converters.h"
-
#include "jobs/basejob.h"
-#include <QtCore/QHash>
-
namespace Quotient {
-// Operations
-
/*! \brief Gets the versions of the specification supported by the server.
*
* Gets the versions of the specification supported by the server.
@@ -48,24 +42,22 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl);
- ~GetVersionsJob() override;
// Result properties
/// The supported versions.
- const QStringList& versions() const;
+ QStringList versions() const
+ {
+ return loadFromJson<QStringList>("versions"_ls);
+ }
/// Experimental features the server supports. Features not listed here,
/// or the lack of this property all together, indicate that a feature is
/// not supported.
- const QHash<QString, bool>& unstableFeatures() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QHash<QString, bool> unstableFeatures() const
+ {
+ return loadFromJson<QHash<QString, bool>>("unstable_features"_ls);
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/voip.cpp b/lib/csapi/voip.cpp
index c98824b3..43170057 100644
--- a/lib/csapi/voip.cpp
+++ b/lib/csapi/voip.cpp
@@ -4,38 +4,18 @@
#include "voip.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-class GetTurnServerJob::Private {
-public:
- QJsonObject data;
-};
-
QUrl GetTurnServerJob::makeRequestUrl(QUrl baseUrl)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/voip/turnServer");
+ QStringLiteral("/_matrix/client/r0")
+ % "/voip/turnServer");
}
GetTurnServerJob::GetTurnServerJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetTurnServerJob"),
- basePath % "/voip/turnServer")
- , d(new Private)
+ QStringLiteral("/_matrix/client/r0") % "/voip/turnServer")
{}
-
-GetTurnServerJob::~GetTurnServerJob() = default;
-
-const QJsonObject& GetTurnServerJob::data() const { return d->data; }
-
-BaseJob::Status GetTurnServerJob::parseJson(const QJsonDocument& data)
-{
- fromJson(data, d->data);
-
- return Success;
-}
diff --git a/lib/csapi/voip.h b/lib/csapi/voip.h
index d3eb3c4b..087ebbbd 100644
--- a/lib/csapi/voip.h
+++ b/lib/csapi/voip.h
@@ -6,12 +6,8 @@
#include "jobs/basejob.h"
-#include <QtCore/QJsonObject>
-
namespace Quotient {
-// Operations
-
/*! \brief Obtain TURN server credentials.
*
* This API provides credentials for the client to use when initiating
@@ -28,19 +24,11 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl);
- ~GetTurnServerJob() override;
// Result properties
/// The TURN server credentials.
- const QJsonObject& data() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QJsonObject data() const { return fromJson<QJsonObject>(jsonData()); }
};
} // namespace Quotient
diff --git a/lib/csapi/wellknown.cpp b/lib/csapi/wellknown.cpp
index 464068e7..1aa0a90b 100644
--- a/lib/csapi/wellknown.cpp
+++ b/lib/csapi/wellknown.cpp
@@ -4,38 +4,18 @@
#include "wellknown.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/.well-known");
-
-class GetWellknownJob::Private {
-public:
- DiscoveryInformation data;
-};
-
QUrl GetWellknownJob::makeRequestUrl(QUrl baseUrl)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/matrix/client");
+ QStringLiteral("/.well-known")
+ % "/matrix/client");
}
GetWellknownJob::GetWellknownJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetWellknownJob"),
- basePath % "/matrix/client", false)
- , d(new Private)
+ QStringLiteral("/.well-known") % "/matrix/client", false)
{}
-
-GetWellknownJob::~GetWellknownJob() = default;
-
-const DiscoveryInformation& GetWellknownJob::data() const { return d->data; }
-
-BaseJob::Status GetWellknownJob::parseJson(const QJsonDocument& data)
-{
- fromJson(data, d->data);
-
- return Success;
-}
diff --git a/lib/csapi/wellknown.h b/lib/csapi/wellknown.h
index 94d3631c..b21d9fc7 100644
--- a/lib/csapi/wellknown.h
+++ b/lib/csapi/wellknown.h
@@ -4,16 +4,12 @@
#pragma once
-#include "converters.h"
-
#include "csapi/definitions/wellknown/full.h"
#include "jobs/basejob.h"
namespace Quotient {
-// Operations
-
/*! \brief Gets Matrix server discovery information about the domain.
*
* Gets discovery information about the domain. The file may include
@@ -36,19 +32,14 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl);
- ~GetWellknownJob() override;
// Result properties
/// Server discovery information.
- const DiscoveryInformation& data() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ DiscoveryInformation data() const
+ {
+ return fromJson<DiscoveryInformation>(jsonData());
+ }
};
} // namespace Quotient
diff --git a/lib/csapi/whoami.cpp b/lib/csapi/whoami.cpp
index 8d4681e4..73f0298e 100644
--- a/lib/csapi/whoami.cpp
+++ b/lib/csapi/whoami.cpp
@@ -4,42 +4,20 @@
#include "whoami.h"
-#include "converters.h"
-
#include <QtCore/QStringBuilder>
using namespace Quotient;
-static const auto basePath = QStringLiteral("/_matrix/client/r0");
-
-class GetTokenOwnerJob::Private {
-public:
- QString userId;
-};
-
QUrl GetTokenOwnerJob::makeRequestUrl(QUrl baseUrl)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
- basePath % "/account/whoami");
+ QStringLiteral("/_matrix/client/r0")
+ % "/account/whoami");
}
GetTokenOwnerJob::GetTokenOwnerJob()
: BaseJob(HttpVerb::Get, QStringLiteral("GetTokenOwnerJob"),
- basePath % "/account/whoami")
- , d(new Private)
-{}
-
-GetTokenOwnerJob::~GetTokenOwnerJob() = default;
-
-const QString& GetTokenOwnerJob::userId() const { return d->userId; }
-
-BaseJob::Status GetTokenOwnerJob::parseJson(const QJsonDocument& data)
+ QStringLiteral("/_matrix/client/r0") % "/account/whoami")
{
- auto json = data.object();
- if (!json.contains("user_id"_ls))
- return { IncorrectResponse,
- "The key 'user_id' not found in the response" };
- fromJson(json.value("user_id"_ls), d->userId);
-
- return Success;
+ addExpectedKey("user_id");
}
diff --git a/lib/csapi/whoami.h b/lib/csapi/whoami.h
index dda8d8c8..af8f1e8a 100644
--- a/lib/csapi/whoami.h
+++ b/lib/csapi/whoami.h
@@ -8,8 +8,6 @@
namespace Quotient {
-// Operations
-
/*! \brief Gets information about the owner of an access token.
*
* Gets information about the owner of a given access token.
@@ -32,19 +30,11 @@ public:
* is necessary but the job itself isn't.
*/
static QUrl makeRequestUrl(QUrl baseUrl);
- ~GetTokenOwnerJob() override;
// Result properties
/// The user id that owns the access token.
- const QString& userId() const;
-
-protected:
- Status parseJson(const QJsonDocument& data) override;
-
-private:
- class Private;
- QScopedPointer<Private> d;
+ QString userId() const { return loadFromJson<QString>("user_id"_ls); }
};
} // namespace Quotient
diff --git a/lib/encryptionmanager.cpp b/lib/encryptionmanager.cpp
index 0895fae9..c50459f3 100644
--- a/lib/encryptionmanager.cpp
+++ b/lib/encryptionmanager.cpp
@@ -89,13 +89,11 @@ public:
// A map from senderKey to InboundSession
QMap<QString, InboundSession*> sessions; // TODO: cache
void updateDeviceKeys(
- const QHash<QString, QHash<QString, QueryKeysJob::DeviceInformation>>&
- deviceKeys)
+ const QHash<QString, QHash<QString, QueryKeysJob::DeviceKeys>>& deviceKeys)
{
for (auto userId : deviceKeys.keys()) {
for (auto deviceId : deviceKeys.value(userId).keys()) {
- QueryKeysJob::DeviceInformation info =
- deviceKeys.value(userId).value(deviceId);
+ auto info = deviceKeys.value(userId).value(deviceId);
// TODO: ed25519Verify, etc
}
}
diff --git a/lib/identity/definitions/request_email_validation.cpp b/lib/identity/definitions/request_email_validation.cpp
deleted file mode 100644
index 22cb0072..00000000
--- a/lib/identity/definitions/request_email_validation.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#include "request_email_validation.h"
-
-using namespace Quotient;
-
-void JsonObjectConverter<RequestEmailValidation>::dumpTo(
- QJsonObject& jo, const RequestEmailValidation& pod)
-{
- 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);
-}
-
-void JsonObjectConverter<RequestEmailValidation>::fillFrom(
- const QJsonObject& jo, RequestEmailValidation& 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 32c6eaaf..079da953 100644
--- a/lib/identity/definitions/request_email_validation.h
+++ b/lib/identity/definitions/request_email_validation.h
@@ -8,8 +8,6 @@
namespace Quotient {
-// Data structures
-
struct RequestEmailValidation {
/// A unique string generated by the client, and used to identify the
/// validation attempt. It must be a string consisting of the characters
@@ -26,18 +24,32 @@ struct RequestEmailValidation {
/// avoid repeatedly sending the same email in the case of request
/// retries between the POSTing user and the identity server.
/// The client should increment this value if they desire a new
- /// email (e.g. a reminder) to be sent.
+ /// email (e.g. a reminder) to be sent. If they do not, the server
+ /// should respond with success but not resend the email.
int sendAttempt;
- /// Optional. When the validation is completed, the identity
- /// server will redirect the user to this URL.
+ /// Optional. When the validation is completed, the identity server will
+ /// redirect the user to this URL. This option is ignored when submitting
+ /// 3PID validation information through a POST request.
QString nextLink;
};
template <>
struct JsonObjectConverter<RequestEmailValidation> {
- static void dumpTo(QJsonObject& jo, const RequestEmailValidation& pod);
- static void fillFrom(const QJsonObject& jo, RequestEmailValidation& pod);
+ static void dumpTo(QJsonObject& jo, const RequestEmailValidation& pod)
+ {
+ 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);
+ }
+ static void fillFrom(const QJsonObject& jo, RequestEmailValidation& pod)
+ {
+ fromJson(jo.value("client_secret"_ls), pod.clientSecret);
+ fromJson(jo.value("email"_ls), pod.email);
+ fromJson(jo.value("send_attempt"_ls), pod.sendAttempt);
+ fromJson(jo.value("next_link"_ls), pod.nextLink);
+ }
};
} // namespace Quotient
diff --git a/lib/identity/definitions/request_msisdn_validation.cpp b/lib/identity/definitions/request_msisdn_validation.cpp
deleted file mode 100644
index 6024bf61..00000000
--- a/lib/identity/definitions/request_msisdn_validation.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#include "request_msisdn_validation.h"
-
-using namespace Quotient;
-
-void JsonObjectConverter<RequestMsisdnValidation>::dumpTo(
- QJsonObject& jo, const RequestMsisdnValidation& pod)
-{
- 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);
-}
-
-void JsonObjectConverter<RequestMsisdnValidation>::fillFrom(
- const QJsonObject& jo, RequestMsisdnValidation& 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 90aed7b8..a29fd0de 100644
--- a/lib/identity/definitions/request_msisdn_validation.h
+++ b/lib/identity/definitions/request_msisdn_validation.h
@@ -8,8 +8,6 @@
namespace Quotient {
-// Data structures
-
struct RequestMsisdnValidation {
/// A unique string generated by the client, and used to identify the
/// validation attempt. It must be a string consisting of the characters
@@ -17,8 +15,8 @@ struct RequestMsisdnValidation {
/// must not be empty.
QString clientSecret;
- /// The two-letter uppercase ISO country code that the number in
- /// ``phone_number`` should be parsed as if it were dialled from.
+ /// The two-letter uppercase ISO-3166-1 alpha-2 country code that the
+ /// number in ``phone_number`` should be parsed as if it were dialled from.
QString country;
/// The phone number to validate.
@@ -33,15 +31,30 @@ struct RequestMsisdnValidation {
/// they desire a new SMS (e.g. a reminder) to be sent.
int sendAttempt;
- /// Optional. When the validation is completed, the identity
- /// server will redirect the user to this URL.
+ /// Optional. When the validation is completed, the identity server will
+ /// redirect the user to this URL. This option is ignored when submitting
+ /// 3PID validation information through a POST request.
QString nextLink;
};
template <>
struct JsonObjectConverter<RequestMsisdnValidation> {
- static void dumpTo(QJsonObject& jo, const RequestMsisdnValidation& pod);
- static void fillFrom(const QJsonObject& jo, RequestMsisdnValidation& pod);
+ static void dumpTo(QJsonObject& jo, const RequestMsisdnValidation& pod)
+ {
+ 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);
+ }
+ static void fillFrom(const QJsonObject& jo, RequestMsisdnValidation& pod)
+ {
+ fromJson(jo.value("client_secret"_ls), pod.clientSecret);
+ fromJson(jo.value("country"_ls), pod.country);
+ fromJson(jo.value("phone_number"_ls), pod.phoneNumber);
+ fromJson(jo.value("send_attempt"_ls), pod.sendAttempt);
+ fromJson(jo.value("next_link"_ls), pod.nextLink);
+ }
};
} // namespace Quotient
diff --git a/lib/identity/definitions/sid.cpp b/lib/identity/definitions/sid.cpp
deleted file mode 100644
index 99fe9b59..00000000
--- a/lib/identity/definitions/sid.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#include "sid.h"
-
-using namespace Quotient;
-
-void JsonObjectConverter<Sid>::dumpTo(QJsonObject& jo, const Sid& pod)
-{
- addParam<>(jo, QStringLiteral("sid"), pod.sid);
-}
-
-void JsonObjectConverter<Sid>::fillFrom(const QJsonObject& jo, Sid& result)
-{
- fromJson(jo.value("sid"_ls), result.sid);
-}
diff --git a/lib/identity/definitions/sid.h b/lib/identity/definitions/sid.h
deleted file mode 100644
index 981826f6..00000000
--- a/lib/identity/definitions/sid.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/******************************************************************************
- * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
- */
-
-#pragma once
-
-#include "converters.h"
-
-namespace Quotient {
-
-// Data structures
-
-struct Sid {
- /// The session ID. Session IDs are opaque strings generated by the identity
- /// server. They must consist entirely of the characters
- /// ``[0-9a-zA-Z.=_-]``. Their length must not exceed 255 characters and
- /// they must not be empty.
- QString sid;
-};
-
-template <>
-struct JsonObjectConverter<Sid> {
- static void dumpTo(QJsonObject& jo, const Sid& pod);
- static void fillFrom(const QJsonObject& jo, Sid& pod);
-};
-
-} // namespace Quotient
diff --git a/lib/jobs/basejob.cpp b/lib/jobs/basejob.cpp
index 2519713e..3978dbcb 100644
--- a/lib/jobs/basejob.cpp
+++ b/lib/jobs/basejob.cpp
@@ -19,12 +19,11 @@
#include "basejob.h"
#include "connectiondata.h"
-#include "util.h"
-#include <QtCore/QJsonObject>
#include <QtCore/QRegularExpression>
#include <QtCore/QTimer>
#include <QtCore/QStringBuilder>
+#include <QtCore/QMetaEnum>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>
@@ -37,6 +36,7 @@ using namespace std::chrono_literals;
BaseJob::StatusCode BaseJob::Status::fromHttpCode(int httpCode)
{
+ // Based on https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
if (httpCode / 10 == 41) // 41x errors
return httpCode == 410 ? IncorrectRequestError : NotFoundError;
switch (httpCode) {
@@ -113,6 +113,13 @@ public:
}
void sendRequest();
+ /*! \brief Parse the response byte array into JSON
+ *
+ * This calls QJsonDocument::fromJson() on rawResponse, converts
+ * the QJsonParseError result to BaseJob::Status and stores the resulting
+ * JSON in jsonResponse.
+ */
+ Status parseJson();
ConnectionData* connection = nullptr;
@@ -131,9 +138,17 @@ public:
// type QMimeType is of little help with MIME type globs (`text/*` etc.)
QByteArrayList expectedContentTypes { "application/json" };
+ QByteArrayList expectedKeys;
+
QScopedPointer<QNetworkReply, NetworkReplyDeleter> reply;
Status status = Unprepared;
QByteArray rawResponse;
+ /// Contains a null document in case of non-JSON body (for a successful
+ /// or unsuccessful response); a document with QJsonObject or QJsonArray
+ /// in case of a successful response with JSON payload, as per the API
+ /// definition (including an empty JSON object - QJsonObject{});
+ /// and QJsonObject in case of an API error.
+ QJsonDocument jsonResponse;
QUrl errorUrl; //< May contain a URL to help with some errors
LoggingCategory logCat = JOBS;
@@ -243,6 +258,19 @@ void BaseJob::setExpectedContentTypes(const QByteArrayList& contentTypes)
d->expectedContentTypes = contentTypes;
}
+const QByteArrayList BaseJob::expectedKeys() const { return d->expectedKeys; }
+
+void BaseJob::addExpectedKey(const QByteArray& key) { d->expectedKeys << key; }
+
+void BaseJob::setExpectedKeys(const QByteArrayList& keys)
+{
+ d->expectedKeys = keys;
+}
+
+const QNetworkReply* BaseJob::reply() const { return d->reply.data(); }
+
+QNetworkReply* BaseJob::reply() { return d->reply.data(); }
+
QUrl BaseJob::makeRequestUrl(QUrl baseUrl, const QString& path,
const QUrlQuery& query)
{
@@ -304,7 +332,7 @@ void BaseJob::doPrepare() { }
void BaseJob::onSentRequest(QNetworkReply*) { }
-void BaseJob::beforeAbandon(QNetworkReply*) { }
+void BaseJob::beforeAbandon() { }
void BaseJob::initiate(ConnectionData* connData, bool inBackground)
{
@@ -346,40 +374,74 @@ void BaseJob::sendRequest()
emit aboutToSendRequest();
d->sendRequest();
Q_ASSERT(d->reply);
- connect(d->reply.data(), &QNetworkReply::finished, this, &BaseJob::gotReply);
+ connect(reply(), &QNetworkReply::finished, this, [this] {
+ gotReply();
+ finishJob();
+ });
if (d->reply->isRunning()) {
- connect(d->reply.data(), &QNetworkReply::metaDataChanged, this,
- &BaseJob::checkReply);
- connect(d->reply.data(), &QNetworkReply::uploadProgress, this,
+ connect(reply(), &QNetworkReply::metaDataChanged, this,
+ [this] { checkReply(reply()); });
+ connect(reply(), &QNetworkReply::uploadProgress, this,
&BaseJob::uploadProgress);
- connect(d->reply.data(), &QNetworkReply::downloadProgress, this,
+ connect(reply(), &QNetworkReply::downloadProgress, this,
&BaseJob::downloadProgress);
d->timer.start(getCurrentTimeout());
qCInfo(d->logCat).noquote() << "Sent" << d->dumpRequest();
- onSentRequest(d->reply.data());
+ onSentRequest(reply());
emit sentRequest();
} else
qCCritical(d->logCat).noquote()
<< "Request could not start:" << d->dumpRequest();
}
+BaseJob::Status BaseJob::Private::parseJson()
+{
+ QJsonParseError error { 0, QJsonParseError::MissingObject };
+ jsonResponse = QJsonDocument::fromJson(rawResponse, &error);
+ return { error.error == QJsonParseError::NoError
+ ? BaseJob::NoError
+ : BaseJob::IncorrectResponse,
+ error.errorString() };
+}
+
void BaseJob::gotReply()
{
- checkReply();
+ setStatus(checkReply(reply()));
+
+ if (status().good()
+ && d->expectedContentTypes == QByteArrayList { "application/json" }) {
+ d->rawResponse = reply()->readAll();
+ setStatus(d->parseJson());
+ if (status().good() && !expectedKeys().empty()) {
+ const auto& responseObject = jsonData();
+ QByteArrayList missingKeys;
+ for (const auto& k: expectedKeys())
+ if (!responseObject.contains(k))
+ missingKeys.push_back(k);
+ if (!missingKeys.empty())
+ setStatus(IncorrectResponse, tr("Required JSON keys missing: ")
+ + missingKeys.join());
+ }
+ if (!status().good()) // Bad JSON in a "good" reply: bail out
+ return;
+ } // else {
+ // If the endpoint expects anything else than just (API-related) JSON
+ // reply()->readAll() is not performed and the whole reply processing
+ // is left to derived job classes: they may read it piecemeal or customise
+ // per content type in prepareResult(), or even have read it already
+ // (see, e.g., DownloadFileJob).
+ // }
+
if (status().good())
- setStatus(parseReply(d->reply.data()));
+ setStatus(prepareResult());
else {
- d->rawResponse = d->reply->readAll();
- const auto jsonBody = d->reply->rawHeader("Content-Type")
- == "application/json";
+ d->rawResponse = reply()->readAll();
qCDebug(d->logCat).noquote()
- << "Error body (truncated if long):" << d->rawResponse.left(500);
- if (jsonBody)
- setStatus(
- parseError(d->reply.data(),
- QJsonDocument::fromJson(d->rawResponse).object()));
+ << "Error body (truncated if long):" << rawDataSample(500);
+ // Parse the error payload and update the status if needed
+ if (const auto newStatus = prepareError(); !newStatus.good())
+ setStatus(newStatus);
}
- finishJob();
}
bool checkContentType(const QByteArray& type, const QByteArrayList& patterns)
@@ -408,12 +470,10 @@ bool checkContentType(const QByteArray& type, const QByteArrayList& patterns)
return false;
}
-BaseJob::Status BaseJob::doCheckReply(QNetworkReply* reply) const
+BaseJob::Status BaseJob::checkReply(const QNetworkReply* reply) const
{
- // QNetworkReply error codes seem to be flawed when it comes to HTTP;
- // see, e.g., https://github.com/quotient-im/libQuotient/issues/200
- // so check genuine HTTP codes. The below processing is based on
- // https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
+ // QNetworkReply error codes are insufficient for our purposes (e.g. they
+ // don't allow to discern HTTP code 429) so check the original code instead
const auto httpCodeHeader =
reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if (!httpCodeHeader.isValid()) {
@@ -444,24 +504,23 @@ BaseJob::Status BaseJob::doCheckReply(QNetworkReply* reply) const
return Status::fromHttpCode(httpCode, message);
}
-void BaseJob::checkReply() { setStatus(doCheckReply(d->reply.data())); }
+BaseJob::Status BaseJob::prepareResult() { return Success; }
-BaseJob::Status BaseJob::parseReply(QNetworkReply* reply)
+BaseJob::Status BaseJob::prepareError()
{
- d->rawResponse = reply->readAll();
- QJsonParseError error { 0, QJsonParseError::MissingObject };
- const auto& json = QJsonDocument::fromJson(d->rawResponse, &error);
- if (error.error == QJsonParseError::NoError)
- return parseJson(json);
+ // Since it's an error, the expected content type is of no help;
+ // check the actually advertised content type instead
+ if (reply()->rawHeader("Content-Type") != "application/json")
+ return NoError; // Retain the status if the error payload is not JSON
- return { IncorrectResponseError, error.errorString() };
-}
+ if (const auto status = d->parseJson(); !status.good())
+ return status;
-BaseJob::Status BaseJob::parseJson(const QJsonDocument&) { return Success; }
+ if (d->jsonResponse.isArray())
+ return { IncorrectResponse,
+ tr("Malformed error JSON: an array instead of an object") };
-BaseJob::Status BaseJob::parseError(QNetworkReply* /*reply*/,
- const QJsonObject& errorJson)
-{
+ const auto& errorJson = jsonData();
const auto errCode = errorJson.value("errcode"_ls).toString();
if (error() == TooManyRequestsError || errCode == "M_LIMIT_EXCEEDED") {
QString msg = tr("Too many requests");
@@ -499,6 +558,16 @@ BaseJob::Status BaseJob::parseError(QNetworkReply* /*reply*/,
return d->status;
}
+QJsonValue BaseJob::takeValueFromJson(const QString& key)
+{
+ if (!d->jsonResponse.isObject())
+ return QJsonValue::Undefined;
+ auto o = d->jsonResponse.object();
+ auto v = o.take(key);
+ d->jsonResponse.setObject(o);
+ return v;
+}
+
void BaseJob::stop()
{
// This method is (also) used to semi-finalise the job before retrying; so
@@ -616,10 +685,19 @@ QString BaseJob::rawDataSample(int bytesAtMost) const
Q_ASSERT(data.size() <= d->rawResponse.size());
return data.size() == d->rawResponse.size()
? data
- : data
- + tr("...(truncated, %Ln bytes in total)",
- "Comes after trimmed raw network response",
- d->rawResponse.size());
+ : data + tr("...(truncated, %Ln bytes in total)",
+ "Comes after trimmed raw network response",
+ d->rawResponse.size());
+}
+
+QJsonObject BaseJob::jsonData() const
+{
+ return d->jsonResponse.object();
+}
+
+QJsonArray BaseJob::jsonItems() const
+{
+ return d->jsonResponse.array();
}
QString BaseJob::statusCaption() const
@@ -704,7 +782,7 @@ void BaseJob::setStatus(int code, QString message)
void BaseJob::abandon()
{
- beforeAbandon(d->reply ? d->reply.data() : nullptr);
+ beforeAbandon();
d->timer.stop();
d->retryTimer.stop(); // In case abandon() was called between retries
setStatus(Abandoned);
diff --git a/lib/jobs/basejob.h b/lib/jobs/basejob.h
index 6920ebc1..be2926be 100644
--- a/lib/jobs/basejob.h
+++ b/lib/jobs/basejob.h
@@ -18,13 +18,11 @@
#pragma once
-#include "../logging.h"
#include "requestdata.h"
+#include "../logging.h"
+#include "../converters.h"
-#include <QtCore/QJsonDocument>
#include <QtCore/QObject>
-#include <QtCore/QUrlQuery>
-#include <QtCore/QMetaEnum>
class QNetworkReply;
class QSslError;
@@ -181,6 +179,49 @@ public:
*/
QString rawDataSample(int bytesAtMost = 65535) const;
+ /** Get the response body as a JSON object
+ *
+ * If the job's returned content type is not `application/json`
+ * or if the top-level JSON entity is not an object, an empty object
+ * is returned.
+ */
+ QJsonObject jsonData() const;
+
+ /** Get the response body as a JSON array
+ *
+ * If the job's returned content type is not `application/json`
+ * or if the top-level JSON entity is not an array, an empty array
+ * is returned.
+ */
+ QJsonArray jsonItems() const;
+
+ /** Load the property from the JSON response assuming a given C++ type
+ *
+ * If there's no top-level JSON object in the response or if there's
+ * no node with the key \p keyName, \p defaultValue is returned.
+ */
+ template <typename T, typename StrT> // Waiting for QStringViews...
+ T loadFromJson(const StrT& keyName, T&& defaultValue = {}) const
+ {
+ const auto& jv = jsonData().value(keyName);
+ return jv.isUndefined() ? std::forward<T>(defaultValue)
+ : fromJson<T>(jv);
+ }
+
+ /** Load the property from the JSON response and delete it from JSON
+ *
+ * If there's no top-level JSON object in the response or if there's
+ * no node with the key \p keyName, \p defaultValue is returned.
+ */
+ template <typename T>
+ T takeFromJson(const QString& key, T&& defaultValue = {})
+ {
+ if (const auto& jv = takeValueFromJson(key); !jv.isUndefined())
+ return fromJson<T>(jv);
+
+ return std::forward<T>(defaultValue);
+ }
+
/** Error (more generally, status) code
* Equivalent to status().code
* \sa status
@@ -314,6 +355,12 @@ protected:
const QByteArrayList& expectedContentTypes() const;
void addExpectedContentType(const QByteArray& contentType);
void setExpectedContentTypes(const QByteArrayList& contentTypes);
+ const QByteArrayList expectedKeys() const;
+ void addExpectedKey(const QByteArray &key);
+ void setExpectedKeys(const QByteArrayList &keys);
+
+ const QNetworkReply* reply() const;
+ QNetworkReply* reply();
/** Construct a URL out of baseUrl, path and query
*
@@ -338,50 +385,42 @@ protected:
* successfully sending a network request (including retries).
*/
virtual void onSentRequest(QNetworkReply*);
- virtual void beforeAbandon(QNetworkReply*);
+ virtual void beforeAbandon();
- /*! \brief Check the pending or received reply for upfront issues
+ /*! \brief An extension point for additional reply processing.
*
- * This is invoked when headers are first received and also once
- * the complete reply is obtained; the base implementation checks the HTTP
- * headers to detect general issues such as network errors or access denial.
- * It cannot read the response body (use parseReply/parseError to check
- * for problems in the body). Returning anything except NoError/Success
- * prevents further processing of the reply.
- *
- * @return the result of checking the reply
+ * The base implementation does nothing and returns Success.
*
- * @see gotReply
+ * \sa gotReply
*/
- virtual Status doCheckReply(QNetworkReply* reply) const;
+ virtual Status prepareResult();
- /**
- * Processes the reply. By default, parses the reply into
- * a QJsonDocument and calls parseJson() if it's a valid JSON.
- *
- * @param reply raw contents of a HTTP reply from the server
+ /*! \brief Process details of the error
*
- * @see gotReply, parseJson
+ * The function processes the reply in case when status from checkReply()
+ * was not good (usually because of an unsuccessful HTTP code).
+ * The base implementation assumes Matrix JSON error object in the body;
+ * overrides are strongly recommended to call it for all stock Matrix
+ * responses as early as possible but in addition can process custom errors,
+ * with JSON or non-JSON payload.
*/
- virtual Status parseReply(QNetworkReply* reply);
+ virtual Status prepareError();
- /**
- * Processes the JSON document received from the Matrix server.
- * By default returns successful status without analysing the JSON.
+ /*! \brief Get direct access to the JSON response object in the job
*
- * @param json valid JSON document received from the server
+ * This allows to implement deserialisation with "move" semantics for parts
+ * of the response. Assuming that the response body is a valid JSON object,
+ * the function calls QJsonObject::take(key) on it and returns the result.
*
- * @see parseReply
- */
- virtual Status parseJson(const QJsonDocument&);
-
- /**
- * Processes the reply in case of unsuccessful HTTP code.
- * The body is already loaded from the reply object to errorJson.
- * @param reply the HTTP reply from the server
- * @param errorJson the JSON payload describing the error
+ * \return QJsonValue::Null, if the response content type is not
+ * advertised as `application/json`;
+ * QJsonValue::Undefined, if the response is a JSON object but
+ * doesn't have \p key;
+ * the value for \p key otherwise.
+ *
+ * \sa takeFromJson
*/
- virtual Status parseError(QNetworkReply*, const QJsonObject& errorJson);
+ QJsonValue takeValueFromJson(const QString& key);
void setStatus(Status s);
void setStatus(int code, QString message);
@@ -397,9 +436,28 @@ protected:
protected slots:
void timeout();
+ /*! \brief Check the pending or received reply for upfront issues
+ *
+ * This is invoked when headers are first received and also once
+ * the complete reply is obtained; the base implementation checks the HTTP
+ * headers to detect general issues such as network errors or access denial
+ * and it's strongly recommended to call it from overrides,
+ * as early as possible.
+ * This slot is const and cannot read the response body. If you need to read
+ * the body on the fly, override onSentRequest() and connect in it
+ * to reply->readyRead(); and if you only need to validate the body after
+ * it fully arrived, use prepareResult() for that). Returning anything
+ * except NoError/Success switches further processing from prepareResult()
+ * to prepareError().
+ *
+ * @return the result of checking the reply
+ *
+ * @see gotReply
+ */
+ virtual Status checkReply(const QNetworkReply *reply) const;
+
private slots:
void sendRequest();
- void checkReply();
void gotReply();
friend class ConnectionData; // to provide access to sendRequest()
diff --git a/lib/jobs/downloadfilejob.cpp b/lib/jobs/downloadfilejob.cpp
index 3e037680..7b4cf690 100644
--- a/lib/jobs/downloadfilejob.cpp
+++ b/lib/jobs/downloadfilejob.cpp
@@ -86,14 +86,14 @@ void DownloadFileJob::onSentRequest(QNetworkReply* reply)
});
}
-void DownloadFileJob::beforeAbandon(QNetworkReply*)
+void DownloadFileJob::beforeAbandon()
{
if (d->targetFile)
d->targetFile->remove();
d->tempFile->remove();
}
-BaseJob::Status DownloadFileJob::parseReply(QNetworkReply*)
+BaseJob::Status DownloadFileJob::prepareResult()
{
if (d->targetFile) {
d->targetFile->close();
diff --git a/lib/jobs/downloadfilejob.h b/lib/jobs/downloadfilejob.h
index 06dc145c..e00fd9e4 100644
--- a/lib/jobs/downloadfilejob.h
+++ b/lib/jobs/downloadfilejob.h
@@ -19,7 +19,7 @@ private:
void doPrepare() override;
void onSentRequest(QNetworkReply* reply) override;
- void beforeAbandon(QNetworkReply*) override;
- Status parseReply(QNetworkReply*) override;
+ void beforeAbandon() override;
+ Status prepareResult() override;
};
} // namespace Quotient
diff --git a/lib/jobs/mediathumbnailjob.cpp b/lib/jobs/mediathumbnailjob.cpp
index df3763b2..33f4236c 100644
--- a/lib/jobs/mediathumbnailjob.cpp
+++ b/lib/jobs/mediathumbnailjob.cpp
@@ -48,12 +48,8 @@ QImage MediaThumbnailJob::scaledThumbnail(QSize toSize) const
Qt::SmoothTransformation);
}
-BaseJob::Status MediaThumbnailJob::parseReply(QNetworkReply* reply)
+BaseJob::Status MediaThumbnailJob::prepareResult()
{
- auto result = GetContentThumbnailJob::parseReply(reply);
- if (!result.good())
- return result;
-
if (_thumbnail.loadFromData(data()->readAll()))
return Success;
diff --git a/lib/jobs/mediathumbnailjob.h b/lib/jobs/mediathumbnailjob.h
index 75e2e55a..e6d39085 100644
--- a/lib/jobs/mediathumbnailjob.h
+++ b/lib/jobs/mediathumbnailjob.h
@@ -37,7 +37,7 @@ public:
QImage scaledThumbnail(QSize toSize) const;
protected:
- Status parseReply(QNetworkReply* reply) override;
+ Status prepareResult() override;
private:
QImage _thumbnail;
diff --git a/lib/jobs/syncjob.cpp b/lib/jobs/syncjob.cpp
index cd7709e1..6b8cfe4b 100644
--- a/lib/jobs/syncjob.cpp
+++ b/lib/jobs/syncjob.cpp
@@ -49,9 +49,9 @@ SyncJob::SyncJob(const QString& since, const Filter& filter, int timeout,
timeout, presence)
{}
-BaseJob::Status SyncJob::parseJson(const QJsonDocument& data)
+BaseJob::Status SyncJob::prepareResult()
{
- d.parseJson(data.object());
+ d.parseJson(jsonData());
if (d.unresolvedRooms().isEmpty())
return BaseJob::Success;
diff --git a/lib/jobs/syncjob.h b/lib/jobs/syncjob.h
index df419ba8..bf139a7b 100644
--- a/lib/jobs/syncjob.h
+++ b/lib/jobs/syncjob.h
@@ -33,7 +33,7 @@ public:
SyncData&& takeData() { return std::move(d); }
protected:
- Status parseJson(const QJsonDocument& data) override;
+ Status prepareResult() override;
private:
SyncData d;
diff --git a/libquotient.pri b/libquotient.pri
index 97ac9976..494a163a 100644
--- a/libquotient.pri
+++ b/libquotient.pri
@@ -5,6 +5,8 @@ QT -= gui
CONFIG *= c++1z warn_on rtti_off create_prl object_parallel_to_source
win32-msvc* {
+ # Quotient code base does not play well with NMake inference rules
+ CONFIG *= no_batch
QMAKE_CXXFLAGS_WARN_ON += -wd4100 -wd4267
} else {
QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-parameter
@@ -114,10 +116,6 @@ SOURCES += \
$$SRCPATH/jobs/mediathumbnailjob.cpp \
$$SRCPATH/jobs/downloadfilejob.cpp \
$$files($$SRCPATH/csapi/*.cpp, false) \
- $$files($$SRCPATH/csapi/definitions/*.cpp, false) \
- $$files($$SRCPATH/csapi/definitions/wellknown/*.cpp, false) \
- $$files($$SRCPATH/application-service/definitions/*.cpp, false) \
- $$files($$SRCPATH/identity/definitions/*.cpp, false) \
$$SRCPATH/logging.cpp \
$$SRCPATH/converters.cpp \
$$SRCPATH/settings.cpp \