diff --git a/README.md b/README.md index c407e7d1..3fabe921 100644 --- a/README.md +++ b/README.md @@ -18,4 +18,9 @@ void main() async { print(capabilities.toJson()); } -``` \ No newline at end of file +``` + +## Generated code + +The files in `lib/src/generated` are generated by [dart_openapi_codegen](https://gitlab.com/famedly/company/frontend/dart_openapi_codegen) +from [matrix-doc](https://github.com/matrix-org/matrix-doc/). See the README.md in dart_openapi_codegen for more information. diff --git a/analysis_options.yaml b/analysis_options.yaml index 7efcbfc1..8e8f9513 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -12,3 +12,4 @@ analyzer: todo: ignore exclude: - example/matrix_api_lite_example.dart + - lib/src/generated/**.dart diff --git a/example/matrix_api_lite_example.dart b/example/matrix_api_lite_example.dart index 0699acc4..70876234 100644 --- a/example/matrix_api_lite_example.dart +++ b/example/matrix_api_lite_example.dart @@ -1,3 +1,4 @@ +// @dart=2.9 import 'package:matrix_api_lite/src/matrix_api.dart'; void main() async { diff --git a/lib/fake_matrix_api.dart b/lib/fake_matrix_api.dart index 7786b4ea..f2b3f6de 100644 --- a/lib/fake_matrix_api.dart +++ b/lib/fake_matrix_api.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH @@ -753,12 +754,7 @@ class FakeMatrixApi extends MockClient { 'error': 'Blabla', }, '/media/r0/preview_url?url=https%3A%2F%2Fmatrix.org&ts=10': (var req) => { - 'og:title': 'Matrix Blog Post', - 'og:description': 'This is a really cool blog post from matrix.org', 'og:image': 'mxc://example.com/ascERGshawAWawugaAcauga', - 'og:image:type': 'image/png', - 'og:image:height': 48, - 'og:image:width': 48, 'matrix:image:size': 102400 }, '/media/r0/config': (var req) => {'m.upload.size': 50000000}, @@ -910,7 +906,7 @@ class FakeMatrixApi extends MockClient { 'com.example.custom.ratelimit': {'max_requests_per_hour': 600} } }, - '/client/r0/rooms/1234/context/1234?filter=%7B%7D&limit=10': (var req) => + '/client/r0/rooms/1234/context/1234?limit=10&filter=%7B%7D': (var req) => { 'end': 't29-57_2_0_2', 'events_after': [ @@ -1271,7 +1267,7 @@ class FakeMatrixApi extends MockClient { 'origin_server_ts': 1432735824653, 'unsigned': {'age': 1234} }, - '/client/r0/rooms/!localpart%3Aserver.abc/messages?from=1234&dir=b&to=1234&limit=10&filter=%7B%22lazy_load_members%22%3Atrue%7D': + '/client/r0/rooms/!localpart%3Aserver.abc/messages?from=1234&to=1234&dir=b&limit=10&filter=%7B%22lazy_load_members%22%3Atrue%7D': (var req) => messagesResponse, '/client/r0/rooms/!localpart%3Aserver.abc/messages?from=&dir=b&limit=10&filter=%7B%22lazy_load_members%22%3Atrue%7D': (var req) => messagesResponse, @@ -1989,7 +1985,7 @@ class FakeMatrixApi extends MockClient { 'access_token': 'SomeT0kenHere', 'token_type': 'Bearer', 'matrix_server_name': 'example.com', - 'expires_in': 3600.0 + 'expires_in': 3600 }, '/client/r0/user/@test:fakeServer.notExisting/openid/request_token': (var req) => { diff --git a/lib/matrix_api_lite.dart b/lib/matrix_api_lite.dart index afd709b0..6695187e 100644 --- a/lib/matrix_api_lite.dart +++ b/lib/matrix_api_lite.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH @@ -24,6 +25,8 @@ library matrix_api_lite; export 'src/matrix_api.dart'; +export 'src/values.dart'; +export 'src/generated/model.dart'; export 'src/utils/logs.dart'; export 'src/utils/map_copy_extension.dart'; export 'src/utils/try_get_map_extension.dart'; @@ -31,50 +34,25 @@ export 'src/model/algorithm_types.dart'; export 'src/model/basic_event.dart'; export 'src/model/basic_event_with_sender.dart'; export 'src/model/basic_room_event.dart'; -export 'src/model/device.dart'; -export 'src/model/event_context.dart'; export 'src/model/event_types.dart'; export 'src/model/events_sync_update.dart'; -export 'src/model/filter.dart'; -export 'src/model/keys_query_response.dart'; -export 'src/model/login_response.dart'; -export 'src/model/login_types.dart'; export 'src/model/matrix_connection_exception.dart'; export 'src/model/matrix_event.dart'; export 'src/model/matrix_exception.dart'; export 'src/model/matrix_keys.dart'; export 'src/model/message_types.dart'; -export 'src/model/notifications_query_response.dart'; -export 'src/model/one_time_keys_claim_response.dart'; -export 'src/model/open_graph_data.dart'; -export 'src/model/open_id_credentials.dart'; export 'src/model/presence.dart'; export 'src/model/presence_content.dart'; -export 'src/model/profile.dart'; -export 'src/model/public_rooms_response.dart'; -export 'src/model/push_rule_set.dart'; -export 'src/model/pusher.dart'; export 'src/model/request_token_response.dart'; -export 'src/model/room_alias_information.dart'; export 'src/model/room_creation_types.dart'; -export 'src/model/room_keys_info.dart'; export 'src/model/room_keys_keys.dart'; export 'src/model/room_summary.dart'; -export 'src/model/server_capabilities.dart'; export 'src/model/stripped_state_event.dart'; export 'src/model/supported_protocol.dart'; -export 'src/model/supported_versions.dart'; export 'src/model/sync_update.dart'; -export 'src/model/tag.dart'; -export 'src/model/third_party_identifier.dart'; export 'src/model/third_party_location.dart'; export 'src/model/third_party_user.dart'; -export 'src/model/timeline_history_response.dart'; -export 'src/model/turn_server_credentials.dart'; export 'src/model/upload_key_signatures_response.dart'; -export 'src/model/user_search_result.dart'; -export 'src/model/well_known_information.dart'; -export 'src/model/who_is_info.dart'; export 'src/model/auth/authentication_data.dart'; export 'src/model/auth/authentication_identifier.dart'; export 'src/model/auth/authentication_password.dart'; diff --git a/lib/src/generated/api.dart b/lib/src/generated/api.dart new file mode 100644 index 00000000..87a8ad4f --- /dev/null +++ b/lib/src/generated/api.dart @@ -0,0 +1,3553 @@ +import '../model/auth/authentication_data.dart'; +import '../model/auth/authentication_types.dart'; +import '../model/auth/authentication_identifier.dart'; +import '../model/matrix_keys.dart'; +import '../model/sync_update.dart'; +import '../model/matrix_event.dart'; + +import 'model.dart'; +import 'fixed_model.dart'; +import 'internal.dart'; + +import 'package:http/http.dart'; +import 'dart:convert'; +import 'dart:typed_data'; + +class Api { + Client httpClient; + Uri? baseUri; + String? bearerToken; + Api({Client? httpClient, this.baseUri, this.bearerToken}) + : httpClient = httpClient ?? Client(); + Never unexpectedResponse(BaseResponse response, Uint8List body) { + throw Exception('http error response'); + } + + /// Gets discovery information about the domain. The file may include + /// additional keys, which MUST follow the Java package naming convention, + /// e.g. `com.example.myapp.property`. This ensures property names are + /// suitably namespaced for each application and reduces the risk of + /// clashes. + /// + /// Note that this endpoint is not necessarily handled by the homeserver, + /// but by another webserver, to be used for discovering the homeserver URL. + Future getWellknown() async { + final requestUri = Uri(path: '.well-known/matrix/client'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return DiscoveryInformation.fromJson(json); + } + + /// Gets a list of the third party identifiers that the homeserver has + /// associated with the user's account. + /// + /// This is *not* the same as the list of third party identifiers bound to + /// the user's Matrix ID in identity servers. + /// + /// 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. + /// + /// returns `threepids` + Future?> getAccount3PIDs() async { + final requestUri = Uri(path: '_matrix/client/r0/account/3pid'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ((v) => v != null + ? (v as List).map((v) => ThirdPartyIdentifier.fromJson(v)).toList() + : null)(json['threepids']); + } + + /// 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. + /// + /// [threePidCreds] The third party credentials to associate with the account. + @deprecated + Future post3PIDs(ThreePidCredentials threePidCreds) async { + final requestUri = Uri(path: '_matrix/client/r0/account/3pid'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + 'three_pid_creds': threePidCreds.toJson(), + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return null; + } + + /// This API endpoint uses the [User-Interactive Authentication API](https://spec.matrix.org/unstable/client-server-api/#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. + /// + /// [auth] Additional authentication information for the + /// user-interactive authentication API. + /// + /// [clientSecret] The client secret used in the session with the homeserver. + /// + /// [sid] The session identifier given by the homeserver. + Future add3PID(String clientSecret, String sid, + {AuthenticationData? auth}) async { + final requestUri = Uri(path: '_matrix/client/r0/account/3pid/add'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (auth != null) 'auth': auth.toJson(), + 'client_secret': clientSecret, + 'sid': sid, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// 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. + /// + /// [clientSecret] The client secret used in the session with the identity server. + /// + /// [idAccessToken] An access token previously registered with the identity server. + /// + /// [idServer] The identity server to use. + /// + /// [sid] The session identifier given by the identity server. + Future bind3PID(String clientSecret, String idAccessToken, + String idServer, String sid) async { + final requestUri = Uri(path: '_matrix/client/r0/account/3pid/bind'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + 'client_secret': clientSecret, + 'id_access_token': idAccessToken, + 'id_server': idServer, + 'sid': sid, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// 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. + /// + /// [address] The third party address being removed. + /// + /// [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`. + /// + /// [medium] The medium of the third party identifier being removed. + /// + /// returns `id_server_unbind_result`: + /// 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. + Future delete3pidFromAccount( + String address, ThirdPartyIdentifierMedium medium, + {String? idServer}) async { + final requestUri = Uri(path: '_matrix/client/r0/account/3pid/delete'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + 'address': address, + if (idServer != null) 'id_server': idServer, + 'medium': { + ThirdPartyIdentifierMedium.email: 'email', + ThirdPartyIdentifierMedium.msisdn: 'msisdn' + }[medium]!, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return { + 'no-support': IdServerUnbindResult.noSupport, + 'success': IdServerUnbindResult.success + }[json['id_server_unbind_result']]!; + } + + /// 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. + /// + /// [address] The third party address being removed. + /// + /// [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`. + /// + /// [medium] The medium of the third party identifier being removed. + /// + /// returns `id_server_unbind_result`: + /// 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. + Future unbind3pidFromAccount( + String address, ThirdPartyIdentifierMedium medium, + {String? idServer}) async { + final requestUri = Uri(path: '_matrix/client/r0/account/3pid/unbind'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + 'address': address, + if (idServer != null) 'id_server': idServer, + 'medium': { + ThirdPartyIdentifierMedium.email: 'email', + ThirdPartyIdentifierMedium.msisdn: 'msisdn' + }[medium]!, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return { + 'no-support': IdServerUnbindResult.noSupport, + 'success': IdServerUnbindResult.success + }[json['id_server_unbind_result']]!; + } + + /// Deactivate the user's account, removing all ability for the user to + /// login again. + /// + /// This API endpoint uses the [User-Interactive Authentication API](https://spec.matrix.org/unstable/client-server-api/#user-interactive-authentication-api). + /// + /// 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. + /// + /// 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. + /// + /// [auth] Additional authentication information for the user-interactive authentication API. + /// + /// [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`. + /// + /// returns `id_server_unbind_result`: + /// 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. + Future deactivateAccount( + {AuthenticationData? auth, String? idServer}) async { + final requestUri = Uri(path: '_matrix/client/r0/account/deactivate'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (auth != null) 'auth': auth.toJson(), + if (idServer != null) 'id_server': idServer, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return { + 'no-support': IdServerUnbindResult.noSupport, + 'success': IdServerUnbindResult.success + }[json['id_server_unbind_result']]!; + } + + /// Changes the password for an account on this homeserver. + /// + /// This API endpoint uses the [User-Interactive Authentication API](https://spec.matrix.org/unstable/client-server-api/#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. 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. + /// + /// [auth] Additional authentication information for the user-interactive authentication API. + /// + /// [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](https://spec.matrix.org/unstable/client-server-api/#soft-logout) + /// for the user's remaining devices. + /// + /// [newPassword] The new password for the account. + Future changePassword(String newPassword, + {AuthenticationData? auth, bool? logoutDevices}) async { + final requestUri = Uri(path: '_matrix/client/r0/account/password'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (auth != null) 'auth': auth.toJson(), + if (logoutDevices != null) 'logout_devices': logoutDevices, + 'new_password': newPassword, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// Gets information about the owner of a given access token. + /// + /// Note that, as with the rest of the Client-Server API, + /// Application Services may masquerade as users within their + /// namespace by giving a `user_id` query parameter. In this + /// situation, the server should verify that the given `user_id` + /// is registered by the appservice, and return it in the response + /// body. + Future getTokenOwner() async { + final requestUri = Uri(path: '_matrix/client/r0/account/whoami'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return TokenOwnerInfo.fromJson(json); + } + + /// Gets information about a particular user. + /// + /// This API may be restricted to only be called by the user being looked + /// up, or by a server admin. Server-local administrator privileges are not + /// specified in this document. + /// + /// [userId] The user to look up. + Future getWhoIs(String userId) async { + final requestUri = Uri( + path: '_matrix/client/r0/admin/whois/${Uri.encodeComponent(userId)}'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return WhoIsInfo.fromJson(json); + } + + /// Gets information about the server's supported feature set + /// and other relevant capabilities. + /// + /// returns `capabilities`: + /// The custom capabilities the server supports, using the + /// Java package naming convention. + Future getCapabilities() async { + final requestUri = Uri(path: '_matrix/client/r0/capabilities'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return Capabilities.fromJson(json['capabilities']); + } + + /// Create a new room with various configuration options. + /// + /// The server MUST apply the normal state resolution rules when creating + /// the new room, including checking power levels for each event. It MUST + /// apply the events implied by the request in the following order: + /// + /// 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. + /// + /// 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. + /// + /// 5. Events listed in `initial_state`, in the order that they are + /// listed. + /// + /// 6. Events implied by `name` and `topic` (`m.room.name` and `m.room.topic` + /// state events). + /// + /// 7. Invite events implied by `invite` and `invite_3pid` (`m.room.member` with + /// `membership: invite` and `m.room.third_party_invite`). + /// + /// The available presets do the following with respect to room state: + /// + /// | Preset | `join_rules` | `history_visibility` | `guest_access` | Other | + /// |------------------------|--------------|----------------------|----------------|-------| + /// | `private_chat` | `invite` | `shared` | `can_join` | | + /// | `trusted_private_chat` | `invite` | `shared` | `can_join` | All invitees are given the same power level as the room creator. | + /// | `public_chat` | `public` | `shared` | `forbidden` | | + /// + /// The server will create a `m.room.create` event in the room with the + /// requesting user as the creator, alongside other keys provided in the + /// `creation_content`. + /// + /// [creationContent] Extra keys, such as `m.federate`, to be added to the content + /// of the [`m.room.create`](client-server-api/#mroomcreate) event. The server will clobber the following + /// keys: `creator`, `room_version`. Future versions of the specification + /// may allow the server to clobber other keys. + /// + /// [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. + /// + /// [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. + /// + /// [invite3pid] A list of objects representing third party IDs to invite into + /// the room. + /// + /// [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](https://spec.matrix.org/unstable/client-server-api/#direct-messaging) for more information. + /// + /// [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`. + /// + /// [powerLevelContentOverride] The power level content to override in the default power level + /// event. This object is applied on top of the generated + /// [`m.room.power_levels`](client-server-api/#mroompower_levels) + /// event content prior to it being sent to the room. Defaults to + /// overriding nothing. + /// + /// [preset] Convenience parameter for setting various default state events + /// based on a preset. + /// + /// If unspecified, the server should use the `visibility` to determine + /// 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`. + /// + /// [roomAliasName] The desired room alias **local part**. If this is included, a + /// room alias will be created and mapped to the newly created + /// room. The alias will belong on the *same* homeserver which + /// created the room. For example, if this was set to "foo" and + /// sent to the homeserver "example.com" the complete room alias + /// would be `#foo:example.com`. + /// + /// The complete room alias will become the canonical alias for + /// the room. + /// + /// [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. + /// + /// [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`. + /// + /// [visibility] A `public` visibility indicates that the room will be shown + /// in the published room list. A `private` visibility will hide + /// the room from the published room list. Rooms default to + /// `private` visibility if this key is not included. NB: This + /// should not be confused with `join_rules` which also uses the + /// word `public`. + /// + /// returns `room_id`: + /// The created room's ID. + Future createRoom( + {Map? creationContent, + List? initialState, + List? invite, + List? invite3pid, + bool? isDirect, + String? name, + Map? powerLevelContentOverride, + CreateRoomPreset? preset, + String? roomAliasName, + String? roomVersion, + String? topic, + Visibility? visibility}) async { + final requestUri = Uri(path: '_matrix/client/r0/createRoom'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (creationContent != null) 'creation_content': creationContent, + if (initialState != null) + 'initial_state': initialState.map((v) => v.toJson()).toList(), + if (invite != null) 'invite': invite.map((v) => v).toList(), + if (invite3pid != null) + 'invite_3pid': invite3pid.map((v) => v.toJson()).toList(), + if (isDirect != null) 'is_direct': isDirect, + if (name != null) 'name': name, + if (powerLevelContentOverride != null) + 'power_level_content_override': powerLevelContentOverride, + if (preset != null) + 'preset': { + CreateRoomPreset.privateChat: 'private_chat', + CreateRoomPreset.publicChat: 'public_chat', + CreateRoomPreset.trustedPrivateChat: 'trusted_private_chat' + }[preset]!, + if (roomAliasName != null) 'room_alias_name': roomAliasName, + if (roomVersion != null) 'room_version': roomVersion, + if (topic != null) 'topic': topic, + if (visibility != null) + 'visibility': { + Visibility.public: 'public', + Visibility.private: 'private' + }[visibility]!, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return json['room_id'] as String; + } + + /// This API endpoint uses the [User-Interactive Authentication API](https://spec.matrix.org/unstable/client-server-api/#user-interactive-authentication-api). + /// + /// Deletes the given devices, and invalidates any access token associated with them. + /// + /// [auth] Additional authentication information for the + /// user-interactive authentication API. + /// + /// [devices] The list of device IDs to delete. + Future deleteDevices(List devices, + {AuthenticationData? auth}) async { + final requestUri = Uri(path: '_matrix/client/r0/delete_devices'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (auth != null) 'auth': auth.toJson(), + 'devices': devices.map((v) => v).toList(), + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// Gets information about all devices for the current user. + /// + /// returns `devices`: + /// A list of all registered devices for this user. + Future?> getDevices() async { + final requestUri = Uri(path: '_matrix/client/r0/devices'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ((v) => v != null + ? (v as List).map((v) => Device.fromJson(v)).toList() + : null)(json['devices']); + } + + /// This API endpoint uses the [User-Interactive Authentication API](https://spec.matrix.org/unstable/client-server-api/#user-interactive-authentication-api). + /// + /// Deletes the given device, and invalidates any access token associated with it. + /// + /// [deviceId] The device to delete. + /// + /// [auth] Additional authentication information for the + /// user-interactive authentication API. + Future deleteDevice(String deviceId, {AuthenticationData? auth}) async { + final requestUri = + Uri(path: '_matrix/client/r0/devices/${Uri.encodeComponent(deviceId)}'); + final request = Request('DELETE', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (auth != null) 'auth': auth.toJson(), + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// Gets information on a single device, by device id. + /// + /// [deviceId] The device to retrieve. + Future getDevice(String deviceId) async { + final requestUri = + Uri(path: '_matrix/client/r0/devices/${Uri.encodeComponent(deviceId)}'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return Device.fromJson(json); + } + + /// Updates the metadata on the given device. + /// + /// [deviceId] The device to update. + /// + /// [displayName] The new display name for this device. If not given, the + /// display name is unchanged. + Future updateDevice(String deviceId, {String? displayName}) async { + final requestUri = + Uri(path: '_matrix/client/r0/devices/${Uri.encodeComponent(deviceId)}'); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (displayName != null) 'display_name': displayName, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// Updates the visibility of a given room on the application service's room + /// directory. + /// + /// This API is similar to the room directory visibility API used by clients + /// to update the homeserver's more general room directory. + /// + /// This API requires the use of an application service access token (`as_token`) + /// instead of a typical client's access_token. This API cannot be invoked by + /// users who are not identified as application services. + /// + /// [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. + /// + /// [roomId] The room ID to add to the directory. + /// + /// [visibility] Whether the room should be visible (public) in the directory + /// or not (private). + Future> updateAppserviceRoomDirectoryVisibility( + String networkId, String roomId, Visibility visibility) async { + final requestUri = Uri( + path: + '_matrix/client/r0/directory/list/appservice/${Uri.encodeComponent(networkId)}/${Uri.encodeComponent(roomId)}'); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + 'visibility': { + Visibility.public: 'public', + Visibility.private: 'private' + }[visibility]!, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return json as Map; + } + + /// Remove a mapping of room alias to room ID. + /// + /// 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. + /// + /// [roomAlias] The room alias to remove. + Future deleteRoomAlias(String roomAlias) async { + final requestUri = Uri( + path: + '_matrix/client/r0/directory/room/${Uri.encodeComponent(roomAlias)}'); + final request = Request('DELETE', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// Requests that the server resolve a room alias to a room ID. + /// + /// The server will use the federation API to resolve the alias if the + /// domain part of the alias does not correspond to the server's own + /// domain. + /// + /// [roomAlias] The room alias. + Future getRoomIdByAlias(String roomAlias) async { + final requestUri = Uri( + path: + '_matrix/client/r0/directory/room/${Uri.encodeComponent(roomAlias)}'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return GetRoomIdByAliasResponse.fromJson(json); + } + + /// setRoomAlias + /// + /// [roomAlias] The room alias to set. + /// + /// [roomId] The room ID to set. + Future setRoomAlias(String roomAlias, String roomId) async { + final requestUri = Uri( + path: + '_matrix/client/r0/directory/room/${Uri.encodeComponent(roomAlias)}'); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + 'room_id': roomId, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// Get a single event based on `event_id`. You must have permission to + /// retrieve this event e.g. by being a member in the room for this event. + /// + /// This endpoint was deprecated in r0 of this specification. Clients + /// should instead call the + /// [/rooms/{roomId}/event/{eventId}](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientr0roomsroomideventeventid) API + /// or the [/rooms/{roomId}/context/{eventId](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientr0roomsroomidcontexteventid) API. + /// + /// [eventId] The event ID to get. + @deprecated + Future getOneEvent(String eventId) async { + final requestUri = + Uri(path: '_matrix/client/r0/events/${Uri.encodeComponent(eventId)}'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return MatrixEvent.fromJson(json); + } + + /// *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`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientr0initialsync) + /// and [`/sync`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientr0sync) APIs. + /// + /// [roomIdOrAlias] The room identifier or alias to join. + /// + /// [serverName] The servers to attempt to join the room through. One of the servers + /// must be participating in the room. + /// + /// [reason] Optional reason to be included as the `reason` on the subsequent + /// membership event. + /// + /// [thirdPartySigned] 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. + /// + /// returns `room_id`: + /// The joined room ID. + Future joinRoom(String roomIdOrAlias, + {List? serverName, + String? reason, + ThirdPartySigned? thirdPartySigned}) async { + final requestUri = Uri( + path: '_matrix/client/r0/join/${Uri.encodeComponent(roomIdOrAlias)}', + queryParameters: { + if (serverName != null) + 'server_name': serverName.map((v) => v).toList(), + }); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (reason != null) 'reason': reason, + if (thirdPartySigned != null) + 'third_party_signed': thirdPartySigned.toJson(), + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return json['room_id'] as String; + } + + /// This API returns a list of the user's current rooms. + /// + /// returns `joined_rooms`: + /// The ID of each room in which the user has `joined` membership. + Future> getJoinedRooms() async { + final requestUri = Uri(path: '_matrix/client/r0/joined_rooms'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return (json['joined_rooms'] as List).map((v) => v as String).toList(); + } + + /// Gets a list of users who have updated their device identity keys since a + /// previous sync token. + /// + /// The server should include in the results any users who: + /// + /// * currently share a room with the calling user (ie, both users have + /// membership state `join`); *and* + /// * added new device identity keys or removed an existing device with + /// identity keys, between `from` and `to`. + /// + /// [from] The desired start point of the list. Should be the `next_batch` field + /// from a response to an earlier call to [`/sync`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientr0sync). 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. + /// + /// [to] The desired end point of the list. Should be the `next_batch` + /// field from a recent call to [`/sync`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientr0sync) - typically the most recent + /// such call. This may be used by the server as a hint to check its + /// caches are up to date. + Future getKeysChanges(String from, String to) async { + final requestUri = + Uri(path: '_matrix/client/r0/keys/changes', queryParameters: { + 'from': from, + 'to': to, + }); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return GetKeysChangesResponse.fromJson(json); + } + + /// Claims one-time keys for use in pre-key messages. + /// + /// [oneTimeKeys] The keys to be claimed. A map from user ID, to a map from + /// device ID to algorithm name. + /// + /// [timeout] The time (in milliseconds) to wait when downloading keys from + /// remote servers. 10 seconds is the recommended default. + Future claimKeys( + Map> oneTimeKeys, + {int? timeout}) async { + final requestUri = Uri(path: '_matrix/client/r0/keys/claim'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + 'one_time_keys': oneTimeKeys + .map((k, v) => MapEntry(k, v.map((k, v) => MapEntry(k, v)))), + if (timeout != null) 'timeout': timeout, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ClaimKeysResponse.fromJson(json); + } + + /// Returns the current devices and identity keys for the given users. + /// + /// [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. + /// + /// [timeout] The time (in milliseconds) to wait when downloading keys from + /// remote servers. 10 seconds is the recommended default. + /// + /// [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 request, + /// or any later sync token. This allows the server to ensure its response + /// contains the keys advertised by the notification in that sync. + Future queryKeys(Map> deviceKeys, + {int? timeout, String? token}) async { + final requestUri = Uri(path: '_matrix/client/r0/keys/query'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + 'device_keys': + deviceKeys.map((k, v) => MapEntry(k, v.map((v) => v).toList())), + if (timeout != null) 'timeout': timeout, + if (token != null) 'token': token, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return QueryKeysResponse.fromJson(json); + } + + /// *Note that this API takes either a room ID or alias, unlike other membership APIs.* + /// + /// This API "knocks" on the room to ask for permission to join, if the user + /// is allowed to knock on the room. Acceptance of the knock happens out of + /// band from this API, meaning that the client will have to watch for updates + /// regarding the acceptance/rejection of the knock. + /// + /// If the room history settings allow, the user will still be able to see + /// history of the room while being in the "knock" state. The user will have + /// to accept the invitation to join the room (acceptance of knock) to see + /// messages reliably. See the `/join` endpoints for more information about + /// history visibility to the user. + /// + /// The knock will appear as an entry in the response of the + /// [`/sync`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientr0sync) API. + /// + /// [roomIdOrAlias] The room identifier or alias to knock upon. + /// + /// [serverName] The servers to attempt to knock on the room through. One of the servers + /// must be participating in the room. + /// + /// [reason] Optional reason to be included as the `reason` on the subsequent + /// membership event. + /// + /// returns `room_id`: + /// The knocked room ID. + Future knockRoom(String roomIdOrAlias, + {List? serverName, String? reason}) async { + final requestUri = Uri( + path: '_matrix/client/r0/knock/${Uri.encodeComponent(roomIdOrAlias)}', + queryParameters: { + if (serverName != null) + 'server_name': serverName.map((v) => v).toList(), + }); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (reason != null) 'reason': reason, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return json['room_id'] as String; + } + + /// Gets the homeserver's supported login types to authenticate users. Clients + /// should pick one of these and supply it as the `type` when logging in. + /// + /// returns `flows`: + /// The homeserver's supported login types + Future?> getLoginFlows() async { + final requestUri = Uri(path: '_matrix/client/r0/login'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ((v) => v != null + ? (v as List).map((v) => LoginFlow.fromJson(v)).toList() + : null)(json['flows']); + } + + /// Authenticates the user, and issues an access token they can + /// use to authorize themself in subsequent requests. + /// + /// If the client does not supply a `device_id`, the server must + /// auto-generate one. + /// + /// The returned access token must be associated with the `device_id` + /// 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](https://spec.matrix.org/unstable/client-server-api/#relationship-between-access-tokens-and-devices). + /// + /// [address] Third party identifier for the user. Deprecated in favour of `identifier`. + /// + /// [deviceId] ID of the client device. If this does not correspond to a + /// known client device, a new device will be created. The given + /// device ID must not be the same as a + /// [cross-signing](https://spec.matrix.org/unstable/client-server-api/#cross-signing) key ID. + /// The server will auto-generate a device_id + /// if this is not specified. + /// + /// [identifier] Identification information for a user + /// + /// [initialDeviceDisplayName] A display name to assign to the newly-created device. Ignored + /// if `device_id` corresponds to a known device. + /// + /// [medium] When logging in using a third party identifier, the medium of the identifier. Must be 'email'. Deprecated in favour of `identifier`. + /// + /// [password] Required when `type` is `m.login.password`. The user's + /// password. + /// + /// [token] Required when `type` is `m.login.token`. Part of Token-based login. + /// + /// [type] The login type being used. + /// + /// [user] The fully qualified user ID or just local part of the user ID, to log in. Deprecated in favour of `identifier`. + Future login(LoginType type, + {String? address, + String? deviceId, + AuthenticationIdentifier? identifier, + String? initialDeviceDisplayName, + String? medium, + String? password, + String? token, + String? user}) async { + final requestUri = Uri(path: '_matrix/client/r0/login'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (address != null) 'address': address, + if (deviceId != null) 'device_id': deviceId, + if (identifier != null) 'identifier': identifier.toJson(), + if (initialDeviceDisplayName != null) + 'initial_device_display_name': initialDeviceDisplayName, + if (medium != null) 'medium': medium, + if (password != null) 'password': password, + if (token != null) 'token': token, + 'type': { + LoginType.mLoginPassword: 'm.login.password', + LoginType.mLoginToken: 'm.login.token' + }[type]!, + if (user != null) 'user': user, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return LoginResponse.fromJson(json); + } + + /// Invalidates an existing access token, so that it can no longer be used for + /// authorization. The device associated with the access token is also deleted. + /// [Device keys](https://spec.matrix.org/unstable/client-server-api/#device-keys) for the device are deleted alongside the device. + Future logout() async { + final requestUri = Uri(path: '_matrix/client/r0/logout'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// 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. All devices + /// for the user are also deleted. [Device keys](https://spec.matrix.org/unstable/client-server-api/#device-keys) for the device are + /// deleted alongside the device. + /// + /// This endpoint does not use the [User-Interactive Authentication API](https://spec.matrix.org/unstable/client-server-api/#user-interactive-authentication-api) because + /// User-Interactive Authentication is designed to protect against attacks where the + /// someone gets hold of a single access token then takes over the account. This + /// endpoint invalidates all access tokens for the user, including the token used in + /// the request, and therefore the attacker is unable to take over the account in + /// this way. + Future logoutAll() async { + final requestUri = Uri(path: '_matrix/client/r0/logout/all'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// This API is used to paginate through the list of events that the + /// user has been, or would have been notified about. + /// + /// [from] Pagination token given to retrieve the next set of events. + /// + /// [limit] Limit on the number of events to return in this request. + /// + /// [only] Allows basic filtering of events returned. Supply `highlight` + /// to return only events where the notification had the highlight + /// tweak set. + Future getNotifications( + {String? from, int? limit, String? only}) async { + final requestUri = + Uri(path: '_matrix/client/r0/notifications', queryParameters: { + if (from != null) 'from': from, + if (limit != null) 'limit': limit.toString(), + if (only != null) 'only': only, + }); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return GetNotificationsResponse.fromJson(json); + } + + /// Get the given user's presence state. + /// + /// [userId] The user whose presence state to get. + Future getPresence(String userId) async { + final requestUri = Uri( + path: + '_matrix/client/r0/presence/${Uri.encodeComponent(userId)}/status'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return GetPresenceResponse.fromJson(json); + } + + /// This API sets the given user's presence state. When setting the status, + /// the activity time is updated to reflect that activity; the client does + /// not need to specify the `last_active_ago` field. You cannot set the + /// presence state of another user. + /// + /// [userId] The user whose presence state to update. + /// + /// [presence] The new presence state. + /// + /// [statusMsg] The status message to attach to this state. + Future setPresence(String userId, PresenceType presence, + {String? statusMsg}) async { + final requestUri = Uri( + path: + '_matrix/client/r0/presence/${Uri.encodeComponent(userId)}/status'); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + 'presence': { + PresenceType.online: 'online', + PresenceType.offline: 'offline', + PresenceType.unavailable: 'unavailable' + }[presence]!, + if (statusMsg != null) 'status_msg': statusMsg, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// Get the combined profile information for this user. This API may be used + /// to fetch the user's own profile information or other users; either + /// locally or on remote homeservers. This API may return keys which are not + /// limited to `displayname` or `avatar_url`. + /// + /// [userId] The user whose profile information to get. + Future getUserProfile(String userId) async { + final requestUri = + Uri(path: '_matrix/client/r0/profile/${Uri.encodeComponent(userId)}'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ProfileInformation.fromJson(json); + } + + /// Get the user's avatar URL. This API may be used to fetch the user's + /// own avatar URL or to query the URL of other users; either locally or + /// on remote homeservers. + /// + /// [userId] The user whose avatar URL to get. + /// + /// returns `avatar_url`: + /// The user's avatar URL if they have set one, otherwise not present. + Future getAvatarUrl(String userId) async { + final requestUri = Uri( + path: + '_matrix/client/r0/profile/${Uri.encodeComponent(userId)}/avatar_url'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ((v) => v != null ? Uri.parse(v) : null)(json['avatar_url']); + } + + /// This API sets the given user's avatar URL. You must have permission to + /// set this user's avatar URL, e.g. you need to have their `access_token`. + /// + /// [userId] The user whose avatar URL to set. + /// + /// [avatarUrl] The new avatar URL for this user. + Future setAvatarUrl(String userId, Uri? avatarUrl) async { + final requestUri = Uri( + path: + '_matrix/client/r0/profile/${Uri.encodeComponent(userId)}/avatar_url'); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (avatarUrl != null) 'avatar_url': avatarUrl.toString(), + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// Get the user's display name. This API may be used to fetch the user's + /// own displayname or to query the name of other users; either locally or + /// on remote homeservers. + /// + /// [userId] The user whose display name to get. + /// + /// returns `displayname`: + /// The user's display name if they have set one, otherwise not present. + Future getDisplayName(String userId) async { + final requestUri = Uri( + path: + '_matrix/client/r0/profile/${Uri.encodeComponent(userId)}/displayname'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ((v) => v != null ? v as String : null)(json['displayname']); + } + + /// This API sets the given user's display name. You must have permission to + /// set this user's display name, e.g. you need to have their `access_token`. + /// + /// [userId] The user whose display name to set. + /// + /// [displayname] The new display name for this user. + Future setDisplayName(String userId, String? displayname) async { + final requestUri = Uri( + path: + '_matrix/client/r0/profile/${Uri.encodeComponent(userId)}/displayname'); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (displayname != null) 'displayname': displayname, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// Lists the public rooms on the server. + /// + /// This API returns paginated responses. The rooms are ordered by the number + /// of joined members, with the largest rooms first. + /// + /// [limit] Limit the number of results returned. + /// + /// [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. + /// + /// [server] The server to fetch the public room lists from. Defaults to the + /// local server. + Future getPublicRooms( + {int? limit, String? since, String? server}) async { + final requestUri = + Uri(path: '_matrix/client/r0/publicRooms', queryParameters: { + if (limit != null) 'limit': limit.toString(), + if (since != null) 'since': since, + if (server != null) 'server': server, + }); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return GetPublicRoomsResponse.fromJson(json); + } + + /// 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. + /// + /// [server] The server to fetch the public room lists from. Defaults to the + /// local server. + /// + /// [filter] Filter to apply to the results. + /// + /// [includeAllNetworks] Whether or not to include all known networks/protocols from + /// application services on the homeserver. Defaults to false. + /// + /// [limit] Limit the number of results returned. + /// + /// [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. + /// + /// [thirdPartyInstanceId] The specific third party network/protocol to request from the + /// homeserver. Can only be used if `include_all_networks` is false. + Future queryPublicRooms( + {String? server, + PublicRoomQueryFilter? filter, + bool? includeAllNetworks, + int? limit, + String? since, + String? thirdPartyInstanceId}) async { + final requestUri = + Uri(path: '_matrix/client/r0/publicRooms', queryParameters: { + if (server != null) 'server': server, + }); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (filter != null) 'filter': filter.toJson(), + if (includeAllNetworks != null) + 'include_all_networks': includeAllNetworks, + if (limit != null) 'limit': limit, + if (since != null) 'since': since, + if (thirdPartyInstanceId != null) + 'third_party_instance_id': thirdPartyInstanceId, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return QueryPublicRoomsResponse.fromJson(json); + } + + /// Gets all currently active pushers for the authenticated user. + /// + /// returns `pushers`: + /// An array containing the current pushers for the user + Future?> getPushers() async { + final requestUri = Uri(path: '_matrix/client/r0/pushers'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ((v) => v != null + ? (v as List).map((v) => Pusher.fromJson(v)).toList() + : null)(json['pushers']); + } + + /// Retrieve all push rulesets for this user. Clients can "drill-down" on + /// the rulesets by suffixing a `scope` to this path e.g. + /// `/pushrules/global/`. This will return a subset of this data under the + /// specified key e.g. the `global` key. + /// + /// returns `global`: + /// The global ruleset. + Future getPushRules() async { + final requestUri = Uri(path: '_matrix/client/r0/pushrules'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return PushRuleSet.fromJson(json['global']); + } + + /// This endpoint removes the push rule defined in the path. + /// + /// [scope] `global` to specify global rules. + /// + /// [kind] The kind of rule + /// + /// + /// [ruleId] The identifier for the rule. + /// + Future deletePushRule( + String scope, PushRuleKind kind, String ruleId) async { + final requestUri = Uri( + path: + '_matrix/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent({ + PushRuleKind.override: 'override', + PushRuleKind.underride: 'underride', + PushRuleKind.sender: 'sender', + PushRuleKind.room: 'room', + PushRuleKind.content: 'content' + }[kind]!)}/${Uri.encodeComponent(ruleId)}'); + final request = Request('DELETE', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// Retrieve a single specified push rule. + /// + /// [scope] `global` to specify global rules. + /// + /// [kind] The kind of rule + /// + /// + /// [ruleId] The identifier for the rule. + /// + Future getPushRule( + String scope, PushRuleKind kind, String ruleId) async { + final requestUri = Uri( + path: + '_matrix/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent({ + PushRuleKind.override: 'override', + PushRuleKind.underride: 'underride', + PushRuleKind.sender: 'sender', + PushRuleKind.room: 'room', + PushRuleKind.content: 'content' + }[kind]!)}/${Uri.encodeComponent(ruleId)}'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return PushRule.fromJson(json); + } + + /// This endpoint allows the creation, modification and deletion of pushers + /// for this user ID. The behaviour of this endpoint varies depending on the + /// values in the JSON body. + /// + /// When creating push rules, they MUST be enabled by default. + /// + /// [scope] `global` to specify global rules. + /// + /// [kind] The kind of rule + /// + /// + /// [ruleId] The identifier for the rule. + /// + /// + /// [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. + /// + /// [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. + /// + /// [actions] The action(s) to perform when the conditions for this rule are met. + /// + /// [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. + /// + /// [pattern] Only applicable to `content` rules. The glob-style pattern to match against. + Future setPushRule( + String scope, PushRuleKind kind, String ruleId, List actions, + {String? before, + String? after, + List? conditions, + String? pattern}) async { + final requestUri = Uri( + path: + '_matrix/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent({ + PushRuleKind.override: 'override', + PushRuleKind.underride: 'underride', + PushRuleKind.sender: 'sender', + PushRuleKind.room: 'room', + PushRuleKind.content: 'content' + }[kind]!)}/${Uri.encodeComponent(ruleId)}', + queryParameters: { + if (before != null) 'before': before, + if (after != null) 'after': after, + }); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + 'actions': actions.map((v) => v).toList(), + if (conditions != null) + 'conditions': conditions.map((v) => v.toJson()).toList(), + if (pattern != null) 'pattern': pattern, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// This endpoint get the actions for the specified push rule. + /// + /// [scope] Either `global` or `device/` to specify global + /// rules or device rules for the given `profile_tag`. + /// + /// [kind] The kind of rule + /// + /// + /// [ruleId] The identifier for the rule. + /// + /// + /// returns `actions`: + /// The action(s) to perform for this rule. + Future> getPushRuleActions( + String scope, PushRuleKind kind, String ruleId) async { + final requestUri = Uri( + path: + '_matrix/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent({ + PushRuleKind.override: 'override', + PushRuleKind.underride: 'underride', + PushRuleKind.sender: 'sender', + PushRuleKind.room: 'room', + PushRuleKind.content: 'content' + }[kind]!)}/${Uri.encodeComponent(ruleId)}/actions'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return (json['actions'] as List).map((v) => v as dynamic).toList(); + } + + /// This endpoint allows clients to change the actions of a push rule. + /// This can be used to change the actions of builtin rules. + /// + /// [scope] `global` to specify global rules. + /// + /// [kind] The kind of rule + /// + /// + /// [ruleId] The identifier for the rule. + /// + /// + /// [actions] The action(s) to perform for this rule. + Future setPushRuleActions(String scope, PushRuleKind kind, + String ruleId, List actions) async { + final requestUri = Uri( + path: + '_matrix/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent({ + PushRuleKind.override: 'override', + PushRuleKind.underride: 'underride', + PushRuleKind.sender: 'sender', + PushRuleKind.room: 'room', + PushRuleKind.content: 'content' + }[kind]!)}/${Uri.encodeComponent(ruleId)}/actions'); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + 'actions': actions.map((v) => v).toList(), + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// This endpoint gets whether the specified push rule is enabled. + /// + /// [scope] Either `global` or `device/` to specify global + /// rules or device rules for the given `profile_tag`. + /// + /// [kind] The kind of rule + /// + /// + /// [ruleId] The identifier for the rule. + /// + /// + /// returns `enabled`: + /// Whether the push rule is enabled or not. + Future isPushRuleEnabled( + String scope, PushRuleKind kind, String ruleId) async { + final requestUri = Uri( + path: + '_matrix/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent({ + PushRuleKind.override: 'override', + PushRuleKind.underride: 'underride', + PushRuleKind.sender: 'sender', + PushRuleKind.room: 'room', + PushRuleKind.content: 'content' + }[kind]!)}/${Uri.encodeComponent(ruleId)}/enabled'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return json['enabled'] as bool; + } + + /// This endpoint allows clients to enable or disable the specified push rule. + /// + /// [scope] `global` to specify global rules. + /// + /// [kind] The kind of rule + /// + /// + /// [ruleId] The identifier for the rule. + /// + /// + /// [enabled] Whether the push rule is enabled or not. + Future setPushRuleEnabled( + String scope, PushRuleKind kind, String ruleId, bool enabled) async { + final requestUri = Uri( + path: + '_matrix/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent({ + PushRuleKind.override: 'override', + PushRuleKind.underride: 'underride', + PushRuleKind.sender: 'sender', + PushRuleKind.room: 'room', + PushRuleKind.content: 'content' + }[kind]!)}/${Uri.encodeComponent(ruleId)}/enabled'); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + 'enabled': enabled, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// This API endpoint uses the [User-Interactive Authentication API](https://spec.matrix.org/unstable/client-server-api/#user-interactive-authentication-api), except in + /// the cases where a guest account is being registered. + /// + /// Register for an account on this homeserver. + /// + /// There are two kinds of user account: + /// + /// - `user` accounts. These accounts may use the full API described in this specification. + /// + /// - `guest` accounts. These accounts may have limited permissions and may not be supported by all servers. + /// + /// If registration is successful, this endpoint will issue an access token + /// the client can use to authorize itself in subsequent requests. + /// + /// If the client does not supply a `device_id`, the server must + /// auto-generate one. + /// + /// The server SHOULD register an account with a User ID based on the + /// `username` provided, if any. Note that the grammar of Matrix User ID + /// localparts is restricted, so the server MUST either map the provided + /// `username` onto a `user_id` in a logical manner, or reject + /// `username`\s which do not comply to the grammar, with + /// `M_INVALID_USERNAME`. + /// + /// Matrix clients MUST NOT assume that localpart of the registered + /// `user_id` matches the provided `username`. + /// + /// The returned access token must be associated with the `device_id` + /// 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](https://spec.matrix.org/unstable/client-server-api/#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](https://spec.matrix.org/unstable/appendices/#user-identifiers). + /// + /// [kind] The kind of account to register. Defaults to `user`. + /// + /// [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. + /// + /// [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. + /// + /// [inhibitLogin] If true, an `access_token` and `device_id` should not be + /// returned from this call, therefore preventing an automatic + /// login. Defaults to false. + /// + /// [initialDeviceDisplayName] A display name to assign to the newly-created device. Ignored + /// if `device_id` corresponds to a known device. + /// + /// [password] The desired password for the account. + /// + /// [username] The basis for the localpart of the desired Matrix ID. If omitted, + /// the homeserver MUST generate a Matrix ID local part. + Future register( + {AccountKind? kind, + AuthenticationData? auth, + String? deviceId, + bool? inhibitLogin, + String? initialDeviceDisplayName, + String? password, + String? username}) async { + final requestUri = + Uri(path: '_matrix/client/r0/register', queryParameters: { + if (kind != null) + 'kind': {AccountKind.guest: 'guest', AccountKind.user: 'user'}[kind]!, + }); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (auth != null) 'auth': auth.toJson(), + if (deviceId != null) 'device_id': deviceId, + if (inhibitLogin != null) 'inhibit_login': inhibitLogin, + if (initialDeviceDisplayName != null) + 'initial_device_display_name': initialDeviceDisplayName, + if (password != null) 'password': password, + if (username != null) 'username': username, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return RegisterResponse.fromJson(json); + } + + /// Checks to see if a username is available, and valid, for the server. + /// + /// The server should check to ensure that, at the time of the request, the + /// username requested is available for use. This includes verifying that an + /// application service has not claimed the username and that the username + /// fits the server's desired requirements (for example, a server could dictate + /// that it does not permit usernames with underscores). + /// + /// Matrix clients may wish to use this API prior to attempting registration, + /// however the clients must also be aware that using this API does not normally + /// reserve the username. This can mean that the username becomes unavailable + /// between checking its availability and attempting to register it. + /// + /// [username] The username to check the availability of. + /// + /// returns `available`: + /// A flag to indicate that the username is available. This should always + /// be `true` when the server replies with 200 OK. + Future checkUsernameAvailability(String username) async { + final requestUri = + Uri(path: '_matrix/client/r0/register/available', queryParameters: { + 'username': username, + }); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ((v) => v != null ? v as bool : null)(json['available']); + } + + /// Store several keys in the backup. + /// + /// [version] The backup in which to store the keys. Must be the current backup. + /// + /// [backupData] The backup data. + Future postRoomKeysKey( + String version, RoomKeys backupData) async { + final requestUri = + Uri(path: '_matrix/client/unstable/room_keys/keys', queryParameters: { + 'version': version, + }); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode(backupData)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return PostRoomKeysKeyResponse.fromJson(json); + } + + /// Store a key in the backup. + /// + /// [roomId] The ID of the room that the keys are for. + /// + /// [version] The backup in which to store the keys. Must be the current backup. + /// + /// [backupData] The backup data + Future postRoomKeysKeyRoomId( + String roomId, String version, RoomKeyBackup backupData) async { + final requestUri = Uri( + path: + '_matrix/client/unstable/room_keys/keys/${Uri.encodeComponent(roomId)}', + queryParameters: { + 'version': version, + }); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode(backupData)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return PostRoomKeysKeyRoomIdResponse.fromJson(json); + } + + /// Store a key in the backup. + /// + /// [roomId] The ID of the room that the key is for. + /// + /// [sessionId] The ID of the megolm session that the key is for. + /// + /// [version] The backup in which to store the key. Must be the current backup. + /// + /// [data] The key data. + Future postRoomKeysKeyRoomIdSessionId( + String roomId, + String sessionId, + String version, + KeyBackupData data) async { + final requestUri = Uri( + path: + '_matrix/client/unstable/room_keys/keys/${Uri.encodeComponent(roomId)}/${Uri.encodeComponent(sessionId)}', + queryParameters: { + 'version': version, + }); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode(data)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return PostRoomKeysKeyRoomIdSessionIdResponse.fromJson(json); + } + + /// Get information about the latest backup version. + Future getRoomKeysVersionCurrent() async { + final requestUri = Uri(path: '_matrix/client/unstable/room_keys/version'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return GetRoomKeysVersionCurrentResponse.fromJson(json); + } + + /// Creates a new backup. + /// + /// [algorithm] The algorithm used for storing backups. + /// + /// [authData] Algorithm-dependent data. See the documentation for the backup + /// algorithms in [Server-side key backups](https://spec.matrix.org/unstable/client-server-api/#server-side-key-backups) for more information on the + /// expected format of the data. + /// + /// returns `version`: + /// The backup version. This is an opaque string. + Future postRoomKeysVersion( + BackupAlgorithm algorithm, Map authData) async { + final requestUri = Uri(path: '_matrix/client/unstable/room_keys/version'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + 'algorithm': { + BackupAlgorithm.mMegolmBackupV1Curve25519AesSha2: + 'm.megolm_backup.v1.curve25519-aes-sha2' + }[algorithm]!, + 'auth_data': authData, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return json['version'] as String; + } + + /// Delete an existing key backup. Both the information about the backup, + /// as well as all key data related to the backup will be deleted. + /// + /// [version] The backup version to delete, as returned in the `version` + /// parameter in the response of + /// [`POST /_matrix/client/r0/room_keys/version`](https://spec.matrix.org/unstable/client-server-api/#post_matrixclientr0room_keysversion) + /// or [`GET /_matrix/client/r0/room_keys/version/{version}`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientr0room_keysversionversion). + Future deleteRoomKeysVersion(String version) async { + final requestUri = Uri( + path: + '_matrix/client/unstable/room_keys/version/${Uri.encodeComponent(version)}'); + final request = Request('DELETE', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// Get information about an existing backup. + /// + /// [version] The backup version to get, as returned in the `version` parameter + /// of the response in + /// [`POST /_matrix/client/r0/room_keys/version`](https://spec.matrix.org/unstable/client-server/#post_matrixclientr0room_keysversion) + /// or this endpoint. + Future getRoomKeysVersion(String version) async { + final requestUri = Uri( + path: + '_matrix/client/unstable/room_keys/version/${Uri.encodeComponent(version)}'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return GetRoomKeysVersionResponse.fromJson(json); + } + + /// Update information about an existing backup. Only `auth_data` can be modified. + /// + /// [version] The backup version to update, as returned in the `version` + /// parameter in the response of + /// [`POST /_matrix/client/r0/room_keys/version`](https://spec.matrix.org/unstable/client-server-api/#post_matrixclientr0room_keysversion) + /// or [`GET /_matrix/client/r0/room_keys/version/{version}`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientr0room_keysversionversion). + /// + /// [algorithm] The algorithm used for storing backups. Must be the same as + /// the algorithm currently used by the backup. + /// + /// [authData] Algorithm-dependent data. See the documentation for the backup + /// algorithms in [Server-side key backups](https://spec.matrix.org/unstable/client-server-api/#server-side-key-backups) for more information on the + /// expected format of the data. + Future putRoomKeysVersion(String version, BackupAlgorithm algorithm, + Map authData) async { + final requestUri = Uri( + path: + '_matrix/client/unstable/room_keys/version/${Uri.encodeComponent(version)}'); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + 'algorithm': { + BackupAlgorithm.mMegolmBackupV1Curve25519AesSha2: + 'm.megolm_backup.v1.curve25519-aes-sha2' + }[algorithm]!, + 'auth_data': authData, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// 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. + /// + /// [roomId] The room ID to find local aliases of. + /// + /// returns `aliases`: + /// The server's local aliases on the room. Can be empty. + Future> getLocalAliases(String roomId) async { + final requestUri = Uri( + path: '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/aliases'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return (json['aliases'] as List).map((v) => v as String).toList(); + } + + /// Ban a user in the room. If the user is currently in the room, also kick them. + /// + /// When a user is banned from a room, they may not join it or be invited to it until they are unbanned. + /// + /// The caller must have the required power level in order to perform this operation. + /// + /// [roomId] The room identifier (not alias) from which the user should be banned. + /// + /// [reason] The reason the user has been banned. This will be supplied as the `reason` on the target's updated [`m.room.member`](https://spec.matrix.org/unstable/client-server-api/#mroommember) event. + /// + /// [userId] The fully qualified user ID of the user being banned. + Future ban(String roomId, String userId, {String? reason}) async { + final requestUri = + Uri(path: '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/ban'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (reason != null) 'reason': reason, + 'user_id': userId, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// 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](https://spec.matrix.org/unstable/client-server-api/#lazy-loading-room-members) for more information. + /// + /// [roomId] The room to get events from. + /// + /// [eventId] The event to get context around. + /// + /// [limit] The maximum number of events to return. Default: 10. + /// + /// [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](https://spec.matrix.org/unstable/client-server-api/#filtering) for more information. + Future getEventContext(String roomId, String eventId, + {int? limit, String? filter}) async { + final requestUri = Uri( + path: + '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/context/${Uri.encodeComponent(eventId)}', + queryParameters: { + if (limit != null) 'limit': limit.toString(), + if (filter != null) 'filter': filter, + }); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return EventContext.fromJson(json); + } + + /// Get a single event based on `roomId/eventId`. You must have permission to + /// retrieve this event e.g. by being a member in the room for this event. + /// + /// [roomId] The ID of the room the event is in. + /// + /// [eventId] The event ID to get. + Future getOneRoomEvent(String roomId, String eventId) async { + final requestUri = Uri( + path: + '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/event/${Uri.encodeComponent(eventId)}'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return MatrixEvent.fromJson(json); + } + + /// This API stops a user remembering about a particular room. + /// + /// In general, history is a first class citizen in Matrix. After this API + /// is called, however, a user will no longer be able to retrieve history + /// for this room. If all users on a homeserver forget a room, the room is + /// eligible for deletion from that homeserver. + /// + /// If the user is currently joined to the room, they must leave the room + /// before calling this API. + /// + /// [roomId] The room identifier to forget. + Future forgetRoom(String roomId) async { + final requestUri = Uri( + path: '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/forget'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// *Note that there are two forms of this API, which are documented separately. + /// This version of the API does not require that the inviter know the Matrix + /// identifier of the invitee, and instead relies on third party identifiers. + /// The homeserver uses an identity server to perform the mapping from + /// third party identifier to a Matrix identifier. The other is documented in the* + /// [joining rooms section](https://spec.matrix.org/unstable/client-server-api/#post_matrixclientr0roomsroomidinvite). + /// + /// This API invites a user to participate in a particular room. + /// They do not start participating in the room until they actually join the + /// room. + /// + /// Only users currently in a particular room can invite other users to + /// join that room. + /// + /// If the identity server did know the Matrix user identifier for the + /// third party identifier, the homeserver will append a `m.room.member` + /// event to the room. + /// + /// If the identity server does not know a Matrix user identifier for the + /// passed third party identifier, the homeserver will issue an invitation + /// which can be accepted upon providing proof of ownership of the third + /// party identifier. This is achieved by the identity server generating a + /// token, which it gives to the inviting homeserver. The homeserver will + /// add an `m.room.third_party_invite` event into the graph for the room, + /// containing that token. + /// + /// When the invitee binds the invited third party identifier to a Matrix + /// user ID, the identity server will give the user a list of pending + /// invitations, each containing: + /// + /// - The room ID to which they were invited + /// + /// - The token given to the homeserver + /// + /// - A signature of the token, signed with the identity server's private key + /// + /// - The matrix user ID who invited them to the room + /// + /// If a token is requested from the identity server, the homeserver will + /// append a `m.room.third_party_invite` event to the room. + /// + /// [roomId] The room identifier (not alias) to which to invite the user. + /// + /// [address] The invitee's third party identifier. + /// + /// [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. + /// + /// [idServer] The hostname+port of the identity server which should be used for third party identifier lookups. + /// + /// [medium] The kind of address being passed in the address field, for example `email`. + Future inviteBy3PID(String roomId, String address, String idAccessToken, + String idServer, String medium) async { + final requestUri = Uri( + path: '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/invite'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + 'address': address, + 'id_access_token': idAccessToken, + 'id_server': idServer, + 'medium': medium, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// *Note that there are two forms of this API, which are documented separately. + /// This version of the API requires that the inviter knows the Matrix + /// identifier of the invitee. The other is documented in the* + /// [third party invites section](https://spec.matrix.org/unstable/client-server-api/#post_matrixclientr0roomsroomidinvite-1). + /// + /// This API invites a user to participate in a particular room. + /// They do not start participating in the room until they actually join the + /// room. + /// + /// Only users currently in a particular room can invite other users to + /// join that room. + /// + /// If the user was invited to the room, the homeserver will append a + /// `m.room.member` event to the room. + /// + /// [roomId] The room identifier (not alias) to which to invite the user. + /// + /// [reason] Optional reason to be included as the `reason` on the subsequent + /// membership event. + /// + /// [userId] The fully qualified user ID of the invitee. + Future inviteUser(String roomId, String userId, + {String? reason}) async { + final requestUri = Uri( + path: '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/invite'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (reason != null) 'reason': reason, + 'user_id': userId, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// *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`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientr0initialsync) + /// and [`/sync`](https://spec.matrix.org/unstable/client-server-api/#get_matrixclientr0sync) APIs. + /// + /// [roomId] The room identifier (not alias) to join. + /// + /// [reason] Optional reason to be included as the `reason` on the subsequent + /// membership event. + /// + /// [thirdPartySigned] If 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. + /// + /// returns `room_id`: + /// The joined room ID. + Future joinRoomById(String roomId, + {String? reason, ThirdPartySigned? thirdPartySigned}) async { + final requestUri = Uri( + path: '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/join'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (reason != null) 'reason': reason, + if (thirdPartySigned != null) + 'third_party_signed': thirdPartySigned.toJson(), + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return json['room_id'] as String; + } + + /// This API returns a map of MXIDs to member info objects for members of the room. The current user must be in the room for it to work, unless it is an Application Service in which case any of the AS's users must be in the room. This API is primarily for Application Services and should be faster to respond than `/members` as it can be implemented more efficiently on the server. + /// + /// [roomId] The room to get the members of. + /// + /// returns `joined`: + /// A map from user ID to a RoomMember object. + Future?> getJoinedMembersByRoom(String roomId) async { + final requestUri = Uri( + path: + '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/joined_members'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ((v) => v != null + ? (v as Map) + .map((k, v) => MapEntry(k, RoomMember.fromJson(v))) + : null)(json['joined']); + } + + /// Kick a user from the room. + /// + /// The caller must have the required power level in order to perform this operation. + /// + /// Kicking a user adjusts the target member's membership state to be `leave` with an + /// optional `reason`. Like with other membership changes, a user can directly adjust + /// the target member's state by making a request to `/rooms//state/m.room.member/`. + /// + /// [roomId] The room identifier (not alias) from which the user should be kicked. + /// + /// [reason] The reason the user has been kicked. This will be supplied as the + /// `reason` on the target's updated [`m.room.member`](https://spec.matrix.org/unstable/client-server-api/#mroommember) event. + /// + /// [userId] The fully qualified user ID of the user being kicked. + Future kick(String roomId, String userId, {String? reason}) async { + final requestUri = Uri( + path: '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/kick'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (reason != null) 'reason': reason, + 'user_id': userId, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// This API stops a user participating in a particular room. + /// + /// If the user was already in the room, they will no longer be able to see + /// new events in the room. If the room requires an invite to join, they + /// will need to be re-invited before they can re-join. + /// + /// If the user was invited to the room, but had not joined, this call + /// serves to reject the invite. + /// + /// The user will still be allowed to retrieve history from the room which + /// they were previously allowed to see. + /// + /// [roomId] The room identifier to leave. + /// + /// [reason] Optional reason to be included as the `reason` on the subsequent + /// membership event. + Future leaveRoom(String roomId, {String? reason}) async { + final requestUri = Uri( + path: '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/leave'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (reason != null) 'reason': reason, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// Get the list of members for this room. + /// + /// [roomId] The room to get the member events for. + /// + /// [at] 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. + /// + /// [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`. + /// + /// [notMembership] The kind of membership to exclude from the results. Defaults to no + /// filtering if unspecified. + /// + /// returns `chunk` + Future?> getMembersByRoom(String roomId, + {String? at, Membership? membership, Membership? notMembership}) async { + final requestUri = Uri( + path: '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/members', + queryParameters: { + if (at != null) 'at': at, + if (membership != null) + 'membership': { + Membership.invite: 'invite', + Membership.join: 'join', + Membership.leave: 'leave', + Membership.ban: 'ban' + }[membership]!, + if (notMembership != null) + 'not_membership': { + Membership.invite: 'invite', + Membership.join: 'join', + Membership.leave: 'leave', + Membership.ban: 'ban' + }[notMembership]!, + }); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ((v) => v != null + ? (v as List).map((v) => MatrixEvent.fromJson(v)).toList() + : null)(json['chunk']); + } + + /// 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](https://spec.matrix.org/unstable/client-server-api/#lazy-loading-room-members) for more information. + /// + /// [roomId] The room to get events from. + /// + /// [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. + /// + /// [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. + /// + /// [dir] The direction to return events from. + /// + /// [limit] The maximum number of events to return. Default: 10. + /// + /// [filter] A JSON RoomEventFilter to filter returned events with. + Future getRoomEvents( + String roomId, String from, Direction dir, + {String? to, int? limit, String? filter}) async { + final requestUri = Uri( + path: '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/messages', + queryParameters: { + 'from': from, + if (to != null) 'to': to, + 'dir': {Direction.b: 'b', Direction.f: 'f'}[dir]!, + if (limit != null) 'limit': limit.toString(), + if (filter != null) 'filter': filter, + }); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return GetRoomEventsResponse.fromJson(json); + } + + /// Sets the position of the read marker for a given room, and optionally + /// the read receipt's location. + /// + /// [roomId] The room ID to set the read marker in for the user. + /// + /// [mFullyRead] The event ID the read marker should be located at. The + /// event MUST belong to the room. + /// + /// [mRead] The event ID to set the read receipt location at. This is + /// equivalent to calling `/receipt/m.read/$elsewhere:example.org` + /// and is provided here to save that extra call. + Future setReadMarker(String roomId, String mFullyRead, + {String? mRead}) async { + final requestUri = Uri( + path: + '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/read_markers'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + 'm.fully_read': mFullyRead, + if (mRead != null) 'm.read': mRead, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// This API updates the marker for the given receipt type to the event ID + /// specified. + /// + /// [roomId] The room in which to send the event. + /// + /// [receiptType] The type of receipt to send. + /// + /// [eventId] The event ID to acknowledge up to. + /// + /// [receipt] Extra receipt information to attach to `content` if any. The + /// server will automatically set the `ts` field. + Future postReceipt(String roomId, ReceiptType receiptType, + String eventId, Map receipt) async { + final requestUri = Uri( + path: + '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/receipt/${Uri.encodeComponent({ + ReceiptType.mRead: 'm.read' + }[receiptType]!)}/${Uri.encodeComponent(eventId)}'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode(receipt)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// Strips all information out of an event which isn't critical to the + /// integrity of the server-side representation of the room. + /// + /// This cannot be undone. + /// + /// Any user with a power level greater than or equal to the `m.room.redaction` + /// event power level may send redaction events in the room. If the user's power + /// level greater is also greater than or equal to the `redact` power level + /// of the room, the user may redact events sent by other users. + /// + /// Server administrators may redact events sent by users on their server. + /// + /// [roomId] The room from which to redact the event. + /// + /// [eventId] The ID of the event to redact + /// + /// [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. + /// + /// [reason] The reason for the event being redacted. + /// + /// returns `event_id`: + /// A unique identifier for the event. + Future redactEvent(String roomId, String eventId, String txnId, + {String? reason}) async { + final requestUri = Uri( + path: + '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/redact/${Uri.encodeComponent(eventId)}/${Uri.encodeComponent(txnId)}'); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (reason != null) 'reason': reason, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ((v) => v != null ? v as String : null)(json['event_id']); + } + + /// Reports an event as inappropriate to the server, which may then notify + /// the appropriate people. + /// + /// [roomId] The room in which the event being reported is located. + /// + /// [eventId] The event to report. + /// + /// [reason] The reason the content is being reported. May be blank. + /// + /// [score] The score to rate this content as where -100 is most offensive + /// and 0 is inoffensive. + Future reportContent(String roomId, String eventId, + {String? reason, int? score}) async { + final requestUri = Uri( + path: + '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/report/${Uri.encodeComponent(eventId)}'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (reason != null) 'reason': reason, + if (score != null) 'score': score, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// This endpoint is used to send a message event to a room. Message events + /// allow access to historical events and pagination, making them suited + /// for "once-off" activity in a room. + /// + /// 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](https://spec.matrix.org/unstable/client-server-api/#room-events) for the m. event specification. + /// + /// [roomId] The room to send the event to. + /// + /// [eventType] The type of event to send. + /// + /// [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. + /// + /// returns `event_id`: + /// A unique identifier for the event. + Future sendMessage(String roomId, String eventType, String txnId, + Map body) async { + final requestUri = Uri( + path: + '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/send/${Uri.encodeComponent(eventType)}/${Uri.encodeComponent(txnId)}'); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode(body)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return json['event_id'] as String; + } + + /// Get the state events for the current state of a room. + /// + /// [roomId] The room to look up the state for. + Future> getRoomState(String roomId) async { + final requestUri = Uri( + path: '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/state'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return (json as List).map((v) => MatrixEvent.fromJson(v)).toList(); + } + + /// 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. + /// + /// [roomId] The room to look up the state in. + /// + /// [eventType] The type of state to look up. + /// + /// [stateKey] 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. + Future> getRoomStateWithKey( + String roomId, String eventType, String stateKey) async { + final requestUri = Uri( + path: + '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/state/${Uri.encodeComponent(eventType)}/${Uri.encodeComponent(stateKey)}'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return json as Map; + } + + /// State events can be sent using this endpoint. These events will be + /// overwritten if ``, `` and `` all + /// match. + /// + /// 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](https://spec.matrix.org/unstable/client-server-api/#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. + /// + /// + /// [roomId] The room to set the state in + /// + /// [eventType] The type of event to send. + /// + /// [stateKey] 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. + /// + /// returns `event_id`: + /// A unique identifier for the event. + Future setRoomStateWithKey(String roomId, String eventType, + String stateKey, Map body) async { + final requestUri = Uri( + path: + '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/state/${Uri.encodeComponent(eventType)}/${Uri.encodeComponent(stateKey)}'); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode(body)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return json['event_id'] as String; + } + + /// This tells the server that the user is typing for the next N + /// milliseconds where N is the value specified in the `timeout` key. + /// Alternatively, if `typing` is `false`, it tells the server that the + /// user has stopped typing. + /// + /// [userId] The user who has started to type. + /// + /// [roomId] The room in which the user is typing. + /// + /// [timeout] The length of time in milliseconds to mark this user as typing. + /// + /// [typing] Whether the user is typing or not. If `false`, the `timeout` + /// key can be omitted. + Future setTyping(String userId, String roomId, bool typing, + {int? timeout}) async { + final requestUri = Uri( + path: + '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/typing/${Uri.encodeComponent(userId)}'); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (timeout != null) 'timeout': timeout, + 'typing': typing, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// Unban a user from the room. This allows them to be invited to the room, + /// and join if they would otherwise be allowed to join according to its join rules. + /// + /// The caller must have the required power level in order to perform this operation. + /// + /// [roomId] The room identifier (not alias) from which the user should be unbanned. + /// + /// [reason] Optional reason to be included as the `reason` on the subsequent + /// membership event. + /// + /// [userId] The fully qualified user ID of the user being unbanned. + Future unban(String roomId, String userId, {String? reason}) async { + final requestUri = Uri( + path: '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/unban'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (reason != null) 'reason': reason, + 'user_id': userId, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// Upgrades the given room to a particular room version. + /// + /// [roomId] The ID of the room to upgrade. + /// + /// [newVersion] The new version for the room. + /// + /// returns `replacement_room`: + /// The ID of the new room. + Future upgradeRoom(String roomId, String newVersion) async { + final requestUri = Uri( + path: '_matrix/client/r0/rooms/${Uri.encodeComponent(roomId)}/upgrade'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + 'new_version': newVersion, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return json['replacement_room'] as String; + } + + /// Performs a full text search across different categories. + /// + /// [nextBatch] The point to return events from. If given, this should be a + /// `next_batch` result from a previous call to this endpoint. + /// + /// [searchCategories] Describes which categories to search in and their criteria. + Future search(Categories searchCategories, + {String? nextBatch}) async { + final requestUri = Uri(path: '_matrix/client/r0/search', queryParameters: { + if (nextBatch != null) 'next_batch': nextBatch, + }); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + 'search_categories': searchCategories.toJson(), + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return SearchResults.fromJson(json); + } + + /// This endpoint is used to send send-to-device events to a set of + /// client devices. + /// + /// [eventType] The type of event to send. + /// + /// [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. + /// + /// [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 `*`, + /// meaning all known devices for the user. + Future sendToDevice(String eventType, String txnId, + Map>> messages) async { + final requestUri = Uri( + path: + '_matrix/client/r0/sendToDevice/${Uri.encodeComponent(eventType)}/${Uri.encodeComponent(txnId)}'); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + 'messages': + messages.map((k, v) => MapEntry(k, v.map((k, v) => MapEntry(k, v)))), + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// Synchronise the client's state with the latest state on the server. + /// Clients use this API when they first log in to get an initial snapshot + /// of the state on the server, and then continue to call this API to get + /// incremental deltas to the state, and to receive new messages. + /// + /// *Note*: This endpoint supports lazy-loading. See [Filtering](https://spec.matrix.org/unstable/client-server-api/#filtering) + /// for more information. Lazy-loading members is only supported on a `StateFilter` + /// for this endpoint. When lazy-loading is enabled, servers MUST include the + /// syncing user's own membership event when they join a room, or when the + /// full state of rooms is requested, to aid discovering the user's avatar & + /// displayname. + /// + /// Further, like other members, the user's own membership event is eligible + /// for being considered redundant by the server. When a sync is `limited`, + /// the server MUST return membership events for events in the gap + /// (between `since` and the start of the returned timeline), regardless + /// as to whether or not they are redundant. This ensures that joins/leaves + /// and profile changes which occur during the gap are not lost. + /// + /// Note that the default behaviour of `state` is to include all membership + /// events, alongside other state, when lazy-loading is not enabled. + /// + /// [filter] The ID of a filter created using the filter API or a filter JSON + /// object encoded as a string. The server will detect whether it is + /// an ID or a JSON object by whether the first character is a `"{"` + /// open brace. Passing the JSON inline is best suited to one off + /// requests. Creating a filter using the filter API is recommended for + /// clients that reuse the same filter multiple times, for example in + /// long poll requests. + /// + /// See [Filtering](https://spec.matrix.org/unstable/client-server-api/#filtering) for more information. + /// + /// [since] A point in time to continue a sync from. + /// + /// [fullState] Controls whether to include the full state for all rooms the user + /// is a member of. + /// + /// If this is set to `true`, then all state events will be returned, + /// even if `since` is non-empty. The timeline will still be limited + /// by the `since` parameter. In this case, the `timeout` parameter + /// will be ignored and the query will return immediately, possibly with + /// an empty timeline. + /// + /// If `false`, and `since` is non-empty, only state which has + /// changed since the point indicated by `since` will be returned. + /// + /// By default, this is `false`. + /// + /// [setPresence] Controls whether the client is automatically marked as online by + /// polling this API. If this parameter is omitted then the client is + /// automatically marked as online when it uses this API. Otherwise if + /// the parameter is set to "offline" then the client is not marked as + /// being online when it uses this API. When set to "unavailable", the + /// client is marked as being idle. + /// + /// [timeout] The maximum time to wait, in milliseconds, before returning this + /// request. If no events (or other data) become available before this + /// time elapses, the server will return a response with empty fields. + /// + /// By default, this is `0`, so the server will return immediately + /// even if the response is empty. + Future sync( + {String? filter, + String? since, + bool? fullState, + PresenceType? setPresence, + int? timeout}) async { + final requestUri = Uri(path: '_matrix/client/r0/sync', queryParameters: { + if (filter != null) 'filter': filter, + if (since != null) 'since': since, + if (fullState != null) 'full_state': fullState.toString(), + if (setPresence != null) + 'set_presence': { + PresenceType.online: 'online', + PresenceType.offline: 'offline', + PresenceType.unavailable: 'unavailable' + }[setPresence]!, + if (timeout != null) 'timeout': timeout.toString(), + }); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return SyncUpdate.fromJson(json); + } + + /// Get some account_data for the client. This config is only visible to the user + /// that set the account_data. + /// + /// [userId] The ID of the user to get account_data for. The access token must be + /// authorized to make requests for this user ID. + /// + /// [type] The event type of the account_data to get. Custom types should be + /// namespaced to avoid clashes. + Future> getAccountData( + String userId, String type) async { + final requestUri = Uri( + path: + '_matrix/client/r0/user/${Uri.encodeComponent(userId)}/account_data/${Uri.encodeComponent(type)}'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return json as Map; + } + + /// Set some account_data for the client. This config is only visible to the user + /// that set the account_data. The config will be synced to clients in the + /// top-level `account_data`. + /// + /// [userId] The ID of the user to set account_data for. The access token must be + /// authorized to make requests for this user ID. + /// + /// [type] The event type of the account_data to set. Custom types should be + /// namespaced to avoid clashes. + /// + /// [content] The content of the account_data + Future setAccountData( + String userId, String type, Map content) async { + final requestUri = Uri( + path: + '_matrix/client/r0/user/${Uri.encodeComponent(userId)}/account_data/${Uri.encodeComponent(type)}'); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode(content)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// 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. + /// + /// [userId] The id of the user uploading the filter. The access token must be authorized to make requests for this user id. + /// + /// [filter] The filter to upload. + /// + /// returns `filter_id`: + /// 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. + Future defineFilter(String userId, Filter filter) async { + final requestUri = Uri( + path: '_matrix/client/r0/user/${Uri.encodeComponent(userId)}/filter'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode(filter)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return json['filter_id'] as String; + } + + /// getFilter + /// + /// [userId] The user ID to download a filter for. + /// + /// [filterId] The filter ID to download. + Future getFilter(String userId, String filterId) async { + final requestUri = Uri( + path: + '_matrix/client/r0/user/${Uri.encodeComponent(userId)}/filter/${Uri.encodeComponent(filterId)}'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return Filter.fromJson(json); + } + + /// Gets an OpenID token object that the requester may supply to another + /// service to verify their identity in Matrix. The generated token is only + /// valid for exchanging for user information from the federation API for + /// OpenID. + /// + /// The access token generated is only valid for the OpenID API. It cannot + /// be used to request another OpenID access token or call `/sync`, for + /// example. + /// + /// [userId] The user to request and OpenID token for. Should be the user who + /// is authenticated for the request. + /// + /// [body] An empty object. Reserved for future expansion. + Future requestOpenIdToken( + String userId, Map body) async { + final requestUri = Uri( + path: + '_matrix/client/r0/user/${Uri.encodeComponent(userId)}/openid/request_token'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode(body)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return OpenIdCredentials.fromJson(json); + } + + /// Get some account_data for the client on a given room. This config is only + /// visible to the user that set the account_data. + /// + /// [userId] The ID of the user to set account_data for. The access token must be + /// authorized to make requests for this user ID. + /// + /// [roomId] The ID of the room to get account_data for. + /// + /// [type] The event type of the account_data to get. Custom types should be + /// namespaced to avoid clashes. + Future> getAccountDataPerRoom( + String userId, String roomId, String type) async { + final requestUri = Uri( + path: + '_matrix/client/r0/user/${Uri.encodeComponent(userId)}/rooms/${Uri.encodeComponent(roomId)}/account_data/${Uri.encodeComponent(type)}'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return json as Map; + } + + /// Set some account_data for the client on a given room. This config is only + /// visible to the user that set the account_data. The config will be synced to + /// clients in the per-room `account_data`. + /// + /// [userId] The ID of the user to set account_data for. The access token must be + /// authorized to make requests for this user ID. + /// + /// [roomId] The ID of the room to set account_data on. + /// + /// [type] The event type of the account_data to set. Custom types should be + /// namespaced to avoid clashes. + /// + /// [content] The content of the account_data + Future setAccountDataPerRoom(String userId, String roomId, String type, + Map content) async { + final requestUri = Uri( + path: + '_matrix/client/r0/user/${Uri.encodeComponent(userId)}/rooms/${Uri.encodeComponent(roomId)}/account_data/${Uri.encodeComponent(type)}'); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode(content)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// List the tags set by a user on a room. + /// + /// [userId] The id of the user to get tags for. The access token must be + /// authorized to make requests for this user ID. + /// + /// [roomId] The ID of the room to get tags for. + /// + /// returns `tags` + Future?> getRoomTags(String userId, String roomId) async { + final requestUri = Uri( + path: + '_matrix/client/r0/user/${Uri.encodeComponent(userId)}/rooms/${Uri.encodeComponent(roomId)}/tags'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ((v) => v != null + ? (v as Map) + .map((k, v) => MapEntry(k, Tag.fromJson(v))) + : null)(json['tags']); + } + + /// Remove a tag from the room. + /// + /// [userId] The id of the user to remove a tag for. The access token must be + /// authorized to make requests for this user ID. + /// + /// [roomId] The ID of the room to remove a tag from. + /// + /// [tag] The tag to remove. + Future deleteRoomTag(String userId, String roomId, String tag) async { + final requestUri = Uri( + path: + '_matrix/client/r0/user/${Uri.encodeComponent(userId)}/rooms/${Uri.encodeComponent(roomId)}/tags/${Uri.encodeComponent(tag)}'); + final request = Request('DELETE', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// Add a tag to the room. + /// + /// [userId] The id of the user to add a tag for. The access token must be + /// authorized to make requests for this user ID. + /// + /// [roomId] The ID of the room to add a tag to. + /// + /// [tag] The tag to add. + /// + /// [order] A number in a range `[0,1]` describing a relative + /// position of the room under the given tag. + Future setRoomTag(String userId, String roomId, String tag, + {double? order, + Map additionalProperties = const {}}) async { + final requestUri = Uri( + path: + '_matrix/client/r0/user/${Uri.encodeComponent(userId)}/rooms/${Uri.encodeComponent(roomId)}/tags/${Uri.encodeComponent(tag)}'); + final request = Request('PUT', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + ...additionalProperties, + if (order != null) 'order': order, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ignore(json); + } + + /// 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). + /// The search MUST consider local users to the homeserver, and SHOULD + /// query remote users as part of the search. + /// + /// 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. + /// + /// [limit] The maximum number of results to return. Defaults to 10. + /// + /// [searchTerm] The term to search for + Future searchUserDirectory(String searchTerm, + {int? limit}) async { + final requestUri = Uri(path: '_matrix/client/r0/user_directory/search'); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + request.headers['content-type'] = 'application/json'; + request.bodyBytes = utf8.encode(jsonEncode({ + if (limit != null) 'limit': limit, + 'search_term': searchTerm, + })); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return SearchUserDirectoryResponse.fromJson(json); + } + + /// This API provides credentials for the client to use when initiating + /// calls. + Future getTurnServer() async { + final requestUri = Uri(path: '_matrix/client/r0/voip/turnServer'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return TurnServerCredentials.fromJson(json); + } + + /// Gets the versions of the specification supported by the server. + /// + /// Values will take the form `rX.Y.Z`. + /// + /// Only the latest `Z` value will be reported for each supported `X.Y` value. + /// i.e. if the server implements `r0.0.0`, `r0.0.1`, and `r1.2.0`, it will report `r0.0.1` and `r1.2.0`. + /// + /// The server may additionally advertise experimental features it supports + /// through `unstable_features`. These features should be namespaced and + /// may optionally include version information within their name if desired. + /// Features listed here are not for optionally toggling parts of the Matrix + /// specification and should only be used to advertise support for a feature + /// which has not yet landed in the spec. For example, a feature currently + /// undergoing the proposal process may appear here and eventually be taken + /// off this list once the feature lands in the spec and the server deems it + /// reasonable to do so. Servers may wish to keep advertising features here + /// after they've been released into the spec to give clients a chance to + /// upgrade appropriately. Additionally, clients should avoid using unstable + /// features in their stable releases. + Future getVersions() async { + final requestUri = Uri(path: '_matrix/client/versions'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return GetVersionsResponse.fromJson(json); + } + + /// This endpoint allows clients to retrieve the configuration of the content + /// repository, such as upload limitations. + /// Clients SHOULD use this as a guide when using content repository endpoints. + /// All values are intentionally left optional. Clients SHOULD follow + /// the advice given in the field description when the field is not available. + /// + /// **NOTE:** Both clients and server administrators should be aware that proxies + /// between the client and the server may affect the apparent behaviour of content + /// repository APIs, for example, proxies may enforce a lower upload size limit + /// than is advertised by the server on this endpoint. + Future getConfig() async { + final requestUri = Uri(path: '_matrix/media/r0/config'); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return ServerConfig.fromJson(json); + } + + /// getContent + /// + /// [serverName] The server name from the `mxc://` URI (the authoritory component) + /// + /// + /// [mediaId] The media ID from the `mxc://` URI (the path component) + /// + /// + /// [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. + /// + Future getContent(String serverName, String mediaId, + {bool? allowRemote}) async { + final requestUri = Uri( + path: + '_matrix/media/r0/download/${Uri.encodeComponent(serverName)}/${Uri.encodeComponent(mediaId)}', + queryParameters: { + if (allowRemote != null) 'allow_remote': allowRemote.toString(), + }); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + return FileResponse( + contentType: response.headers['content-type'], data: responseBody); + } + + /// This will download content from the content repository (same as + /// the previous endpoint) but replace the target file name with the one + /// provided by the caller. + /// + /// [serverName] The server name from the `mxc://` URI (the authoritory component) + /// + /// + /// [mediaId] The media ID from the `mxc://` URI (the path component) + /// + /// + /// [fileName] A filename to give in the `Content-Disposition` header. + /// + /// [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. + /// + Future getContentOverrideName( + String serverName, String mediaId, String fileName, + {bool? allowRemote}) async { + final requestUri = Uri( + path: + '_matrix/media/r0/download/${Uri.encodeComponent(serverName)}/${Uri.encodeComponent(mediaId)}/${Uri.encodeComponent(fileName)}', + queryParameters: { + if (allowRemote != null) 'allow_remote': allowRemote.toString(), + }); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + return FileResponse( + contentType: response.headers['content-type'], data: responseBody); + } + + /// 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. + /// + /// [url] The URL to get a preview of. + /// + /// [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 + /// available. + Future getUrlPreview(Uri url, {int? ts}) async { + final requestUri = + Uri(path: '_matrix/media/r0/preview_url', queryParameters: { + 'url': url.toString(), + if (ts != null) 'ts': ts.toString(), + }); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return GetUrlPreviewResponse.fromJson(json); + } + + /// Download a thumbnail of content from the content repository. + /// See the [Thumbnails](https://spec.matrix.org/unstable/client-server-api/#thumbnails) section for more information. + /// + /// [serverName] The server name from the `mxc://` URI (the authoritory component) + /// + /// + /// [mediaId] The media ID from the `mxc://` URI (the path component) + /// + /// + /// [width] The *desired* width of the thumbnail. The actual thumbnail may be + /// larger than the size specified. + /// + /// [height] The *desired* height of the thumbnail. The actual thumbnail may be + /// larger than the size specified. + /// + /// [method] The desired resizing method. See the [Thumbnails](https://spec.matrix.org/unstable/client-server-api/#thumbnails) + /// section for more information. + /// + /// [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. + Future getContentThumbnail( + String serverName, String mediaId, int width, int height, + {Method? method, bool? allowRemote}) async { + final requestUri = Uri( + path: + '_matrix/media/r0/thumbnail/${Uri.encodeComponent(serverName)}/${Uri.encodeComponent(mediaId)}', + queryParameters: { + 'width': width.toString(), + 'height': height.toString(), + if (method != null) + 'method': {Method.crop: 'crop', Method.scale: 'scale'}[method]!, + if (allowRemote != null) 'allow_remote': allowRemote.toString(), + }); + final request = Request('GET', baseUri!.resolveUri(requestUri)); + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + return FileResponse( + contentType: response.headers['content-type'], data: responseBody); + } + + /// uploadContent + /// + /// [contentType] The content type of the file being uploaded + /// + /// [filename] The name of the file being uploaded + /// + /// [content] The content to be uploaded. + /// + /// returns `content_uri`: + /// The [MXC URI](https://spec.matrix.org/unstable/client-server-api/#matrix-content-mxc-uris) to the uploaded content. + Future uploadContent(Uint8List content, + {String? contentType, String? filename}) async { + final requestUri = Uri(path: '_matrix/media/r0/upload', queryParameters: { + if (filename != null) 'filename': filename, + }); + final request = Request('POST', baseUri!.resolveUri(requestUri)); + request.headers['authorization'] = 'Bearer ${bearerToken!}'; + if (contentType != null) request.headers['content-type'] = contentType; + request.bodyBytes = content; + final response = await httpClient.send(request); + final responseBody = await response.stream.toBytes(); + if (response.statusCode != 200) unexpectedResponse(response, responseBody); + final responseString = utf8.decode(responseBody); + final json = jsonDecode(responseString); + return json['content_uri'] as String; + } +} diff --git a/lib/src/generated/fixed_model.dart b/lib/src/generated/fixed_model.dart new file mode 100644 index 00000000..22c27070 --- /dev/null +++ b/lib/src/generated/fixed_model.dart @@ -0,0 +1,7 @@ +import 'dart:typed_data'; + +class FileResponse { + FileResponse({this.contentType, required this.data}); + String? contentType; + Uint8List data; +} diff --git a/lib/src/generated/internal.dart b/lib/src/generated/internal.dart new file mode 100644 index 00000000..48d80d0c --- /dev/null +++ b/lib/src/generated/internal.dart @@ -0,0 +1,6 @@ +import 'fixed_model.dart'; + +void ignore(Object? input) {} +FileResponse ignoreFile(dynamic input) { + throw UnimplementedError(); +} diff --git a/lib/src/generated/model.dart b/lib/src/generated/model.dart new file mode 100644 index 00000000..71989bcc --- /dev/null +++ b/lib/src/generated/model.dart @@ -0,0 +1,3113 @@ +import '../model/auth/authentication_data.dart'; +import '../model/auth/authentication_types.dart'; +import '../model/auth/authentication_identifier.dart'; +import '../model/matrix_keys.dart'; +import '../model/sync_update.dart'; +import '../model/matrix_event.dart'; + +import 'internal.dart'; + +class _NameSource { + final String source; + const _NameSource(this.source); +} + +@_NameSource('spec') +class HomeserverInformation { + HomeserverInformation({ + required this.baseUrl, + }); + + HomeserverInformation.fromJson(Map json) + : baseUrl = Uri.parse(json['base_url']); + Map toJson() => { + 'base_url': baseUrl.toString(), + }; + + /// The base URL for the homeserver for client-server connections. + Uri baseUrl; +} + +@_NameSource('spec') +class IdentityServerInformation { + IdentityServerInformation({ + required this.baseUrl, + }); + + IdentityServerInformation.fromJson(Map json) + : baseUrl = Uri.parse(json['base_url']); + Map toJson() => { + 'base_url': baseUrl.toString(), + }; + + /// The base URL for the identity server for client-server connections. + Uri baseUrl; +} + +/// Used by clients to determine the homeserver, identity server, and other +/// optional components they should be interacting with. +@_NameSource('spec') +class DiscoveryInformation { + DiscoveryInformation({ + required this.mHomeserver, + this.mIdentityServer, + this.additionalProperties = const {}, + }); + + DiscoveryInformation.fromJson(Map json) + : mHomeserver = HomeserverInformation.fromJson(json['m.homeserver']), + mIdentityServer = ((v) => v != null + ? IdentityServerInformation.fromJson(v) + : null)(json['m.identity_server']), + additionalProperties = Map.fromEntries(json.entries + .where( + (e) => !['m.homeserver', 'm.identity_server'].contains(e.key)) + .map((e) => MapEntry(e.key, e.value as Map))); + Map toJson() { + final mIdentityServer = this.mIdentityServer; + return { + ...additionalProperties, + 'm.homeserver': mHomeserver.toJson(), + if (mIdentityServer != null) + 'm.identity_server': mIdentityServer.toJson(), + }; + } + + /// Used by clients to discover homeserver information. + HomeserverInformation mHomeserver; + + /// Used by clients to discover identity server information. + IdentityServerInformation? mIdentityServer; + + Map> additionalProperties; +} + +@_NameSource('rule override generated') +enum ThirdPartyIdentifierMedium { email, msisdn } + +@_NameSource('spec') +class ThirdPartyIdentifier { + ThirdPartyIdentifier({ + required this.addedAt, + required this.address, + required this.medium, + required this.validatedAt, + }); + + ThirdPartyIdentifier.fromJson(Map json) + : addedAt = json['added_at'] as int, + address = json['address'] as String, + medium = { + 'email': ThirdPartyIdentifierMedium.email, + 'msisdn': ThirdPartyIdentifierMedium.msisdn + }[json['medium']]!, + validatedAt = json['validated_at'] as int; + Map toJson() => { + 'added_at': addedAt, + 'address': address, + 'medium': { + ThirdPartyIdentifierMedium.email: 'email', + ThirdPartyIdentifierMedium.msisdn: 'msisdn' + }[medium]!, + 'validated_at': validatedAt, + }; + + /// The timestamp, in milliseconds, when the homeserver associated the third party identifier with the user. + int addedAt; + + /// The third party identifier address. + String address; + + /// The medium of the third party identifier. + ThirdPartyIdentifierMedium medium; + + /// The timestamp, in milliseconds, when the identifier was + /// validated by the identity server. + int validatedAt; +} + +@_NameSource('spec') +class ThreePidCredentials { + ThreePidCredentials({ + required this.clientSecret, + required this.idAccessToken, + required this.idServer, + required this.sid, + }); + + ThreePidCredentials.fromJson(Map json) + : clientSecret = json['client_secret'] as String, + idAccessToken = json['id_access_token'] as String, + idServer = json['id_server'] as String, + sid = json['sid'] as String; + Map toJson() => { + 'client_secret': clientSecret, + 'id_access_token': idAccessToken, + 'id_server': idServer, + 'sid': sid, + }; + + /// The client secret used in the session with the identity server. + String clientSecret; + + /// 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. + String idAccessToken; + + /// The identity server to use. + String idServer; + + /// The session identifier given by the identity server. + String sid; +} + +@_NameSource('generated') +enum IdServerUnbindResult { noSupport, success } + +@_NameSource('rule override generated') +class TokenOwnerInfo { + TokenOwnerInfo({ + this.deviceId, + required this.userId, + }); + + TokenOwnerInfo.fromJson(Map json) + : deviceId = ((v) => v != null ? v as String : null)(json['device_id']), + userId = json['user_id'] as String; + Map toJson() { + final deviceId = this.deviceId; + return { + if (deviceId != null) 'device_id': deviceId, + 'user_id': userId, + }; + } + + /// Device ID associated with the access token. If no device + /// is associated with the access token (such as in the case + /// of application services) then this field can be omitted. + /// Otherwise this is required. + String? deviceId; + + /// The user ID that owns the access token. + String userId; +} + +@_NameSource('spec') +class ConnectionInfo { + ConnectionInfo({ + this.ip, + this.lastSeen, + this.userAgent, + }); + + ConnectionInfo.fromJson(Map json) + : ip = ((v) => v != null ? v as String : null)(json['ip']), + lastSeen = ((v) => v != null ? v as int : null)(json['last_seen']), + userAgent = ((v) => v != null ? v as String : null)(json['user_agent']); + Map toJson() { + final ip = this.ip; + final lastSeen = this.lastSeen; + final userAgent = this.userAgent; + return { + if (ip != null) 'ip': ip, + if (lastSeen != null) 'last_seen': lastSeen, + if (userAgent != null) 'user_agent': userAgent, + }; + } + + /// Most recently seen IP address of the session. + String? ip; + + /// Unix timestamp that the session was last active. + int? lastSeen; + + /// User agent string last seen in the session. + String? userAgent; +} + +@_NameSource('spec') +class SessionInfo { + SessionInfo({ + this.connections, + }); + + SessionInfo.fromJson(Map json) + : connections = ((v) => v != null + ? (v as List).map((v) => ConnectionInfo.fromJson(v)).toList() + : null)(json['connections']); + Map toJson() { + final connections = this.connections; + return { + if (connections != null) + 'connections': connections.map((v) => v.toJson()).toList(), + }; + } + + /// Information particular connections in the session. + List? connections; +} + +@_NameSource('spec') +class DeviceInfo { + DeviceInfo({ + this.sessions, + }); + + DeviceInfo.fromJson(Map json) + : sessions = ((v) => v != null + ? (v as List).map((v) => SessionInfo.fromJson(v)).toList() + : null)(json['sessions']); + Map toJson() { + final sessions = this.sessions; + return { + if (sessions != null) + 'sessions': sessions.map((v) => v.toJson()).toList(), + }; + } + + /// A user's sessions (i.e. what they did with an access token from one login). + List? sessions; +} + +@_NameSource('rule override generated') +class WhoIsInfo { + WhoIsInfo({ + this.devices, + this.userId, + }); + + WhoIsInfo.fromJson(Map json) + : devices = ((v) => v != null + ? (v as Map) + .map((k, v) => MapEntry(k, DeviceInfo.fromJson(v))) + : null)(json['devices']), + userId = ((v) => v != null ? v as String : null)(json['user_id']); + Map toJson() { + final devices = this.devices; + final userId = this.userId; + return { + if (devices != null) + 'devices': devices.map((k, v) => MapEntry(k, v.toJson())), + if (userId != null) 'user_id': userId, + }; + } + + /// Each key is an identifier for one of the user's devices. + Map? devices; + + /// The Matrix user ID of the user. + String? userId; +} + +@_NameSource('spec') +class ChangePasswordCapability { + ChangePasswordCapability({ + required this.enabled, + }); + + ChangePasswordCapability.fromJson(Map json) + : enabled = json['enabled'] as bool; + Map toJson() => { + 'enabled': enabled, + }; + + /// True if the user can change their password, false otherwise. + bool enabled; +} + +/// The stability of the room version. +@_NameSource('rule override generated') +enum RoomVersionAvailable { stable, unstable } + +@_NameSource('spec') +class RoomVersionsCapability { + RoomVersionsCapability({ + required this.available, + required this.default$, + }); + + RoomVersionsCapability.fromJson(Map json) + : available = (json['available'] as Map).map((k, v) => + MapEntry( + k, + { + 'stable': RoomVersionAvailable.stable, + 'unstable': RoomVersionAvailable.unstable + }[v]!)), + default$ = json['default'] as String; + Map toJson() => { + 'available': available.map((k, v) => MapEntry( + k, + { + RoomVersionAvailable.stable: 'stable', + RoomVersionAvailable.unstable: 'unstable' + }[v]!)), + 'default': default$, + }; + + /// A detailed description of the room versions the server supports. + Map available; + + /// The default room version the server is using for new rooms. + String default$; +} + +@_NameSource('spec') +class Capabilities { + Capabilities({ + this.mChangePassword, + this.mRoomVersions, + this.additionalProperties = const {}, + }); + + Capabilities.fromJson(Map json) + : mChangePassword = ((v) => v != null + ? ChangePasswordCapability.fromJson(v) + : null)(json['m.change_password']), + mRoomVersions = ((v) => v != null + ? RoomVersionsCapability.fromJson(v) + : null)(json['m.room_versions']), + additionalProperties = Map.fromEntries(json.entries + .where((e) => + !['m.change_password', 'm.room_versions'].contains(e.key)) + .map((e) => MapEntry(e.key, e.value as Map))); + Map toJson() { + final mChangePassword = this.mChangePassword; + final mRoomVersions = this.mRoomVersions; + return { + ...additionalProperties, + if (mChangePassword != null) + 'm.change_password': mChangePassword.toJson(), + if (mRoomVersions != null) 'm.room_versions': mRoomVersions.toJson(), + }; + } + + /// Capability to indicate if the user can change their password. + ChangePasswordCapability? mChangePassword; + + /// The room versions the server supports. + RoomVersionsCapability? mRoomVersions; + + Map> additionalProperties; +} + +@_NameSource('spec') +class StateEvent { + StateEvent({ + required this.content, + this.stateKey, + required this.type, + }); + + StateEvent.fromJson(Map json) + : content = json['content'] as Map, + stateKey = ((v) => v != null ? v as String : null)(json['state_key']), + type = json['type'] as String; + Map toJson() { + final stateKey = this.stateKey; + return { + 'content': content, + if (stateKey != null) 'state_key': stateKey, + 'type': type, + }; + } + + /// The content of the event. + Map content; + + /// The state_key of the state event. Defaults to an empty string. + String? stateKey; + + /// The type of event to send. + String type; +} + +@_NameSource('spec') +class Invite3pid { + Invite3pid({ + required this.address, + required this.idAccessToken, + required this.idServer, + required this.medium, + }); + + Invite3pid.fromJson(Map json) + : address = json['address'] as String, + idAccessToken = json['id_access_token'] as String, + idServer = json['id_server'] as String, + medium = json['medium'] as String; + Map toJson() => { + 'address': address, + 'id_access_token': idAccessToken, + 'id_server': idServer, + 'medium': medium, + }; + + /// The invitee's third party identifier. + String address; + + /// 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. + String idAccessToken; + + /// The hostname+port of the identity server which should be used for third party identifier lookups. + String idServer; + + /// The kind of address being passed in the address field, for example `email`. + String medium; +} + +@_NameSource('rule override generated') +enum CreateRoomPreset { privateChat, publicChat, trustedPrivateChat } + +@_NameSource('generated') +enum Visibility { private, public } + +/// A client device +@_NameSource('spec') +class Device { + Device({ + required this.deviceId, + this.displayName, + this.lastSeenIp, + this.lastSeenTs, + }); + + Device.fromJson(Map json) + : deviceId = json['device_id'] as String, + displayName = + ((v) => v != null ? v as String : null)(json['display_name']), + lastSeenIp = + ((v) => v != null ? v as String : null)(json['last_seen_ip']), + lastSeenTs = ((v) => v != null ? v as int : null)(json['last_seen_ts']); + Map toJson() { + final displayName = this.displayName; + final lastSeenIp = this.lastSeenIp; + final lastSeenTs = this.lastSeenTs; + return { + 'device_id': deviceId, + if (displayName != null) 'display_name': displayName, + if (lastSeenIp != null) 'last_seen_ip': lastSeenIp, + if (lastSeenTs != null) 'last_seen_ts': lastSeenTs, + }; + } + + /// Identifier of this device. + String deviceId; + + /// Display name set by the user for this device. Absent if no name has been + /// set. + String? displayName; + + /// The IP address where this device was last seen. (May be a few minutes out + /// of date, for efficiency reasons). + String? lastSeenIp; + + /// The timestamp (in milliseconds since the unix epoch) when this devices + /// was last seen. (May be a few minutes out of date, for efficiency + /// reasons). + int? lastSeenTs; +} + +@_NameSource('generated') +class GetRoomIdByAliasResponse { + GetRoomIdByAliasResponse({ + this.roomId, + this.servers, + }); + + GetRoomIdByAliasResponse.fromJson(Map json) + : roomId = ((v) => v != null ? v as String : null)(json['room_id']), + servers = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['servers']); + Map toJson() { + final roomId = this.roomId; + final servers = this.servers; + return { + if (roomId != null) 'room_id': roomId, + if (servers != null) 'servers': servers.map((v) => v).toList(), + }; + } + + /// The room ID for this room alias. + String? roomId; + + /// A list of servers that are aware of this room alias. + List? servers; +} + +/// 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. +@_NameSource('spec') +class ThirdPartySigned { + ThirdPartySigned({ + required this.mxid, + required this.sender, + required this.signatures, + required this.token, + }); + + ThirdPartySigned.fromJson(Map json) + : mxid = json['mxid'] as String, + sender = json['sender'] as String, + signatures = (json['signatures'] as Map).map((k, v) => + MapEntry( + k, + (v as Map) + .map((k, v) => MapEntry(k, v as String)))), + token = json['token'] as String; + Map toJson() => { + 'mxid': mxid, + 'sender': sender, + 'signatures': signatures + .map((k, v) => MapEntry(k, v.map((k, v) => MapEntry(k, v)))), + 'token': token, + }; + + /// The Matrix ID of the invitee. + String mxid; + + /// The Matrix ID of the user who issued the invite. + String sender; + + /// A signatures object containing a signature of the entire signed object. + Map> signatures; + + /// The state key of the m.third_party_invite event. + String token; +} + +@_NameSource('generated') +class GetKeysChangesResponse { + GetKeysChangesResponse({ + this.changed, + this.left, + }); + + GetKeysChangesResponse.fromJson(Map json) + : changed = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['changed']), + left = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['left']); + Map toJson() { + final changed = this.changed; + final left = this.left; + return { + if (changed != null) 'changed': changed.map((v) => v).toList(), + if (left != null) 'left': left.map((v) => v).toList(), + }; + } + + /// The Matrix User IDs of all users who updated their device + /// identity keys. + List? changed; + + /// The Matrix User IDs of all users who may have left all + /// the end-to-end encrypted rooms they previously shared + /// with the user. + List? left; +} + +@_NameSource('generated') +class ClaimKeysResponse { + ClaimKeysResponse({ + this.failures, + required this.oneTimeKeys, + }); + + ClaimKeysResponse.fromJson(Map json) + : failures = ((v) => v != null + ? (v as Map) + .map((k, v) => MapEntry(k, v as Map)) + : null)(json['failures']), + oneTimeKeys = (json['one_time_keys'] as Map).map( + (k, v) => MapEntry( + k, + (v as Map) + .map((k, v) => MapEntry(k, v as dynamic)))); + Map toJson() { + final failures = this.failures; + return { + if (failures != null) 'failures': failures.map((k, v) => MapEntry(k, v)), + 'one_time_keys': oneTimeKeys + .map((k, v) => MapEntry(k, v.map((k, v) => MapEntry(k, v)))), + }; + } + + /// If any remote homeservers could not be reached, they are + /// recorded here. The names of the properties are the names of + /// the unreachable servers. + /// + /// 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. + Map>? failures; + + /// One-time keys for the queried devices. A map from user ID, to a + /// map from devices to a map from `:` to the key object. + /// + /// See the [key algorithms](https://spec.matrix.org/unstable/client-server-api/#key-algorithms) section for information + /// on the Key Object format. + Map> oneTimeKeys; +} + +@_NameSource('generated') +class QueryKeysResponse { + QueryKeysResponse({ + this.deviceKeys, + this.failures, + this.masterKeys, + this.selfSigningKeys, + this.userSigningKeys, + }); + + QueryKeysResponse.fromJson(Map json) + : deviceKeys = ((v) => v != null + ? (v as Map).map((k, v) => MapEntry( + k, + (v as Map) + .map((k, v) => MapEntry(k, MatrixDeviceKeys.fromJson(v))))) + : null)(json['device_keys']), + failures = ((v) => v != null + ? (v as Map) + .map((k, v) => MapEntry(k, v as Map)) + : null)(json['failures']), + masterKeys = ((v) => v != null + ? (v as Map) + .map((k, v) => MapEntry(k, MatrixCrossSigningKey.fromJson(v))) + : null)(json['master_keys']), + selfSigningKeys = ((v) => v != null + ? (v as Map) + .map((k, v) => MapEntry(k, MatrixCrossSigningKey.fromJson(v))) + : null)(json['self_signing_keys']), + userSigningKeys = ((v) => v != null + ? (v as Map) + .map((k, v) => MapEntry(k, MatrixCrossSigningKey.fromJson(v))) + : null)(json['user_signing_keys']); + Map toJson() { + final deviceKeys = this.deviceKeys; + final failures = this.failures; + final masterKeys = this.masterKeys; + final selfSigningKeys = this.selfSigningKeys; + final userSigningKeys = this.userSigningKeys; + return { + if (deviceKeys != null) + 'device_keys': deviceKeys.map( + (k, v) => MapEntry(k, v.map((k, v) => MapEntry(k, v.toJson())))), + if (failures != null) 'failures': failures.map((k, v) => MapEntry(k, v)), + if (masterKeys != null) + 'master_keys': masterKeys.map((k, v) => MapEntry(k, v.toJson())), + if (selfSigningKeys != null) + 'self_signing_keys': + selfSigningKeys.map((k, v) => MapEntry(k, v.toJson())), + if (userSigningKeys != null) + 'user_signing_keys': + userSigningKeys.map((k, v) => MapEntry(k, v.toJson())), + }; + } + + /// 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. + Map>? deviceKeys; + + /// If any remote homeservers could not be reached, they are + /// recorded here. The names of the properties are the names of + /// the unreachable servers. + /// + /// 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. + Map>? failures; + + /// Information on the master cross-signing keys of the queried users. + /// A map from user ID, to master key information. For each key, the + /// information returned will be the same as uploaded via + /// `/keys/device_signing/upload`, along with the signatures + /// uploaded via `/keys/signatures/upload` that the requesting user + /// is allowed to see. + Map? masterKeys; + + /// Information on the self-signing keys of the queried users. A map + /// from user ID, to self-signing key information. For each key, the + /// information returned will be the same as uploaded via + /// `/keys/device_signing/upload`. + Map? selfSigningKeys; + + /// Information on the user-signing key of the user making the + /// request, if they queried their own device information. A map + /// from user ID, to user-signing key information. The + /// information returned will be the same as uploaded via + /// `/keys/device_signing/upload`. + Map? userSigningKeys; +} + +@_NameSource('spec') +class LoginFlow { + LoginFlow({ + this.type, + }); + + LoginFlow.fromJson(Map json) + : type = ((v) => v != null ? v as String : null)(json['type']); + Map toJson() { + final type = this.type; + return { + if (type != null) 'type': type, + }; + } + + /// The login type. This is supplied as the `type` when + /// logging in. + String? type; +} + +@_NameSource('rule override generated') +enum LoginType { mLoginPassword, mLoginToken } + +@_NameSource('generated') +class LoginResponse { + LoginResponse({ + this.accessToken, + this.deviceId, + this.homeServer, + this.userId, + this.wellKnown, + }); + + LoginResponse.fromJson(Map json) + : accessToken = + ((v) => v != null ? v as String : null)(json['access_token']), + deviceId = ((v) => v != null ? v as String : null)(json['device_id']), + homeServer = + ((v) => v != null ? v as String : null)(json['home_server']), + userId = ((v) => v != null ? v as String : null)(json['user_id']), + wellKnown = ((v) => v != null + ? DiscoveryInformation.fromJson(v) + : null)(json['well_known']); + Map toJson() { + final accessToken = this.accessToken; + final deviceId = this.deviceId; + final homeServer = this.homeServer; + final userId = this.userId; + final wellKnown = this.wellKnown; + return { + if (accessToken != null) 'access_token': accessToken, + if (deviceId != null) 'device_id': deviceId, + if (homeServer != null) 'home_server': homeServer, + if (userId != null) 'user_id': userId, + if (wellKnown != null) 'well_known': wellKnown.toJson(), + }; + } + + /// An access token for the account. + /// This access token can then be used to authorize other requests. + String? accessToken; + + /// ID of the logged-in device. Will be the same as the + /// corresponding parameter in the request, if one was specified. + String? deviceId; + + /// The server_name of the homeserver on which the account has + /// been registered. + /// + /// **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. + String? homeServer; + + /// The fully-qualified Matrix ID for the account. + String? userId; + + /// 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. + DiscoveryInformation? wellKnown; +} + +@_NameSource('spec') +class Notification { + Notification({ + required this.actions, + required this.event, + this.profileTag, + required this.read, + required this.roomId, + required this.ts, + }); + + Notification.fromJson(Map json) + : actions = (json['actions'] as List).map((v) => v as dynamic).toList(), + event = MatrixEvent.fromJson(json['event']), + profileTag = + ((v) => v != null ? v as String : null)(json['profile_tag']), + read = json['read'] as bool, + roomId = json['room_id'] as String, + ts = json['ts'] as int; + Map toJson() { + final profileTag = this.profileTag; + return { + 'actions': actions.map((v) => v).toList(), + 'event': event.toJson(), + if (profileTag != null) 'profile_tag': profileTag, + 'read': read, + 'room_id': roomId, + 'ts': ts, + }; + } + + /// The action(s) to perform when the conditions for this rule are met. + /// See [Push Rules: API](https://spec.matrix.org/unstable/client-server-api/#push-rules-api). + List actions; + + /// The Event object for the event that triggered the notification. + MatrixEvent event; + + /// The profile tag of the rule that matched this event. + String? profileTag; + + /// Indicates whether the user has sent a read receipt indicating + /// that they have read this message. + bool read; + + /// The ID of the room in which the event was posted. + String roomId; + + /// The unix timestamp at which the event notification was sent, + /// in milliseconds. + int ts; +} + +@_NameSource('generated') +class GetNotificationsResponse { + GetNotificationsResponse({ + this.nextToken, + required this.notifications, + }); + + GetNotificationsResponse.fromJson(Map json) + : nextToken = ((v) => v != null ? v as String : null)(json['next_token']), + notifications = (json['notifications'] as List) + .map((v) => Notification.fromJson(v)) + .toList(); + Map toJson() { + final nextToken = this.nextToken; + return { + if (nextToken != null) 'next_token': nextToken, + 'notifications': notifications.map((v) => v.toJson()).toList(), + }; + } + + /// 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. + String? nextToken; + + /// The list of events that triggered notifications. + List notifications; +} + +@_NameSource('rule override generated') +enum PresenceType { offline, online, unavailable } + +@_NameSource('generated') +class GetPresenceResponse { + GetPresenceResponse({ + this.currentlyActive, + this.lastActiveAgo, + required this.presence, + this.statusMsg, + }); + + GetPresenceResponse.fromJson(Map json) + : currentlyActive = + ((v) => v != null ? v as bool : null)(json['currently_active']), + lastActiveAgo = + ((v) => v != null ? v as int : null)(json['last_active_ago']), + presence = { + 'online': PresenceType.online, + 'offline': PresenceType.offline, + 'unavailable': PresenceType.unavailable + }[json['presence']]!, + statusMsg = ((v) => v != null ? v as String : null)(json['status_msg']); + Map toJson() { + final currentlyActive = this.currentlyActive; + final lastActiveAgo = this.lastActiveAgo; + final statusMsg = this.statusMsg; + return { + if (currentlyActive != null) 'currently_active': currentlyActive, + if (lastActiveAgo != null) 'last_active_ago': lastActiveAgo, + 'presence': { + PresenceType.online: 'online', + PresenceType.offline: 'offline', + PresenceType.unavailable: 'unavailable' + }[presence]!, + if (statusMsg != null) 'status_msg': statusMsg, + }; + } + + /// Whether the user is currently active + bool? currentlyActive; + + /// The length of time in milliseconds since an action was performed + /// by this user. + int? lastActiveAgo; + + /// This user's presence. + PresenceType presence; + + /// The state message for this user if one was set. + String? statusMsg; +} + +@_NameSource('rule override generated') +class ProfileInformation { + ProfileInformation({ + this.avatarUrl, + this.displayname, + }); + + ProfileInformation.fromJson(Map json) + : avatarUrl = + ((v) => v != null ? Uri.parse(v) : null)(json['avatar_url']), + displayname = + ((v) => v != null ? v as String : null)(json['displayname']); + Map toJson() { + final avatarUrl = this.avatarUrl; + final displayname = this.displayname; + return { + if (avatarUrl != null) 'avatar_url': avatarUrl.toString(), + if (displayname != null) 'displayname': displayname, + }; + } + + /// The user's avatar URL if they have set one, otherwise not present. + Uri? avatarUrl; + + /// The user's display name if they have set one, otherwise not present. + String? displayname; +} + +@_NameSource('spec') +class PublicRoomsChunk { + PublicRoomsChunk({ + this.aliases, + this.avatarUrl, + this.canonicalAlias, + required this.guestCanJoin, + this.joinRule, + this.name, + required this.numJoinedMembers, + required this.roomId, + this.topic, + required this.worldReadable, + }); + + PublicRoomsChunk.fromJson(Map json) + : aliases = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['aliases']), + avatarUrl = + ((v) => v != null ? Uri.parse(v) : null)(json['avatar_url']), + canonicalAlias = + ((v) => v != null ? v as String : null)(json['canonical_alias']), + guestCanJoin = json['guest_can_join'] as bool, + joinRule = ((v) => v != null ? v as String : null)(json['join_rule']), + name = ((v) => v != null ? v as String : null)(json['name']), + numJoinedMembers = json['num_joined_members'] as int, + roomId = json['room_id'] as String, + topic = ((v) => v != null ? v as String : null)(json['topic']), + worldReadable = json['world_readable'] as bool; + Map toJson() { + final aliases = this.aliases; + final avatarUrl = this.avatarUrl; + final canonicalAlias = this.canonicalAlias; + final joinRule = this.joinRule; + final name = this.name; + final topic = this.topic; + return { + if (aliases != null) 'aliases': aliases.map((v) => v).toList(), + if (avatarUrl != null) 'avatar_url': avatarUrl.toString(), + if (canonicalAlias != null) 'canonical_alias': canonicalAlias, + 'guest_can_join': guestCanJoin, + if (joinRule != null) 'join_rule': joinRule, + if (name != null) 'name': name, + 'num_joined_members': numJoinedMembers, + 'room_id': roomId, + if (topic != null) 'topic': topic, + 'world_readable': worldReadable, + }; + } + + /// Aliases of the room. May be empty. + List? aliases; + + /// The URL for the room's avatar, if one is set. + Uri? avatarUrl; + + /// The canonical alias of the room, if any. + String? canonicalAlias; + + /// 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 room's join rule. When not present, the room is assumed to + /// be `public`. Note that rooms with `invite` join rules are not + /// expected here, but rooms with `knock` rules are given their + /// near-public nature. + String? joinRule; + + /// The name of the room, if any. + String? name; + + /// The number of members joined to the room. + int numJoinedMembers; + + /// The ID of the room. + String roomId; + + /// The topic of the room, if any. + String? topic; + + /// Whether the room may be viewed by guest users without joining. + bool worldReadable; +} + +/// A list of the rooms on the server. +@_NameSource('generated') +class GetPublicRoomsResponse { + GetPublicRoomsResponse({ + required this.chunk, + this.nextBatch, + this.prevBatch, + this.totalRoomCountEstimate, + }); + + GetPublicRoomsResponse.fromJson(Map json) + : chunk = (json['chunk'] as List) + .map((v) => PublicRoomsChunk.fromJson(v)) + .toList(), + nextBatch = ((v) => v != null ? v as String : null)(json['next_batch']), + prevBatch = ((v) => v != null ? v as String : null)(json['prev_batch']), + totalRoomCountEstimate = ((v) => + v != null ? v as int : null)(json['total_room_count_estimate']); + Map toJson() { + final nextBatch = this.nextBatch; + final prevBatch = this.prevBatch; + final totalRoomCountEstimate = this.totalRoomCountEstimate; + return { + 'chunk': chunk.map((v) => v.toJson()).toList(), + if (nextBatch != null) 'next_batch': nextBatch, + if (prevBatch != null) 'prev_batch': prevBatch, + if (totalRoomCountEstimate != null) + 'total_room_count_estimate': totalRoomCountEstimate, + }; + } + + /// A paginated chunk of public rooms. + List chunk; + + /// 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. + String? nextBatch; + + /// 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. + String? prevBatch; + + /// An estimate on the total number of public rooms, if the + /// server has an estimate. + int? totalRoomCountEstimate; +} + +@_NameSource('rule override spec') +class PublicRoomQueryFilter { + PublicRoomQueryFilter({ + this.genericSearchTerm, + }); + + PublicRoomQueryFilter.fromJson(Map json) + : genericSearchTerm = ((v) => + v != null ? v as String : null)(json['generic_search_term']); + Map toJson() { + final genericSearchTerm = this.genericSearchTerm; + return { + if (genericSearchTerm != null) 'generic_search_term': genericSearchTerm, + }; + } + + /// A string to search for in the room metadata, e.g. name, + /// topic, canonical alias etc. (Optional). + String? genericSearchTerm; +} + +/// A list of the rooms on the server. +@_NameSource('generated') +class QueryPublicRoomsResponse { + QueryPublicRoomsResponse({ + required this.chunk, + this.nextBatch, + this.prevBatch, + this.totalRoomCountEstimate, + }); + + QueryPublicRoomsResponse.fromJson(Map json) + : chunk = (json['chunk'] as List) + .map((v) => PublicRoomsChunk.fromJson(v)) + .toList(), + nextBatch = ((v) => v != null ? v as String : null)(json['next_batch']), + prevBatch = ((v) => v != null ? v as String : null)(json['prev_batch']), + totalRoomCountEstimate = ((v) => + v != null ? v as int : null)(json['total_room_count_estimate']); + Map toJson() { + final nextBatch = this.nextBatch; + final prevBatch = this.prevBatch; + final totalRoomCountEstimate = this.totalRoomCountEstimate; + return { + 'chunk': chunk.map((v) => v.toJson()).toList(), + if (nextBatch != null) 'next_batch': nextBatch, + if (prevBatch != null) 'prev_batch': prevBatch, + if (totalRoomCountEstimate != null) + 'total_room_count_estimate': totalRoomCountEstimate, + }; + } + + /// A paginated chunk of public rooms. + List chunk; + + /// 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. + String? nextBatch; + + /// 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. + String? prevBatch; + + /// An estimate on the total number of public rooms, if the + /// server has an estimate. + int? totalRoomCountEstimate; +} + +@_NameSource('spec') +class PusherData { + PusherData({ + this.format, + this.url, + }); + + PusherData.fromJson(Map json) + : format = ((v) => v != null ? v as String : null)(json['format']), + url = ((v) => v != null ? Uri.parse(v) : null)(json['url']); + Map toJson() { + final format = this.format; + final url = this.url; + return { + if (format != null) 'format': format, + if (url != null) 'url': url.toString(), + }; + } + + /// The format to use when sending notifications to the Push + /// Gateway. + String? format; + + /// Required if `kind` is `http`. The URL to use to send + /// notifications to. + Uri? url; +} + +@_NameSource('spec') +class Pusher { + Pusher({ + required this.appDisplayName, + required this.appId, + required this.data, + required this.deviceDisplayName, + required this.kind, + required this.lang, + this.profileTag, + required this.pushkey, + }); + + Pusher.fromJson(Map json) + : appDisplayName = json['app_display_name'] as String, + appId = json['app_id'] as String, + data = PusherData.fromJson(json['data']), + deviceDisplayName = json['device_display_name'] as String, + kind = json['kind'] as String, + lang = json['lang'] as String, + profileTag = + ((v) => v != null ? v as String : null)(json['profile_tag']), + pushkey = json['pushkey'] as String; + Map toJson() { + final profileTag = this.profileTag; + return { + 'app_display_name': appDisplayName, + 'app_id': appId, + 'data': data.toJson(), + 'device_display_name': deviceDisplayName, + 'kind': kind, + 'lang': lang, + if (profileTag != null) 'profile_tag': profileTag, + 'pushkey': pushkey, + }; + } + + /// A string that will allow the user to identify what application + /// owns this pusher. + String appDisplayName; + + /// This is a reverse-DNS style identifier for the application. + /// Max length, 64 chars. + String appId; + + /// A dictionary of information for the pusher implementation + /// itself. + PusherData data; + + /// A string that will allow the user to identify what device owns + /// this pusher. + String deviceDisplayName; + + /// The kind of pusher. `"http"` is a pusher that + /// sends HTTP pokes. + String kind; + + /// The preferred language for receiving notifications (e.g. 'en' + /// or 'en-US') + String lang; + + /// This string determines which set of device specific rules this + /// pusher executes. + String? profileTag; + + /// This is a unique identifier for this pusher. See `/set` for + /// more detail. + /// Max length, 512 bytes. + String pushkey; +} + +@_NameSource('spec') +class PushCondition { + PushCondition({ + this.is$, + this.key, + required this.kind, + this.pattern, + }); + + PushCondition.fromJson(Map json) + : is$ = ((v) => v != null ? v as String : null)(json['is']), + key = ((v) => v != null ? v as String : null)(json['key']), + kind = json['kind'] as String, + pattern = ((v) => v != null ? v as String : null)(json['pattern']); + Map toJson() { + final is$ = this.is$; + final key = this.key; + final pattern = this.pattern; + return { + if (is$ != null) 'is': is$, + if (key != null) 'key': key, + 'kind': kind, + if (pattern != null) 'pattern': pattern, + }; + } + + /// Required for `room_member_count` conditions. A decimal integer + /// optionally prefixed by one of, ==, <, >, >= or <=. A prefix of < matches + /// rooms where the member count is strictly less than the given number and + /// so forth. If no prefix is present, this parameter defaults to ==. + String? is$; + + /// 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`. + String? key; + + /// The kind of condition to apply. See [conditions](https://spec.matrix.org/unstable/client-server-api/#conditions) for + /// more information on the allowed kinds and how they work. + String kind; + + /// Required for `event_match` conditions. The glob-style pattern to + /// match against. Patterns with no special glob characters should be + /// treated as having asterisks prepended and appended when testing the + /// condition. + String? pattern; +} + +@_NameSource('spec') +class PushRule { + PushRule({ + required this.actions, + this.conditions, + required this.default$, + required this.enabled, + this.pattern, + required this.ruleId, + }); + + PushRule.fromJson(Map json) + : actions = (json['actions'] as List).map((v) => v as dynamic).toList(), + conditions = ((v) => v != null + ? (v as List).map((v) => PushCondition.fromJson(v)).toList() + : null)(json['conditions']), + default$ = json['default'] as bool, + enabled = json['enabled'] as bool, + pattern = ((v) => v != null ? v as String : null)(json['pattern']), + ruleId = json['rule_id'] as String; + Map toJson() { + final conditions = this.conditions; + final pattern = this.pattern; + return { + 'actions': actions.map((v) => v).toList(), + if (conditions != null) + 'conditions': conditions.map((v) => v.toJson()).toList(), + 'default': default$, + 'enabled': enabled, + if (pattern != null) 'pattern': pattern, + 'rule_id': ruleId, + }; + } + + /// The actions to perform when this rule is matched. + List actions; + + /// 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. + List? conditions; + + /// Whether this is a default rule, or has been set explicitly. + bool default$; + + /// Whether the push rule is enabled or not. + bool enabled; + + /// The glob-style pattern to match against. Only applicable to `content` + /// rules. + String? pattern; + + /// The ID of this rule. + String ruleId; +} + +@_NameSource('rule override generated') +class PushRuleSet { + PushRuleSet({ + this.content, + this.override, + this.room, + this.sender, + this.underride, + }); + + PushRuleSet.fromJson(Map json) + : content = ((v) => v != null + ? (v as List).map((v) => PushRule.fromJson(v)).toList() + : null)(json['content']), + override = ((v) => v != null + ? (v as List).map((v) => PushRule.fromJson(v)).toList() + : null)(json['override']), + room = ((v) => v != null + ? (v as List).map((v) => PushRule.fromJson(v)).toList() + : null)(json['room']), + sender = ((v) => v != null + ? (v as List).map((v) => PushRule.fromJson(v)).toList() + : null)(json['sender']), + underride = ((v) => v != null + ? (v as List).map((v) => PushRule.fromJson(v)).toList() + : null)(json['underride']); + Map toJson() { + final content = this.content; + final override = this.override; + final room = this.room; + final sender = this.sender; + final underride = this.underride; + return { + if (content != null) 'content': content.map((v) => v.toJson()).toList(), + if (override != null) + 'override': override.map((v) => v.toJson()).toList(), + if (room != null) 'room': room.map((v) => v.toJson()).toList(), + if (sender != null) 'sender': sender.map((v) => v.toJson()).toList(), + if (underride != null) + 'underride': underride.map((v) => v.toJson()).toList(), + }; + } + + List? content; + + List? override; + + List? room; + + List? sender; + + List? underride; +} + +@_NameSource('rule override generated') +enum PushRuleKind { content, override, room, sender, underride } + +@_NameSource('rule override generated') +enum AccountKind { guest, user } + +@_NameSource('generated') +class RegisterResponse { + RegisterResponse({ + this.accessToken, + this.deviceId, + this.homeServer, + required this.userId, + }); + + RegisterResponse.fromJson(Map json) + : accessToken = + ((v) => v != null ? v as String : null)(json['access_token']), + deviceId = ((v) => v != null ? v as String : null)(json['device_id']), + homeServer = + ((v) => v != null ? v as String : null)(json['home_server']), + userId = json['user_id'] as String; + Map toJson() { + final accessToken = this.accessToken; + final deviceId = this.deviceId; + final homeServer = this.homeServer; + return { + if (accessToken != null) 'access_token': accessToken, + if (deviceId != null) 'device_id': deviceId, + if (homeServer != null) 'home_server': homeServer, + 'user_id': userId, + }; + } + + /// 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. + String? accessToken; + + /// 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. + String? deviceId; + + /// The server_name of the homeserver on which the account has + /// been registered. + /// + /// **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. + String? homeServer; + + /// 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://spec.matrix.org/unstable/appendices/#user-identifiers). + String userId; +} + +/// The key data +@_NameSource('spec') +class KeyBackupData { + KeyBackupData({ + required this.firstMessageIndex, + required this.forwardedCount, + required this.isVerified, + required this.sessionData, + }); + + KeyBackupData.fromJson(Map json) + : firstMessageIndex = json['first_message_index'] as int, + forwardedCount = json['forwarded_count'] as int, + isVerified = json['is_verified'] as bool, + sessionData = json['session_data'] as Map; + Map toJson() => { + 'first_message_index': firstMessageIndex, + 'forwarded_count': forwardedCount, + 'is_verified': isVerified, + 'session_data': sessionData, + }; + + /// The index of the first message in the session that the key can decrypt. + int firstMessageIndex; + + /// The number of times this key has been forwarded via key-sharing between devices. + int forwardedCount; + + /// Whether the device backing up the key verified the device that the key + /// is from. + bool isVerified; + + /// Algorithm-dependent data. See the documentation for the backup + /// algorithms in [Server-side key backups](https://spec.matrix.org/unstable/client-server-api/#server-side-key-backups) for more information on the + /// expected format of the data. + Map sessionData; +} + +/// The backed up keys for a room. +@_NameSource('spec') +class RoomKeyBackup { + RoomKeyBackup({ + required this.sessions, + }); + + RoomKeyBackup.fromJson(Map json) + : sessions = (json['sessions'] as Map) + .map((k, v) => MapEntry(k, KeyBackupData.fromJson(v))); + Map toJson() => { + 'sessions': sessions.map((k, v) => MapEntry(k, v.toJson())), + }; + + /// A map of session IDs to key data. + Map sessions; +} + +@_NameSource('rule override generated') +class RoomKeys { + RoomKeys({ + required this.rooms, + }); + + RoomKeys.fromJson(Map json) + : rooms = (json['rooms'] as Map) + .map((k, v) => MapEntry(k, RoomKeyBackup.fromJson(v))); + Map toJson() => { + 'rooms': rooms.map((k, v) => MapEntry(k, v.toJson())), + }; + + /// A map of room IDs to room key backup data. + Map rooms; +} + +@_NameSource('generated') +class PostRoomKeysKeyResponse { + PostRoomKeysKeyResponse({ + required this.count, + required this.etag, + }); + + PostRoomKeysKeyResponse.fromJson(Map json) + : count = json['count'] as int, + etag = json['etag'] as String; + Map toJson() => { + 'count': count, + 'etag': etag, + }; + + /// The number of keys stored in the backup + int count; + + /// The new etag value representing stored keys in the backup. + /// See `GET /room_keys/version/{version}` for more details. + String etag; +} + +@_NameSource('generated') +class PostRoomKeysKeyRoomIdResponse { + PostRoomKeysKeyRoomIdResponse({ + required this.count, + required this.etag, + }); + + PostRoomKeysKeyRoomIdResponse.fromJson(Map json) + : count = json['count'] as int, + etag = json['etag'] as String; + Map toJson() => { + 'count': count, + 'etag': etag, + }; + + /// The number of keys stored in the backup + int count; + + /// The new etag value representing stored keys in the backup. + /// See `GET /room_keys/version/{version}` for more details. + String etag; +} + +@_NameSource('generated') +class PostRoomKeysKeyRoomIdSessionIdResponse { + PostRoomKeysKeyRoomIdSessionIdResponse({ + required this.count, + required this.etag, + }); + + PostRoomKeysKeyRoomIdSessionIdResponse.fromJson(Map json) + : count = json['count'] as int, + etag = json['etag'] as String; + Map toJson() => { + 'count': count, + 'etag': etag, + }; + + /// The number of keys stored in the backup + int count; + + /// The new etag value representing stored keys in the backup. + /// See `GET /room_keys/version/{version}` for more details. + String etag; +} + +@_NameSource('rule override generated') +enum BackupAlgorithm { mMegolmBackupV1Curve25519AesSha2 } + +@_NameSource('generated') +class GetRoomKeysVersionCurrentResponse { + GetRoomKeysVersionCurrentResponse({ + required this.algorithm, + required this.authData, + required this.count, + required this.etag, + required this.version, + }); + + GetRoomKeysVersionCurrentResponse.fromJson(Map json) + : algorithm = { + 'm.megolm_backup.v1.curve25519-aes-sha2': + BackupAlgorithm.mMegolmBackupV1Curve25519AesSha2 + }[json['algorithm']]!, + authData = json['auth_data'] as Map, + count = json['count'] as int, + etag = json['etag'] as String, + version = json['version'] as String; + Map toJson() => { + 'algorithm': { + BackupAlgorithm.mMegolmBackupV1Curve25519AesSha2: + 'm.megolm_backup.v1.curve25519-aes-sha2' + }[algorithm]!, + 'auth_data': authData, + 'count': count, + 'etag': etag, + 'version': version, + }; + + /// The algorithm used for storing backups. + BackupAlgorithm algorithm; + + /// Algorithm-dependent data. See the documentation for the backup + /// algorithms in [Server-side key backups](https://spec.matrix.org/unstable/client-server-api/#server-side-key-backups) for more information on the + /// expected format of the data. + Map authData; + + /// The number of keys stored in the backup. + int count; + + /// An opaque string representing stored keys in the backup. + /// Clients can compare it with the `etag` value they received + /// in the request of their last key storage request. If not + /// equal, another client has modified the backup. + String etag; + + /// The backup version. + String version; +} + +@_NameSource('generated') +class GetRoomKeysVersionResponse { + GetRoomKeysVersionResponse({ + required this.algorithm, + required this.authData, + required this.count, + required this.etag, + required this.version, + }); + + GetRoomKeysVersionResponse.fromJson(Map json) + : algorithm = { + 'm.megolm_backup.v1.curve25519-aes-sha2': + BackupAlgorithm.mMegolmBackupV1Curve25519AesSha2 + }[json['algorithm']]!, + authData = json['auth_data'] as Map, + count = json['count'] as int, + etag = json['etag'] as String, + version = json['version'] as String; + Map toJson() => { + 'algorithm': { + BackupAlgorithm.mMegolmBackupV1Curve25519AesSha2: + 'm.megolm_backup.v1.curve25519-aes-sha2' + }[algorithm]!, + 'auth_data': authData, + 'count': count, + 'etag': etag, + 'version': version, + }; + + /// The algorithm used for storing backups. + BackupAlgorithm algorithm; + + /// Algorithm-dependent data. See the documentation for the backup + /// algorithms in [Server-side key backups](https://spec.matrix.org/unstable/client-server-api/#server-side-key-backups) for more information on the + /// expected format of the data. + Map authData; + + /// The number of keys stored in the backup. + int count; + + /// An opaque string representing stored keys in the backup. + /// Clients can compare it with the `etag` value they received + /// in the request of their last key storage request. If not + /// equal, another client has modified the backup. + String etag; + + /// The backup version. + String version; +} + +/// The events and state surrounding the requested event. +@_NameSource('rule override generated') +class EventContext { + EventContext({ + this.end, + this.event, + this.eventsAfter, + this.eventsBefore, + this.start, + this.state, + }); + + EventContext.fromJson(Map json) + : end = ((v) => v != null ? v as String : null)(json['end']), + event = + ((v) => v != null ? MatrixEvent.fromJson(v) : null)(json['event']), + eventsAfter = ((v) => v != null + ? (v as List).map((v) => MatrixEvent.fromJson(v)).toList() + : null)(json['events_after']), + eventsBefore = ((v) => v != null + ? (v as List).map((v) => MatrixEvent.fromJson(v)).toList() + : null)(json['events_before']), + start = ((v) => v != null ? v as String : null)(json['start']), + state = ((v) => v != null + ? (v as List).map((v) => MatrixEvent.fromJson(v)).toList() + : null)(json['state']); + Map toJson() { + final end = this.end; + final event = this.event; + final eventsAfter = this.eventsAfter; + final eventsBefore = this.eventsBefore; + final start = this.start; + final state = this.state; + return { + if (end != null) 'end': end, + if (event != null) 'event': event.toJson(), + if (eventsAfter != null) + 'events_after': eventsAfter.map((v) => v.toJson()).toList(), + if (eventsBefore != null) + 'events_before': eventsBefore.map((v) => v.toJson()).toList(), + if (start != null) 'start': start, + if (state != null) 'state': state.map((v) => v.toJson()).toList(), + }; + } + + /// A token that can be used to paginate forwards with. + String? end; + + /// Details of the requested event. + MatrixEvent? event; + + /// A list of room events that happened just after the + /// requested event, in chronological order. + List? eventsAfter; + + /// A list of room events that happened just before the + /// requested event, in reverse-chronological order. + List? eventsBefore; + + /// A token that can be used to paginate backwards with. + String? start; + + /// The state of the room at the last event returned. + List? state; +} + +@_NameSource('spec') +class RoomMember { + RoomMember({ + this.avatarUrl, + this.displayName, + }); + + RoomMember.fromJson(Map json) + : avatarUrl = + ((v) => v != null ? Uri.parse(v) : null)(json['avatar_url']), + displayName = + ((v) => v != null ? v as String : null)(json['display_name']); + Map toJson() { + final avatarUrl = this.avatarUrl; + final displayName = this.displayName; + return { + if (avatarUrl != null) 'avatar_url': avatarUrl.toString(), + if (displayName != null) 'display_name': displayName, + }; + } + + /// The mxc avatar url of the user this object is representing. + Uri? avatarUrl; + + /// The display name of the user this object is representing. + String? displayName; +} + +@_NameSource('(generated, rule override generated)') +enum Membership { ban, invite, join, leave } + +@_NameSource('rule override generated') +enum Direction { b, f } + +/// A list of messages with a new token to request more. +@_NameSource('generated') +class GetRoomEventsResponse { + GetRoomEventsResponse({ + this.chunk, + this.end, + this.start, + this.state, + }); + + GetRoomEventsResponse.fromJson(Map json) + : chunk = ((v) => v != null + ? (v as List).map((v) => MatrixEvent.fromJson(v)).toList() + : null)(json['chunk']), + end = ((v) => v != null ? v as String : null)(json['end']), + start = ((v) => v != null ? v as String : null)(json['start']), + state = ((v) => v != null + ? (v as List).map((v) => MatrixEvent.fromJson(v)).toList() + : null)(json['state']); + Map toJson() { + final chunk = this.chunk; + final end = this.end; + final start = this.start; + final state = this.state; + return { + if (chunk != null) 'chunk': chunk.map((v) => v.toJson()).toList(), + if (end != null) 'end': end, + if (start != null) 'start': start, + if (state != null) 'state': state.map((v) => v.toJson()).toList(), + }; + } + + /// 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. + List? chunk; + + /// The token the pagination ends at. If `dir=b` this token should + /// be used again to request even earlier events. + String? end; + + /// The token the pagination starts from. If `dir=b` this will be + /// the token supplied in `from`. + String? start; + + /// 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. + List? state; +} + +@_NameSource('generated') +enum ReceiptType { mRead } + +@_NameSource('spec') +class IncludeEventContext { + IncludeEventContext({ + this.afterLimit, + this.beforeLimit, + this.includeProfile, + }); + + IncludeEventContext.fromJson(Map json) + : afterLimit = ((v) => v != null ? v as int : null)(json['after_limit']), + beforeLimit = + ((v) => v != null ? v as int : null)(json['before_limit']), + includeProfile = + ((v) => v != null ? v as bool : null)(json['include_profile']); + Map toJson() { + final afterLimit = this.afterLimit; + final beforeLimit = this.beforeLimit; + final includeProfile = this.includeProfile; + return { + if (afterLimit != null) 'after_limit': afterLimit, + if (beforeLimit != null) 'before_limit': beforeLimit, + if (includeProfile != null) 'include_profile': includeProfile, + }; + } + + /// How many events after the result are + /// returned. By default, this is `5`. + int? afterLimit; + + /// How many events before the result are + /// returned. By default, this is `5`. + int? beforeLimit; + + /// Requests that the server returns the + /// historic profile information for the users + /// that sent the events that were returned. + /// By default, this is `false`. + bool? includeProfile; +} + +@_NameSource('spec') +class EventFilter { + EventFilter({ + this.limit, + this.notSenders, + this.notTypes, + this.senders, + this.types, + }); + + EventFilter.fromJson(Map json) + : limit = ((v) => v != null ? v as int : null)(json['limit']), + notSenders = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['not_senders']), + notTypes = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['not_types']), + senders = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['senders']), + types = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['types']); + Map toJson() { + final limit = this.limit; + final notSenders = this.notSenders; + final notTypes = this.notTypes; + final senders = this.senders; + final types = this.types; + return { + if (limit != null) 'limit': limit, + if (notSenders != null) 'not_senders': notSenders.map((v) => v).toList(), + if (notTypes != null) 'not_types': notTypes.map((v) => v).toList(), + if (senders != null) 'senders': senders.map((v) => v).toList(), + if (types != null) 'types': types.map((v) => v).toList(), + }; + } + + /// The maximum number of events to return. + int? limit; + + /// A list of sender IDs to exclude. If this list is absent then no senders are excluded. A matching sender will be excluded even if it is listed in the `'senders'` filter. + List? notSenders; + + /// A list of event types to exclude. If this list is absent then no event types are excluded. A matching type will be excluded even if it is listed in the `'types'` filter. A '*' can be used as a wildcard to match any sequence of characters. + List? notTypes; + + /// A list of senders IDs to include. If this list is absent then all senders are included. + List? senders; + + /// A list of event types to include. If this list is absent then all event types are included. A `'*'` can be used as a wildcard to match any sequence of characters. + List? types; +} + +@_NameSource('spec') +class RoomEventFilter { + RoomEventFilter({ + this.containsUrl, + this.includeRedundantMembers, + this.lazyLoadMembers, + this.notRooms, + this.rooms, + }); + + RoomEventFilter.fromJson(Map json) + : containsUrl = + ((v) => v != null ? v as bool : null)(json['contains_url']), + includeRedundantMembers = ((v) => + v != null ? v as bool : null)(json['include_redundant_members']), + lazyLoadMembers = + ((v) => v != null ? v as bool : null)(json['lazy_load_members']), + notRooms = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['not_rooms']), + rooms = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['rooms']); + Map toJson() { + final containsUrl = this.containsUrl; + final includeRedundantMembers = this.includeRedundantMembers; + final lazyLoadMembers = this.lazyLoadMembers; + final notRooms = this.notRooms; + final rooms = this.rooms; + return { + if (containsUrl != null) 'contains_url': containsUrl, + if (includeRedundantMembers != null) + 'include_redundant_members': includeRedundantMembers, + if (lazyLoadMembers != null) 'lazy_load_members': lazyLoadMembers, + if (notRooms != null) 'not_rooms': notRooms.map((v) => v).toList(), + if (rooms != null) 'rooms': rooms.map((v) => v).toList(), + }; + } + + /// If `true`, includes only events with a `url` key in their content. If `false`, excludes those events. If omitted, `url` key is not considered for filtering. + bool? containsUrl; + + /// 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](https://spec.matrix.org/unstable/client-server-api/#lazy-loading-room-members) + /// for more information. Defaults to `false`. + bool? includeRedundantMembers; + + /// If `true`, enables lazy-loading of membership events. See + /// [Lazy-loading room members](https://spec.matrix.org/unstable/client-server-api/#lazy-loading-room-members) + /// for more information. Defaults to `false`. + bool? lazyLoadMembers; + + /// 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. + List? notRooms; + + /// A list of room IDs to include. If this list is absent then all rooms are included. + List? rooms; +} + +@_NameSource('rule override generated') +class SearchFilter implements EventFilter, RoomEventFilter { + SearchFilter({ + this.limit, + this.notSenders, + this.notTypes, + this.senders, + this.types, + this.containsUrl, + this.includeRedundantMembers, + this.lazyLoadMembers, + this.notRooms, + this.rooms, + }); + + SearchFilter.fromJson(Map json) + : limit = ((v) => v != null ? v as int : null)(json['limit']), + notSenders = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['not_senders']), + notTypes = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['not_types']), + senders = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['senders']), + types = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['types']), + containsUrl = + ((v) => v != null ? v as bool : null)(json['contains_url']), + includeRedundantMembers = ((v) => + v != null ? v as bool : null)(json['include_redundant_members']), + lazyLoadMembers = + ((v) => v != null ? v as bool : null)(json['lazy_load_members']), + notRooms = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['not_rooms']), + rooms = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['rooms']); + Map toJson() { + final limit = this.limit; + final notSenders = this.notSenders; + final notTypes = this.notTypes; + final senders = this.senders; + final types = this.types; + final containsUrl = this.containsUrl; + final includeRedundantMembers = this.includeRedundantMembers; + final lazyLoadMembers = this.lazyLoadMembers; + final notRooms = this.notRooms; + final rooms = this.rooms; + return { + if (limit != null) 'limit': limit, + if (notSenders != null) 'not_senders': notSenders.map((v) => v).toList(), + if (notTypes != null) 'not_types': notTypes.map((v) => v).toList(), + if (senders != null) 'senders': senders.map((v) => v).toList(), + if (types != null) 'types': types.map((v) => v).toList(), + if (containsUrl != null) 'contains_url': containsUrl, + if (includeRedundantMembers != null) + 'include_redundant_members': includeRedundantMembers, + if (lazyLoadMembers != null) 'lazy_load_members': lazyLoadMembers, + if (notRooms != null) 'not_rooms': notRooms.map((v) => v).toList(), + if (rooms != null) 'rooms': rooms.map((v) => v).toList(), + }; + } + + /// The maximum number of events to return. + int? limit; + + /// A list of sender IDs to exclude. If this list is absent then no senders are excluded. A matching sender will be excluded even if it is listed in the `'senders'` filter. + List? notSenders; + + /// A list of event types to exclude. If this list is absent then no event types are excluded. A matching type will be excluded even if it is listed in the `'types'` filter. A '*' can be used as a wildcard to match any sequence of characters. + List? notTypes; + + /// A list of senders IDs to include. If this list is absent then all senders are included. + List? senders; + + /// A list of event types to include. If this list is absent then all event types are included. A `'*'` can be used as a wildcard to match any sequence of characters. + List? types; + + /// If `true`, includes only events with a `url` key in their content. If `false`, excludes those events. If omitted, `url` key is not considered for filtering. + bool? containsUrl; + + /// 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](https://spec.matrix.org/unstable/client-server-api/#lazy-loading-room-members) + /// for more information. Defaults to `false`. + bool? includeRedundantMembers; + + /// If `true`, enables lazy-loading of membership events. See + /// [Lazy-loading room members](https://spec.matrix.org/unstable/client-server-api/#lazy-loading-room-members) + /// for more information. Defaults to `false`. + bool? lazyLoadMembers; + + /// 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. + List? notRooms; + + /// A list of room IDs to include. If this list is absent then all rooms are included. + List? rooms; +} + +@_NameSource('rule override generated') +enum GroupKey { roomId, sender } + +/// Configuration for group. +@_NameSource('spec') +class Group { + Group({ + this.key, + }); + + Group.fromJson(Map json) + : key = ((v) => v != null + ? {'room_id': GroupKey.roomId, 'sender': GroupKey.sender}[v]! + : null)(json['key']); + Map toJson() { + final key = this.key; + return { + if (key != null) + 'key': {GroupKey.roomId: 'room_id', GroupKey.sender: 'sender'}[key]!, + }; + } + + /// Key that defines the group. + GroupKey? key; +} + +@_NameSource('spec') +class Groupings { + Groupings({ + this.groupBy, + }); + + Groupings.fromJson(Map json) + : groupBy = ((v) => v != null + ? (v as List).map((v) => Group.fromJson(v)).toList() + : null)(json['group_by']); + Map toJson() { + final groupBy = this.groupBy; + return { + if (groupBy != null) 'group_by': groupBy.map((v) => v.toJson()).toList(), + }; + } + + /// List of groups to request. + List? groupBy; +} + +@_NameSource('rule override generated') +enum KeyKind { contentBody, contentName, contentTopic } + +@_NameSource('rule override generated') +enum SearchOrder { rank, recent } + +@_NameSource('spec') +class RoomEventsCriteria { + RoomEventsCriteria({ + this.eventContext, + this.filter, + this.groupings, + this.includeState, + this.keys, + this.orderBy, + required this.searchTerm, + }); + + RoomEventsCriteria.fromJson(Map json) + : eventContext = ((v) => v != null + ? IncludeEventContext.fromJson(v) + : null)(json['event_context']), + filter = ((v) => + v != null ? SearchFilter.fromJson(v) : null)(json['filter']), + groupings = ((v) => + v != null ? Groupings.fromJson(v) : null)(json['groupings']), + includeState = + ((v) => v != null ? v as bool : null)(json['include_state']), + keys = ((v) => v != null + ? (v as List) + .map((v) => { + 'content.body': KeyKind.contentBody, + 'content.name': KeyKind.contentName, + 'content.topic': KeyKind.contentTopic + }[v]!) + .toList() + : null)(json['keys']), + orderBy = ((v) => v != null + ? {'recent': SearchOrder.recent, 'rank': SearchOrder.rank}[v]! + : null)(json['order_by']), + searchTerm = json['search_term'] as String; + Map toJson() { + final eventContext = this.eventContext; + final filter = this.filter; + final groupings = this.groupings; + final includeState = this.includeState; + final keys = this.keys; + final orderBy = this.orderBy; + return { + if (eventContext != null) 'event_context': eventContext.toJson(), + if (filter != null) 'filter': filter.toJson(), + if (groupings != null) 'groupings': groupings.toJson(), + if (includeState != null) 'include_state': includeState, + if (keys != null) + 'keys': keys + .map((v) => { + KeyKind.contentBody: 'content.body', + KeyKind.contentName: 'content.name', + KeyKind.contentTopic: 'content.topic' + }[v]!) + .toList(), + if (orderBy != null) + 'order_by': { + SearchOrder.recent: 'recent', + SearchOrder.rank: 'rank' + }[orderBy]!, + 'search_term': searchTerm, + }; + } + + /// Configures whether any context for the events + /// returned are included in the response. + IncludeEventContext? eventContext; + + /// This takes a [filter](https://spec.matrix.org/unstable/client-server-api/#filtering). + SearchFilter? filter; + + /// Requests that the server partitions the result set + /// based on the provided list of keys. + Groupings? groupings; + + /// Requests the server return the current state for + /// each room returned. + bool? includeState; + + /// The keys to search. Defaults to all. + List? keys; + + /// The order in which to search for results. + /// By default, this is `"rank"`. + SearchOrder? orderBy; + + /// The string to search events for + String searchTerm; +} + +@_NameSource('spec') +class Categories { + Categories({ + this.roomEvents, + }); + + Categories.fromJson(Map json) + : roomEvents = ((v) => v != null ? RoomEventsCriteria.fromJson(v) : null)( + json['room_events']); + Map toJson() { + final roomEvents = this.roomEvents; + return { + if (roomEvents != null) 'room_events': roomEvents.toJson(), + }; + } + + /// Mapping of category name to search criteria. + RoomEventsCriteria? roomEvents; +} + +/// The results for a particular group value. +@_NameSource('spec') +class GroupValue { + GroupValue({ + this.nextBatch, + this.order, + this.results, + }); + + GroupValue.fromJson(Map json) + : nextBatch = ((v) => v != null ? v as String : null)(json['next_batch']), + order = ((v) => v != null ? v as int : null)(json['order']), + results = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['results']); + Map toJson() { + final nextBatch = this.nextBatch; + final order = this.order; + final results = this.results; + return { + if (nextBatch != null) 'next_batch': nextBatch, + if (order != null) 'order': order, + if (results != null) 'results': results.map((v) => v).toList(), + }; + } + + /// Token that can be used to get the next batch + /// of results in the group, by passing as the + /// `next_batch` parameter to the next call. If + /// this field is absent, there are no more + /// results in this group. + String? nextBatch; + + /// Key that can be used to order different + /// groups. + int? order; + + /// Which results are in this group. + List? results; +} + +@_NameSource('spec') +class UserProfile { + UserProfile({ + this.avatarUrl, + this.displayname, + }); + + UserProfile.fromJson(Map json) + : avatarUrl = + ((v) => v != null ? Uri.parse(v) : null)(json['avatar_url']), + displayname = + ((v) => v != null ? v as String : null)(json['displayname']); + Map toJson() { + final avatarUrl = this.avatarUrl; + final displayname = this.displayname; + return { + if (avatarUrl != null) 'avatar_url': avatarUrl.toString(), + if (displayname != null) 'displayname': displayname, + }; + } + + Uri? avatarUrl; + + String? displayname; +} + +@_NameSource('rule override spec') +class SearchResultsEventContext { + SearchResultsEventContext({ + this.end, + this.eventsAfter, + this.eventsBefore, + this.profileInfo, + this.start, + }); + + SearchResultsEventContext.fromJson(Map json) + : end = ((v) => v != null ? v as String : null)(json['end']), + eventsAfter = ((v) => v != null + ? (v as List).map((v) => MatrixEvent.fromJson(v)).toList() + : null)(json['events_after']), + eventsBefore = ((v) => v != null + ? (v as List).map((v) => MatrixEvent.fromJson(v)).toList() + : null)(json['events_before']), + profileInfo = ((v) => v != null + ? (v as Map) + .map((k, v) => MapEntry(k, UserProfile.fromJson(v))) + : null)(json['profile_info']), + start = ((v) => v != null ? v as String : null)(json['start']); + Map toJson() { + final end = this.end; + final eventsAfter = this.eventsAfter; + final eventsBefore = this.eventsBefore; + final profileInfo = this.profileInfo; + final start = this.start; + return { + if (end != null) 'end': end, + if (eventsAfter != null) + 'events_after': eventsAfter.map((v) => v.toJson()).toList(), + if (eventsBefore != null) + 'events_before': eventsBefore.map((v) => v.toJson()).toList(), + if (profileInfo != null) + 'profile_info': profileInfo.map((k, v) => MapEntry(k, v.toJson())), + if (start != null) 'start': start, + }; + } + + /// Pagination token for the end of the chunk + String? end; + + /// Events just after the result. + List? eventsAfter; + + /// Events just before the result. + List? eventsBefore; + + /// The historic profile information of the + /// users that sent the events returned. + /// + /// The `string` key is the user ID for which + /// the profile belongs to. + Map? profileInfo; + + /// Pagination token for the start of the chunk + String? start; +} + +/// The result object. +@_NameSource('spec') +class Result { + Result({ + this.context, + this.rank, + this.result, + }); + + Result.fromJson(Map json) + : context = ((v) => v != null + ? SearchResultsEventContext.fromJson(v) + : null)(json['context']), + rank = ((v) => v != null ? (v as num).toDouble() : null)(json['rank']), + result = + ((v) => v != null ? MatrixEvent.fromJson(v) : null)(json['result']); + Map toJson() { + final context = this.context; + final rank = this.rank; + final result = this.result; + return { + if (context != null) 'context': context.toJson(), + if (rank != null) 'rank': rank, + if (result != null) 'result': result.toJson(), + }; + } + + /// Context for result, if requested. + SearchResultsEventContext? context; + + /// A number that describes how closely this result matches the search. Higher is closer. + double? rank; + + /// The event that matched. + MatrixEvent? result; +} + +@_NameSource('spec') +class ResultRoomEvents { + ResultRoomEvents({ + this.count, + this.groups, + this.highlights, + this.nextBatch, + this.results, + this.state, + }); + + ResultRoomEvents.fromJson(Map json) + : count = ((v) => v != null ? v as int : null)(json['count']), + groups = ((v) => v != null + ? (v as Map).map((k, v) => MapEntry( + k, + (v as Map) + .map((k, v) => MapEntry(k, GroupValue.fromJson(v))))) + : null)(json['groups']), + highlights = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['highlights']), + nextBatch = ((v) => v != null ? v as String : null)(json['next_batch']), + results = ((v) => v != null + ? (v as List).map((v) => Result.fromJson(v)).toList() + : null)(json['results']), + state = ((v) => v != null + ? (v as Map).map((k, v) => MapEntry( + k, (v as List).map((v) => MatrixEvent.fromJson(v)).toList())) + : null)(json['state']); + Map toJson() { + final count = this.count; + final groups = this.groups; + final highlights = this.highlights; + final nextBatch = this.nextBatch; + final results = this.results; + final state = this.state; + return { + if (count != null) 'count': count, + if (groups != null) + 'groups': groups.map( + (k, v) => MapEntry(k, v.map((k, v) => MapEntry(k, v.toJson())))), + if (highlights != null) 'highlights': highlights.map((v) => v).toList(), + if (nextBatch != null) 'next_batch': nextBatch, + if (results != null) 'results': results.map((v) => v.toJson()).toList(), + if (state != null) + 'state': + state.map((k, v) => MapEntry(k, v.map((v) => v.toJson()).toList())), + }; + } + + /// An approximate count of the total number of results found. + int? count; + + /// Any groups that were requested. + /// + /// The outer `string` key is the group key requested (eg: `room_id` + /// or `sender`). The inner `string` key is the grouped value (eg: + /// a room's ID or a user's ID). + Map>? groups; + + /// List of words which should be highlighted, useful for stemming which may change the query terms. + List? highlights; + + /// Token that can be used to get the next batch of + /// results, by passing as the `next_batch` parameter to + /// the next call. If this field is absent, there are no + /// more results. + String? nextBatch; + + /// List of results in the requested order. + List? results; + + /// The current state for every room in the results. + /// This is included if the request had the + /// `include_state` key set with a value of `true`. + /// + /// The `string` key is the room ID for which the `State + /// Event` array belongs to. + Map>? state; +} + +@_NameSource('spec') +class ResultCategories { + ResultCategories({ + this.roomEvents, + }); + + ResultCategories.fromJson(Map json) + : roomEvents = ((v) => v != null ? ResultRoomEvents.fromJson(v) : null)( + json['room_events']); + Map toJson() { + final roomEvents = this.roomEvents; + return { + if (roomEvents != null) 'room_events': roomEvents.toJson(), + }; + } + + /// Mapping of category name to search criteria. + ResultRoomEvents? roomEvents; +} + +@_NameSource('rule override spec') +class SearchResults { + SearchResults({ + required this.searchCategories, + }); + + SearchResults.fromJson(Map json) + : searchCategories = ResultCategories.fromJson(json['search_categories']); + Map toJson() => { + 'search_categories': searchCategories.toJson(), + }; + + /// Describes which categories to search in and their criteria. + ResultCategories searchCategories; +} + +@_NameSource('generated') +enum EventFormat { client, federation } + +@_NameSource('rule override generated') +class StateFilter implements EventFilter, RoomEventFilter { + StateFilter({ + this.limit, + this.notSenders, + this.notTypes, + this.senders, + this.types, + this.containsUrl, + this.includeRedundantMembers, + this.lazyLoadMembers, + this.notRooms, + this.rooms, + }); + + StateFilter.fromJson(Map json) + : limit = ((v) => v != null ? v as int : null)(json['limit']), + notSenders = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['not_senders']), + notTypes = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['not_types']), + senders = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['senders']), + types = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['types']), + containsUrl = + ((v) => v != null ? v as bool : null)(json['contains_url']), + includeRedundantMembers = ((v) => + v != null ? v as bool : null)(json['include_redundant_members']), + lazyLoadMembers = + ((v) => v != null ? v as bool : null)(json['lazy_load_members']), + notRooms = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['not_rooms']), + rooms = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['rooms']); + Map toJson() { + final limit = this.limit; + final notSenders = this.notSenders; + final notTypes = this.notTypes; + final senders = this.senders; + final types = this.types; + final containsUrl = this.containsUrl; + final includeRedundantMembers = this.includeRedundantMembers; + final lazyLoadMembers = this.lazyLoadMembers; + final notRooms = this.notRooms; + final rooms = this.rooms; + return { + if (limit != null) 'limit': limit, + if (notSenders != null) 'not_senders': notSenders.map((v) => v).toList(), + if (notTypes != null) 'not_types': notTypes.map((v) => v).toList(), + if (senders != null) 'senders': senders.map((v) => v).toList(), + if (types != null) 'types': types.map((v) => v).toList(), + if (containsUrl != null) 'contains_url': containsUrl, + if (includeRedundantMembers != null) + 'include_redundant_members': includeRedundantMembers, + if (lazyLoadMembers != null) 'lazy_load_members': lazyLoadMembers, + if (notRooms != null) 'not_rooms': notRooms.map((v) => v).toList(), + if (rooms != null) 'rooms': rooms.map((v) => v).toList(), + }; + } + + /// The maximum number of events to return. + int? limit; + + /// A list of sender IDs to exclude. If this list is absent then no senders are excluded. A matching sender will be excluded even if it is listed in the `'senders'` filter. + List? notSenders; + + /// A list of event types to exclude. If this list is absent then no event types are excluded. A matching type will be excluded even if it is listed in the `'types'` filter. A '*' can be used as a wildcard to match any sequence of characters. + List? notTypes; + + /// A list of senders IDs to include. If this list is absent then all senders are included. + List? senders; + + /// A list of event types to include. If this list is absent then all event types are included. A `'*'` can be used as a wildcard to match any sequence of characters. + List? types; + + /// If `true`, includes only events with a `url` key in their content. If `false`, excludes those events. If omitted, `url` key is not considered for filtering. + bool? containsUrl; + + /// 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](https://spec.matrix.org/unstable/client-server-api/#lazy-loading-room-members) + /// for more information. Defaults to `false`. + bool? includeRedundantMembers; + + /// If `true`, enables lazy-loading of membership events. See + /// [Lazy-loading room members](https://spec.matrix.org/unstable/client-server-api/#lazy-loading-room-members) + /// for more information. Defaults to `false`. + bool? lazyLoadMembers; + + /// 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. + List? notRooms; + + /// A list of room IDs to include. If this list is absent then all rooms are included. + List? rooms; +} + +@_NameSource('spec') +class RoomFilter { + RoomFilter({ + this.accountData, + this.ephemeral, + this.includeLeave, + this.notRooms, + this.rooms, + this.state, + this.timeline, + }); + + RoomFilter.fromJson(Map json) + : accountData = ((v) => + v != null ? StateFilter.fromJson(v) : null)(json['account_data']), + ephemeral = ((v) => + v != null ? StateFilter.fromJson(v) : null)(json['ephemeral']), + includeLeave = + ((v) => v != null ? v as bool : null)(json['include_leave']), + notRooms = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['not_rooms']), + rooms = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['rooms']), + state = + ((v) => v != null ? StateFilter.fromJson(v) : null)(json['state']), + timeline = ((v) => + v != null ? StateFilter.fromJson(v) : null)(json['timeline']); + Map toJson() { + final accountData = this.accountData; + final ephemeral = this.ephemeral; + final includeLeave = this.includeLeave; + final notRooms = this.notRooms; + final rooms = this.rooms; + final state = this.state; + final timeline = this.timeline; + return { + if (accountData != null) 'account_data': accountData.toJson(), + if (ephemeral != null) 'ephemeral': ephemeral.toJson(), + if (includeLeave != null) 'include_leave': includeLeave, + if (notRooms != null) 'not_rooms': notRooms.map((v) => v).toList(), + if (rooms != null) 'rooms': rooms.map((v) => v).toList(), + if (state != null) 'state': state.toJson(), + if (timeline != null) 'timeline': timeline.toJson(), + }; + } + + /// The per user account data to include for rooms. + StateFilter? accountData; + + /// The events that aren't recorded in the room history, e.g. typing and receipts, to include for rooms. + StateFilter? ephemeral; + + /// Include rooms that the user has left in the sync, default false + bool? includeLeave; + + /// 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. This filter is applied before the filters in `ephemeral`, `state`, `timeline` or `account_data` + List? notRooms; + + /// A list of room IDs to include. If this list is absent then all rooms are included. This filter is applied before the filters in `ephemeral`, `state`, `timeline` or `account_data` + List? rooms; + + /// The state events to include for rooms. + StateFilter? state; + + /// The message and state update events to include for rooms. + StateFilter? timeline; +} + +@_NameSource('spec') +class Filter { + Filter({ + this.accountData, + this.eventFields, + this.eventFormat, + this.presence, + this.room, + }); + + Filter.fromJson(Map json) + : accountData = ((v) => + v != null ? EventFilter.fromJson(v) : null)(json['account_data']), + eventFields = ((v) => v != null + ? (v as List).map((v) => v as String).toList() + : null)(json['event_fields']), + eventFormat = ((v) => v != null + ? { + 'client': EventFormat.client, + 'federation': EventFormat.federation + }[v]! + : null)(json['event_format']), + presence = ((v) => + v != null ? EventFilter.fromJson(v) : null)(json['presence']), + room = ((v) => v != null ? RoomFilter.fromJson(v) : null)(json['room']); + Map toJson() { + final accountData = this.accountData; + final eventFields = this.eventFields; + final eventFormat = this.eventFormat; + final presence = this.presence; + final room = this.room; + return { + if (accountData != null) 'account_data': accountData.toJson(), + if (eventFields != null) + 'event_fields': eventFields.map((v) => v).toList(), + if (eventFormat != null) + 'event_format': { + EventFormat.client: 'client', + EventFormat.federation: 'federation' + }[eventFormat]!, + if (presence != null) 'presence': presence.toJson(), + if (room != null) 'room': room.toJson(), + }; + } + + /// The user account data that isn't associated with rooms to include. + EventFilter? accountData; + + /// List of event fields to include. If this list is absent then all fields 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. + List? eventFields; + + /// The format to use for events. 'client' will return the events in a format suitable for clients. 'federation' will return the raw event as received over federation. The default is 'client'. + EventFormat? eventFormat; + + /// The presence updates to include. + EventFilter? presence; + + /// Filters to be applied to room data. + RoomFilter? room; +} + +@_NameSource('rule override generated') +class OpenIdCredentials { + OpenIdCredentials({ + required this.accessToken, + required this.expiresIn, + required this.matrixServerName, + required this.tokenType, + }); + + OpenIdCredentials.fromJson(Map json) + : accessToken = json['access_token'] as String, + expiresIn = json['expires_in'] as int, + matrixServerName = json['matrix_server_name'] as String, + tokenType = json['token_type'] as String; + Map toJson() => { + 'access_token': accessToken, + 'expires_in': expiresIn, + 'matrix_server_name': matrixServerName, + 'token_type': tokenType, + }; + + /// 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. + String accessToken; + + /// The number of seconds before this token expires and a new one must + /// be generated. + int expiresIn; + + /// The homeserver domain the consumer should use when attempting to + /// verify the user's identity. + String matrixServerName; + + /// The string `Bearer`. + String tokenType; +} + +@_NameSource('spec') +class Tag { + Tag({ + this.order, + this.additionalProperties = const {}, + }); + + Tag.fromJson(Map json) + : order = + ((v) => v != null ? (v as num).toDouble() : null)(json['order']), + additionalProperties = Map.fromEntries(json.entries + .where((e) => !['order'].contains(e.key)) + .map((e) => MapEntry(e.key, e.value as dynamic))); + Map toJson() { + final order = this.order; + return { + ...additionalProperties, + if (order != null) 'order': order, + }; + } + + /// A number in a range `[0,1]` describing a relative + /// position of the room under the given tag. + double? order; + + Map additionalProperties; +} + +@_NameSource('rule override spec') +class Profile { + Profile({ + this.avatarUrl, + this.displayName, + required this.userId, + }); + + Profile.fromJson(Map json) + : avatarUrl = + ((v) => v != null ? Uri.parse(v) : null)(json['avatar_url']), + displayName = + ((v) => v != null ? v as String : null)(json['display_name']), + userId = json['user_id'] as String; + Map toJson() { + final avatarUrl = this.avatarUrl; + final displayName = this.displayName; + return { + if (avatarUrl != null) 'avatar_url': avatarUrl.toString(), + if (displayName != null) 'display_name': displayName, + 'user_id': userId, + }; + } + + /// The avatar url, as an MXC, if one exists. + Uri? avatarUrl; + + /// The display name of the user, if one exists. + String? displayName; + + /// The user's matrix user ID. + String userId; +} + +@_NameSource('generated') +class SearchUserDirectoryResponse { + SearchUserDirectoryResponse({ + required this.limited, + required this.results, + }); + + SearchUserDirectoryResponse.fromJson(Map json) + : limited = json['limited'] as bool, + results = + (json['results'] as List).map((v) => Profile.fromJson(v)).toList(); + Map toJson() => { + 'limited': limited, + 'results': results.map((v) => v.toJson()).toList(), + }; + + /// Indicates if the result list has been truncated by the limit. + bool limited; + + /// Ordered by rank and then whether or not profile info is available. + List results; +} + +@_NameSource('rule override generated') +class TurnServerCredentials { + TurnServerCredentials({ + required this.password, + required this.ttl, + required this.uris, + required this.username, + }); + + TurnServerCredentials.fromJson(Map json) + : password = json['password'] as String, + ttl = json['ttl'] as int, + uris = (json['uris'] as List).map((v) => v as String).toList(), + username = json['username'] as String; + Map toJson() => { + 'password': password, + 'ttl': ttl, + 'uris': uris.map((v) => v).toList(), + 'username': username, + }; + + /// The password to use. + String password; + + /// The time-to-live in seconds + int ttl; + + /// A list of TURN URIs + List uris; + + /// The username to use. + String username; +} + +@_NameSource('generated') +class GetVersionsResponse { + GetVersionsResponse({ + this.unstableFeatures, + required this.versions, + }); + + GetVersionsResponse.fromJson(Map json) + : unstableFeatures = ((v) => v != null + ? (v as Map).map((k, v) => MapEntry(k, v as bool)) + : null)(json['unstable_features']), + versions = (json['versions'] as List).map((v) => v as String).toList(); + Map toJson() { + final unstableFeatures = this.unstableFeatures; + return { + if (unstableFeatures != null) + 'unstable_features': unstableFeatures.map((k, v) => MapEntry(k, v)), + 'versions': versions.map((v) => v).toList(), + }; + } + + /// Experimental features the server supports. Features not listed here, + /// or the lack of this property all together, indicate that a feature is + /// not supported. + Map? unstableFeatures; + + /// The supported versions. + List versions; +} + +@_NameSource('rule override generated') +class ServerConfig { + ServerConfig({ + this.mUploadSize, + }); + + ServerConfig.fromJson(Map json) + : mUploadSize = + ((v) => v != null ? v as int : null)(json['m.upload.size']); + Map toJson() { + final mUploadSize = this.mUploadSize; + return { + if (mUploadSize != null) 'm.upload.size': mUploadSize, + }; + } + + /// 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. + int? mUploadSize; +} + +@_NameSource('generated') +class GetUrlPreviewResponse { + GetUrlPreviewResponse({ + this.matrixImageSize, + this.ogImage, + }); + + GetUrlPreviewResponse.fromJson(Map json) + : matrixImageSize = + ((v) => v != null ? v as int : null)(json['matrix:image:size']), + ogImage = ((v) => v != null ? Uri.parse(v) : null)(json['og:image']); + Map toJson() { + final matrixImageSize = this.matrixImageSize; + final ogImage = this.ogImage; + return { + if (matrixImageSize != null) 'matrix:image:size': matrixImageSize, + if (ogImage != null) 'og:image': ogImage.toString(), + }; + } + + /// The byte-size of the image. Omitted if there is no image attached. + int? matrixImageSize; + + /// An [MXC URI](https://spec.matrix.org/unstable/client-server-api/#matrix-content-mxc-uris) to the image. Omitted if there is no image. + Uri? ogImage; +} + +@_NameSource('generated') +enum Method { crop, scale } diff --git a/lib/src/matrix_api.dart b/lib/src/matrix_api.dart index 9e601ef7..2e2bb31c 100644 --- a/lib/src/matrix_api.dart +++ b/lib/src/matrix_api.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH @@ -26,57 +27,23 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:http/http.dart' as http; -import 'package:mime/mime.dart'; import '../matrix_api_lite.dart'; import 'model/auth/authentication_data.dart'; -import 'model/auth/authentication_types.dart'; -import 'model/device.dart'; -import 'model/event_context.dart'; import 'model/events_sync_update.dart'; -import 'model/filter.dart'; -import 'model/keys_query_response.dart'; -import 'model/login_response.dart'; -import 'model/login_types.dart'; import 'model/matrix_connection_exception.dart'; -import 'model/matrix_event.dart'; import 'model/matrix_exception.dart'; import 'model/matrix_keys.dart'; -import 'model/notifications_query_response.dart'; -import 'model/one_time_keys_claim_response.dart'; -import 'model/open_graph_data.dart'; -import 'model/open_id_credentials.dart'; -import 'model/presence_content.dart'; -import 'model/profile.dart'; -import 'model/public_rooms_response.dart'; -import 'model/push_rule_set.dart'; -import 'model/pusher.dart'; import 'model/request_token_response.dart'; -import 'model/room_alias_information.dart'; -import 'model/room_keys_info.dart'; import 'model/room_keys_keys.dart'; -import 'model/server_capabilities.dart'; import 'model/supported_protocol.dart'; -import 'model/supported_versions.dart'; -import 'model/sync_update.dart'; -import 'model/tag.dart'; -import 'model/third_party_identifier.dart'; import 'model/third_party_location.dart'; import 'model/third_party_user.dart'; -import 'model/timeline_history_response.dart'; -import 'model/turn_server_credentials.dart'; import 'model/upload_key_signatures_response.dart'; -import 'model/user_search_result.dart'; -import 'model/well_known_information.dart'; -import 'model/who_is_info.dart'; + +import 'generated/api.dart'; enum RequestType { GET, POST, PUT, DELETE } -enum IdServerUnbindResult { success, no_support } -enum ThirdPartyIdentifierMedium { email, msisdn } -enum Membership { join, invite, leave, ban } -enum Direction { b, f } -enum Visibility { public, private } -enum CreateRoomPreset { private_chat, public_chat, trusted_private_chat } String describeEnum(Object enumEntry) { final description = enumEntry.toString(); @@ -85,35 +52,39 @@ String describeEnum(Object enumEntry) { return description.substring(indexOfDot + 1); } -class MatrixApi { +class MatrixApi extends Api { /// The homeserver this client is communicating with. - Uri homeserver; + Uri get homeserver => baseUri; + set homeserver(Uri uri) => baseUri = uri; /// This is the access token for the matrix client. When it is undefined, then /// the user needs to sign in first. - String accessToken; + String get accessToken => bearerToken; + set accessToken(String token) => bearerToken = token; + + @override + Null unexpectedResponse(http.BaseResponse response, Uint8List responseBody) { + if (response.statusCode >= 400 && response.statusCode < 500) { + throw MatrixException.fromJson(json.decode(utf8.decode(responseBody))); + } + super.unexpectedResponse(response, responseBody); + } /// Matrix synchronisation is done with https long polling. This needs a /// timeout which is usually 30 seconds. int syncTimeoutSec; - http.Client httpClient = http.Client(); - - bool get _testMode => - homeserver.toString() == 'https://fakeserver.notexisting'; - int _timeoutFactor = 1; MatrixApi({ - this.homeserver, - this.accessToken, + Uri homeserver, + String accessToken, http.Client httpClient, this.syncTimeoutSec = 30, - }) { - if (httpClient != null) { - this.httpClient = httpClient; - } - } + }) : super( + httpClient: httpClient, + baseUri: homeserver, + bearerToken: accessToken); /// Used for all Matrix json requests using the [c2s API](https://matrix.org/docs/spec/client_server/r0.6.0.html). /// @@ -217,128 +188,6 @@ class MatrixApi { return jsonResp; } - /// Gets the versions of the specification supported by the server. - /// https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-versions - Future getVersions() async { - final response = await request( - RequestType.GET, - '/client/versions', - ); - return SupportedVersions.fromJson(response); - } - - /// Gets discovery information about the domain. The file may include additional keys. - /// https://matrix.org/docs/spec/client_server/r0.6.0#get-well-known-matrix-client - Future getWellknown() async { - final response = - await httpClient.get(homeserver.resolve('.well-known/matrix/client')); - final rawJson = json.decode(response.body); - return WellKnownInformation.fromJson(rawJson); - } - - Future getLoginFlows() async { - final response = await request( - RequestType.GET, - '/client/r0/login', - ); - return LoginTypes.fromJson(response); - } - - /// Authenticates the user, and issues an access token they can use to authorize themself in subsequent requests. - /// https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-login - /// To just login with the username 'alice' you set [identifier] to: - /// `AuthenticationUserIdentifier(user: 'alice')` - /// Maybe you want to set [user] to the same String to stay compatible with - /// older server versions. - Future login({ - String type = AuthenticationTypes.password, - AuthenticationIdentifier identifier, - String password, - String token, - String deviceId, - String initialDeviceDisplayName, - AuthenticationData auth, - @Deprecated('Deprecated in favour of identifier.') String user, - @Deprecated('Deprecated in favour of identifier.') String medium, - @Deprecated('Deprecated in favour of identifier.') String address, - }) async { - final response = await request(RequestType.POST, '/client/r0/login', data: { - 'type': type, - if (identifier != null) 'identifier': identifier.toJson(), - if (user != null) 'user': user, - if (medium != null) 'medium': medium, - if (address != null) 'address': address, - if (password != null) 'password': password, - if (token != null) 'token': token, - if (deviceId != null) 'device_id': deviceId, - if (initialDeviceDisplayName != null) - 'initial_device_display_name': initialDeviceDisplayName, - if (auth != null) 'auth': auth.toJson(), - }); - return LoginResponse.fromJson(response); - } - - /// Invalidates an existing access token, so that it can no longer be used for authorization. - /// The device associated with the access token is also deleted. Device keys for the device - /// are deleted alongside the device. - /// https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-logout - Future logout() async { - await request( - RequestType.POST, - '/client/r0/logout', - ); - return; - } - - /// 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. All - /// devices for the user are also deleted. Device keys for the device are - /// deleted alongside the device. - /// https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-logout-all - Future logoutAll() async { - await request( - RequestType.POST, - '/client/r0/logout/all', - ); - return; - } - - /// Register for an account on this homeserver. - /// - /// There are two kinds of user account: - /// - /// user accounts. These accounts may use the full API described in this - /// specification. - /// guest accounts. These accounts may have limited permissions and may not - /// be supported by all servers. - /// - /// If registration is successful, this endpoint will issue an access token - /// the client can use to authorize itself in subsequent requests. - /// https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-register - Future register({ - String username, - String password, - String deviceId, - String initialDeviceDisplayName, - bool inhibitLogin, - AuthenticationData auth, - String kind, - }) async { - final response = - await request(RequestType.POST, '/client/r0/register', query: { - if (kind != null) 'kind': kind, - }, data: { - if (username != null) 'username': username, - if (password != null) 'password': password, - if (deviceId != null) 'device_id': deviceId, - if (initialDeviceDisplayName != null) - 'initial_device_display_name': initialDeviceDisplayName, - if (inhibitLogin != null) 'inhibit_login': inhibitLogin, - if (auth != null) 'auth': auth.toJson(), - }); - return LoginResponse.fromJson(response); - } - /// 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 @@ -392,19 +241,6 @@ class MatrixApi { return RequestTokenResponse.fromJson(response); } - /// Changes the password for an account on this homeserver. - /// https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-account-password - Future changePassword( - String newPassword, { - AuthenticationData auth, - }) async { - await request(RequestType.POST, '/client/r0/account/password', data: { - 'new_password': newPassword, - if (auth != null) 'auth': auth.toJson(), - }); - return; - } - /// 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. @@ -457,118 +293,6 @@ class MatrixApi { return RequestTokenResponse.fromJson(response); } - /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-account-deactivate - Future deactivateAccount({ - String idServer, - AuthenticationData auth, - }) async { - final response = - await request(RequestType.POST, '/client/r0/account/deactivate', data: { - if (idServer != null) 'id_server': idServer, - if (auth != null) 'auth': auth.toJson(), - }); - - return IdServerUnbindResult.values.firstWhere( - (i) => describeEnum(i) == response['id_server_unbind_result'], - ); - } - - Future checkUsernameAvailability(String username) async { - final response = await request( - RequestType.GET, - '/client/r0/register/available', - query: { - 'username': username, - }, - ); - return response['available']; - } - - /// Gets a list of the third party identifiers that the homeserver has - /// associated with the user's account. - /// https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-register-available - Future> getAccount3PIDs() async { - final response = await request( - RequestType.GET, - '/client/r0/account/3pid', - ); - return (response['threepids'] as List) - .map((item) => ThirdPartyIdentifier.fromJson(item)) - .toList(); - } - - /// 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. - /// https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-account-3pid-add - Future add3PID( - String clientSecret, - String sid, { - AuthenticationData auth, - }) async { - await request(RequestType.POST, '/client/r0/account/3pid/add', data: { - 'sid': sid, - 'client_secret': clientSecret, - if (auth != null) 'auth': auth.toJson(), - }); - return; - } - - /// Binds a 3PID to the user's account through the specified identity server. - /// https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-account-3pid-bind - Future bind3PID( - String clientSecret, - String sid, - String idServer, - String idAccessToken, - ) async { - await request(RequestType.POST, '/client/r0/account/3pid/bind', data: { - 'sid': sid, - 'client_secret': clientSecret, - 'id_server': idServer, - 'id_access_token': idAccessToken, - }); - return; - } - - /// Removes a third party identifier from the user's account. This might not cause an unbind of the identifier from the identity server. - /// https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-account-3pid-delete - Future delete3pidFromAccount( - String address, - ThirdPartyIdentifierMedium medium, { - String idServer, - }) async { - final response = await request( - RequestType.POST, '/client/r0/account/3pid/delete', - data: { - 'address': address, - 'medium': describeEnum(medium), - if (idServer != null) 'id_server': idServer, - }); - return IdServerUnbindResult.values.firstWhere( - (i) => describeEnum(i) == response['id_server_unbind_result'], - ); - } - - /// Removes a user's third party identifier from the provided identity server without removing it from the homeserver. - /// https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-account-3pid-unbind - Future unbind3pidFromAccount( - String address, - ThirdPartyIdentifierMedium medium, - String idServer, - ) async { - final response = await request( - RequestType.POST, '/client/r0/account/3pid/unbind', - data: { - 'address': address, - 'medium': describeEnum(medium), - 'id_server': idServer, - }); - return IdServerUnbindResult.values.firstWhere( - (i) => describeEnum(i) == response['id_server_unbind_result'], - ); - } - /// This API should be used to request validation tokens when adding an email address to an account. /// https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-account-3pid-email-requesttoken Future requestEmailValidationToken( @@ -617,87 +341,6 @@ class MatrixApi { return RequestTokenResponse.fromJson(response); } - /// Gets information about the owner of a given access token. - /// https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-account-whoami - Future getTokenOwner() async { - final response = await request( - RequestType.GET, - '/client/r0/account/whoami', - ); - return response['user_id']; - } - - /// Gets information about the server's supported feature set and other relevant capabilities. - /// https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-capabilities - Future getCapabilities() async { - final response = await request( - RequestType.GET, - '/client/r0/capabilities', - ); - return ServerCapabilities.fromJson(response['capabilities']); - } - - /// 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. - /// https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-user-userid-filter - Future defineFilter( - String userId, - Filter filter, - ) async { - final response = await request( - RequestType.POST, - '/client/r0/user/${Uri.encodeComponent(userId)}/filter', - data: filter.toJson(), - ); - return response['filter_id']; - } - - /// Download a filter - /// https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-user-userid-filter - Future getFilter(String userId, String filterId) async { - final response = await request( - RequestType.GET, - '/client/r0/user/${Uri.encodeComponent(userId)}/filter/${Uri.encodeComponent(filterId)}', - ); - return Filter.fromJson(response); - } - - /// Synchronise the client's state with the latest state on the server. Clients use this API when - /// they first log in to get an initial snapshot of the state on the server, and then continue to - /// call this API to get incremental deltas to the state, and to receive new messages. - /// https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-sync - Future sync({ - String filter, - String since, - bool fullState, - PresenceType setPresence, - int timeout, - }) async { - final response = await request( - RequestType.GET, - '/client/r0/sync', - query: { - if (filter != null) 'filter': filter, - if (since != null) 'since': since, - if (fullState != null) 'full_state': fullState.toString(), - if (setPresence != null) 'set_presence': describeEnum(setPresence), - if (timeout != null) 'timeout': timeout.toString(), - }, - ); - return SyncUpdate.fromJson(response); - } - - /// Get a single event based on roomId/eventId. You must have permission to - /// retrieve this event e.g. by being a member in the room for this event. - /// https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-rooms-roomid-event-eventid - Future getOneRoomEvent(String roomId, String eventId) async { - final response = await request( - RequestType.GET, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/event/${Uri.encodeComponent(eventId)}', - ); - return MatrixEvent.fromJson(response); - } - /// 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. @@ -717,329 +360,6 @@ class MatrixApi { return response; } - /// Get the state events for the current state of a room. - /// https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-rooms-roomid-state - Future> getRoomState(String roomId) async { - final response = await request( - RequestType.GET, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/state', - ); - return (response['chunk'] as List) - .map((i) => MatrixEvent.fromJson(i)) - .toList(); - } - - /// Get the list of members for this room. - /// https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-rooms-roomid-members - Future> getMembersByRoom( - String roomId, { - String at, - Membership membership, - Membership notMembership, - }) async { - final response = await request( - RequestType.GET, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/members', - query: { - if (at != null) 'at': at, - if (membership != null) 'membership': describeEnum(membership), - if (notMembership != null) - 'not_membership': describeEnum(notMembership), - }, - ); - return (response['chunk'] as List) - .map((i) => MatrixEvent.fromJson(i)) - .toList(); - } - - /// This API returns a map of MXIDs to member info objects for members of the room. - /// https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-rooms-roomid-joined-members - Future> getJoinedMembersByRoom(String roomId) async { - final response = await request( - RequestType.GET, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/joined_members', - ); - return (response['joined'] as Map).map( - (k, v) => MapEntry(k, Profile.fromJson(v)), - ); - } - - /// This API returns a list of message and state events for a room. It uses pagination query - /// parameters to paginate history in the room. - /// https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-rooms-roomid-messages - Future getRoomEvents( - String roomId, - String from, - Direction dir, { - String to, - int limit, - String filter, - }) async { - final response = await request(RequestType.GET, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/messages', - query: { - 'from': from, - 'dir': describeEnum(dir), - if (to != null) 'to': to, - if (limit != null) 'limit': limit.toString(), - if (filter != null) 'filter': filter, - }); - return TimelineHistoryResponse.fromJson(response); - } - - /// State events can be sent using this endpoint. - /// https://matrix.org/docs/spec/client_server/r0.6.0#put-matrix-client-r0-rooms-roomid-state-eventtype-statekey - Future setRoomStateWithKey( - String roomId, - String eventType, - Map content, [ - String stateKey = '', - ]) async { - final response = await request(RequestType.PUT, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/state/${Uri.encodeComponent(eventType)}/${Uri.encodeComponent(stateKey)}', - data: content); - return response['event_id']; - } - - /// This endpoint is used to send a message event to a room. - /// Message events allow access to historical events and pagination, - /// making them suited for "once-off" activity in a room. - /// https://matrix.org/docs/spec/client_server/r0.6.0#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid - Future sendMessage( - String roomId, - String eventType, - String txnId, - Map content, - ) async { - final response = await request(RequestType.PUT, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/send/${Uri.encodeComponent(eventType)}/${Uri.encodeComponent(txnId)}', - data: content); - return response['event_id']; - } - - /// Strips all information out of an event which isn't critical to the integrity of - /// the server-side representation of the room. - /// https://matrix.org/docs/spec/client_server/r0.6.0#put-matrix-client-r0-rooms-roomid-redact-eventid-txnid - Future redactEvent( - String roomId, - String eventId, - String txnId, { - String reason, - }) async { - final response = await request(RequestType.PUT, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/redact/${Uri.encodeComponent(eventId)}/${Uri.encodeComponent(txnId)}', - data: { - if (reason != null) 'reason': reason, - }); - return response['event_id']; - } - - Future createRoom({ - Visibility visibility, - String roomAliasName, - String name, - String topic, - List invite, - List> invite3pid, - String roomVersion, - Map creationContent, - List> initialState, - CreateRoomPreset preset, - bool isDirect, - Map powerLevelContentOverride, - }) async { - final response = - await request(RequestType.POST, '/client/r0/createRoom', data: { - if (visibility != null) 'visibility': describeEnum(visibility), - if (roomAliasName != null) 'room_alias_name': roomAliasName, - if (name != null) 'name': name, - if (topic != null) 'topic': topic, - if (invite != null) 'invite': invite, - if (invite3pid != null) 'invite_3pid': invite3pid, - if (roomVersion != null) 'room_version': roomVersion, - if (creationContent != null) 'creation_content': creationContent, - if (initialState != null) 'initial_state': initialState, - if (preset != null) 'preset': describeEnum(preset), - if (isDirect != null) 'is_direct': isDirect, - if (powerLevelContentOverride != null) - 'power_level_content_override': powerLevelContentOverride, - }); - return response['room_id']; - } - - /// Create a new mapping from room alias to room ID. - /// https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-directory-room-roomalias - Future setRoomAlias(String alias, String roomId) async { - await request( - RequestType.PUT, - '/client/r0/directory/room/${Uri.encodeComponent(alias)}', - data: {'room_id': roomId}, - ); - return; - } - - /// Requests that the server resolve a room alias to a room ID. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-directory-room-roomalias - Future getRoomIdByAlias(String alias) async { - final response = await request( - RequestType.GET, - '/client/r0/directory/room/${Uri.encodeComponent(alias)}', - ); - return RoomAliasInformation.fromJson(response); - } - - /// Remove a mapping of room alias to room ID. - /// https://matrix.org/docs/spec/client_server/r0.6.1#delete-matrix-client-r0-directory-room-roomalias - Future deleteRoomAlias(String alias) async { - await request( - RequestType.DELETE, - '/client/r0/directory/room/${Uri.encodeComponent(alias)}', - ); - return; - } - - /// Get a list of aliases maintained by the local server for the given room. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-rooms-roomid-aliases - Future> getLocalAliases(String roomId) async { - final response = await request( - RequestType.GET, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/aliases', - ); - return List.from(response['aliases']); - } - - /// This API returns a list of the user's current rooms. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-joined-rooms - Future> getJoinedRooms() async { - final response = await request( - RequestType.GET, - '/client/r0/joined_rooms', - ); - return List.from(response['joined_rooms']); - } - - /// This API invites a user to participate in a particular room. - /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-invite - Future inviteToRoom(String roomId, String userId) async { - await request( - RequestType.POST, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/invite', - data: { - 'user_id': userId, - }, - ); - return; - } - - /// This API starts a user participating in a particular room, if that user is allowed to participate in that room. - /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-invite - Future joinRoomById( - String roomId, { - String thirdPidSignedSender, - String thirdPidSignedmxid, - String thirdPidSignedToken, - Map thirdPidSignedSiganture, - }) async { - final response = await request( - RequestType.POST, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/join', - data: { - if (thirdPidSignedSiganture != null) - 'third_party_signed': { - 'sender': thirdPidSignedSender, - 'mxid': thirdPidSignedmxid, - 'token': thirdPidSignedToken, - 'signatures': thirdPidSignedSiganture, - } - }, - ); - return response['room_id']; - } - - /// This API starts a user participating in a particular room, if that user is allowed to participate in that room. - /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-join-roomidoralias - Future joinRoom( - String roomIdOrAlias, { - List servers, - String thirdPidSignedSender, - String thirdPidSignedmxid, - String thirdPidSignedToken, - Map thirdPidSignedSiganture, - }) async { - final response = await request( - RequestType.POST, - '/client/r0/join/${Uri.encodeComponent(roomIdOrAlias)}', - query: {'server_name': servers ?? []}, - data: { - if (thirdPidSignedSiganture != null) - 'third_party_signed': { - 'sender': thirdPidSignedSender, - 'mxid': thirdPidSignedmxid, - 'token': thirdPidSignedToken, - 'signatures': thirdPidSignedSiganture, - } - }, - ); - return response['room_id']; - } - - /// This API stops a user participating in a particular room. - /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-leave - Future leaveRoom(String roomId) async { - await request( - RequestType.POST, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/leave', - ); - return; - } - - /// This API stops a user remembering about a particular room. - /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-forget - Future forgetRoom(String roomId) async { - await request( - RequestType.POST, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/forget', - ); - return; - } - - /// Kick a user from the room. - /// The caller must have the required power level in order to perform this operation. - /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-kick - Future kick(String roomId, String userId, {String reason}) async { - await request(RequestType.POST, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/kick', - data: { - 'user_id': userId, - if (reason != null) 'reason': reason, - }); - return; - } - - /// Ban a user in the room. If the user is currently in the room, also kick them. - /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-ban - Future ban(String roomId, String userId, {String reason}) async { - await request( - RequestType.POST, '/client/r0/rooms/${Uri.encodeComponent(roomId)}/ban', - data: { - 'user_id': userId, - if (reason != null) 'reason': reason, - }); - return; - } - - /// Unban a user from the room. This allows them to be invited to the room, and join if they - /// would otherwise be allowed to join according to its join rules. - /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-unban - Future unban(String roomId, String userId) async { - await request(RequestType.POST, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/unban', - data: { - 'user_id': userId, - }); - return; - } - /// Gets the visibility of a given room on the server's public room directory. /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-directory-list-room-roomid Future getRoomVisibilityOnDirectory(String roomId) async { @@ -1065,356 +385,6 @@ class MatrixApi { return; } - /// Lists the public rooms on the server. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-publicrooms - Future getPublicRooms({ - int limit, - String since, - String server, - }) async { - final response = await request( - RequestType.GET, - '/client/r0/publicRooms', - query: { - if (limit != null) 'limit': limit.toString(), - if (since != null) 'since': since, - if (server != null) 'server': server, - }, - ); - return PublicRoomsResponse.fromJson(response); - } - - /// Lists the public rooms on the server, with optional filter. - /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-publicrooms - Future queryPublicRooms({ - String genericSearchTerm, - int limit, - String since, - String server, - bool includeAllNetworks, - String thirdPartyInstanceId, - }) async { - final response = await request( - RequestType.POST, - '/client/r0/publicRooms', - query: { - if (server != null) 'server': server, - }, - data: { - if (limit != null) 'limit': limit, - if (since != null) 'since': since, - if (includeAllNetworks != null) - 'include_all_networks': includeAllNetworks, - if (thirdPartyInstanceId != null) - 'third_party_instance_id': thirdPartyInstanceId, - if (genericSearchTerm != null) - 'filter': { - 'generic_search_term': genericSearchTerm, - }, - }, - ); - return PublicRoomsResponse.fromJson(response); - } - - /// 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). The search MUST - /// consider local users to the homeserver, and SHOULD query remote users as part of the search. - /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-user-directory-search - Future searchUserDirectory( - String searchTerm, { - int limit, - }) async { - final response = await request( - RequestType.POST, - '/client/r0/user_directory/search', - data: { - 'search_term': searchTerm, - if (limit != null) 'limit': limit, - }, - ); - return UserSearchResult.fromJson(response); - } - - /// This API sets the given user's display name. You must have permission to - /// set this user's display name, e.g. you need to have their access_token. - /// https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-profile-userid-displayname - Future setDisplayName(String userId, String displayname) async { - await request( - RequestType.PUT, - '/client/r0/profile/${Uri.encodeComponent(userId)}/displayname', - data: { - 'displayname': displayname, - }, - ); - return; - } - - /// Get the user's display name. This API may be used to fetch the user's own - /// displayname or to query the name of other users; either locally or on remote homeservers. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-profile-userid-displayname - Future getDisplayName(String userId) async { - final response = await request( - RequestType.GET, - '/client/r0/profile/${Uri.encodeComponent(userId)}/displayname', - ); - return response['displayname']; - } - - /// This API sets the given user's avatar URL. You must have permission to set - /// this user's avatar URL, e.g. you need to have their access_token. - /// https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-profile-userid-avatar-url - Future setAvatarUrl(String userId, Uri avatarUrl) async { - await request( - RequestType.PUT, - '/client/r0/profile/${Uri.encodeComponent(userId)}/avatar_url', - data: { - 'avatar_url': avatarUrl.toString(), - }, - ); - return; - } - - /// Get the user's avatar URL. This API may be used to fetch the user's own avatar URL or to - /// query the URL of other users; either locally or on remote homeservers. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-profile-userid-avatar-url - Future getAvatarUrl(String userId) async { - final response = await request( - RequestType.GET, - '/client/r0/profile/${Uri.encodeComponent(userId)}/avatar_url', - ); - return Uri.parse(response['avatar_url']); - } - - /// Get the combined profile information for this user. This API may be used to fetch the user's - /// own profile information or other users; either locally or on remote homeservers. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-profile-userid-avatar-url - Future getUserProfile(String userId) async { - final response = await request( - RequestType.GET, - '/client/r0/profile/${Uri.encodeComponent(userId)}', - ); - return Profile.fromJson(response); - } - - /// This API provides credentials for the client to use when initiating calls. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-voip-turnserver - Future getTurnServer() async { - final response = await request( - RequestType.GET, - '/client/r0/voip/turnServer', - ); - return TurnServerCredentials.fromJson(response); - } - - /// This tells the server that the user is typing for the next N milliseconds - /// where N is the value specified in the timeout key. Alternatively, if typing is false, - /// it tells the server that the user has stopped typing. - /// https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-rooms-roomid-typing-userid - Future setTyping( - String userId, - String roomId, - bool typing, { - int timeout, - }) async { - await request(RequestType.PUT, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/typing/${Uri.encodeComponent(userId)}', - data: { - 'typing': typing, - if (timeout != null) 'timeout': timeout, - }); - return; - } - - /// This API updates the marker for the given receipt type to the event ID specified. - /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-receipt-receipttype-eventid - /// - Future postReceipt(String roomId, String eventId) async { - await request( - RequestType.POST, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/receipt/m.read/${Uri.encodeComponent(eventId)}', - ); - return; - } - - /// Sets the position of the read marker for a given room, and optionally the read receipt's location. - /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-read-markers - Future setReadMarker(String roomId, String eventId, - {String readReceiptLocationEventId}) async { - await request( - RequestType.POST, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/read_markers', - data: { - 'm.fully_read': eventId, - if (readReceiptLocationEventId != null) - 'm.read': readReceiptLocationEventId, - }, - ); - return; - } - - /// This API sets the given user's presence state. When setting the status, - /// the activity time is updated to reflect that activity; the client does not need - /// to specify the last_active_ago field. You cannot set the presence state of another user. - /// https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-presence-userid-status - Future setPresence( - String userId, - PresenceType presenceType, { - String statusMsg, - }) async { - await request( - RequestType.PUT, - '/client/r0/presence/${Uri.encodeComponent(userId)}/status', - data: { - 'presence': describeEnum(presenceType), - if (statusMsg != null) 'status_msg': statusMsg, - }, - ); - return; - } - - /// Get the given user's presence state. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-presence-userid-status - Future getPresence(String userId) async { - final response = await request( - RequestType.GET, - '/client/r0/presence/${Uri.encodeComponent(userId)}/status', - ); - return PresenceContent.fromJson(response); - } - - /// Uploads a file with the name [fileName] as base64 encoded to the server - /// and returns the mxc url as a string. - /// https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-media-r0-upload - Future uploadContent(Uint8List file, String fileName, - {String contentType}) async { - fileName = fileName.split('/').last; - final length = file.length; - final headers = {}; - headers['Authorization'] = 'Bearer $accessToken'; - headers['Content-Type'] = - contentType ?? lookupMimeType(fileName, headerBytes: file); - headers['Content-Length'] = length.toString(); - fileName = Uri.encodeQueryComponent(fileName); - final url = homeserver.resolveUri(Uri( - path: '_matrix/media/r0/upload', - queryParameters: {'filename': fileName}, - )); - final streamedRequest = http.StreamedRequest('POST', url) - ..headers.addAll(headers); - streamedRequest.contentLength = length; - streamedRequest.sink.add(file); - streamedRequest.sink.close(); - final streamedResponse = _testMode ? null : await streamedRequest.send(); - final Map jsonResponse = json.decode( - String.fromCharCodes(_testMode - ? ((fileName == 'file.jpeg') - ? '{"content_uri": "mxc://example.com/AQwafuaFswefuhsfAFAgsw"}' - : '{"errcode":"M_FORBIDDEN","error":"Cannot upload this content"}') - .codeUnits - : await streamedResponse.stream.first), - ); - if (!(jsonResponse['content_uri'] is String)) { - throw MatrixException.fromJson(jsonResponse); - } - return jsonResponse['content_uri']; - } - - /// 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. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-media-r0-preview-url - Future getUrlPreview(Uri url, {int ts}) async { - final action = homeserver - .resolveUri(Uri(path: '_matrix/media/r0/preview_url', queryParameters: { - 'url': url.toString(), - if (ts != null) 'ts': ts.toString(), - })); - final response = await httpClient.get(action); - final rawJson = json.decode(response.body.isEmpty ? '{}' : response.body); - return OpenGraphData.fromJson(rawJson); - } - - /// This endpoint allows clients to retrieve the configuration of the content repository, such as upload limitations. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-media-r0-config - Future getConfig() async { - final action = homeserver.resolve('_matrix/media/r0/config'); - final response = await httpClient.get(action); - final rawJson = json.decode(response.body.isEmpty ? '{}' : response.body); - return rawJson['m.upload.size']; - } - - /// This endpoint is used to send send-to-device events to a set of client devices. - /// https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-sendtodevice-eventtype-txnid - Future sendToDevice( - String eventType, - String txnId, - Map>> messages, - ) async { - await request( - RequestType.PUT, - '/client/r0/sendToDevice/${Uri.encodeComponent(eventType)}/${Uri.encodeComponent(txnId)}', - data: { - 'messages': messages, - }, - ); - return; - } - - /// Gets information about all devices for the current user. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-devices - Future> getDevices() async { - final response = await request( - RequestType.GET, - '/client/r0/devices', - ); - return (response['devices'] as List) - .map((i) => Device.fromJson(i)) - .toList(); - } - - /// Gets information on a single device, by device id. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-devices-deviceid - Future getDevice(String deviceId) async { - final response = await request( - RequestType.GET, - '/client/r0/devices/${Uri.encodeComponent(deviceId)}', - ); - return Device.fromJson(response); - } - - /// Updates the metadata on the given device. - /// https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-devices-deviceid - Future updateDevice(String deviceId, {String displayName}) async { - await request( - RequestType.PUT, '/client/r0/devices/${Uri.encodeComponent(deviceId)}', - data: { - if (displayName != null) 'display_name': displayName, - }); - return; - } - - /// Deletes the given device, and invalidates any access token associated with it. - /// https://matrix.org/docs/spec/client_server/r0.6.1#delete-matrix-client-r0-devices-deviceid - Future deleteDevice(String deviceId, {AuthenticationData auth}) async { - await request(RequestType.DELETE, - '/client/r0/devices/${Uri.encodeComponent(deviceId)}', - data: { - if (auth != null) 'auth': auth.toJson(), - }); - return; - } - - /// Deletes the given devices, and invalidates any access token associated with them. - /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-delete-devices - Future deleteDevices(List deviceIds, - {AuthenticationData auth}) async { - await request(RequestType.POST, '/client/r0/delete_devices', data: { - 'devices': deviceIds, - if (auth != null) 'auth': auth.toJson(), - }); - return; - } - /// Publishes end-to-end encryption keys for the device. /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-keys-query Future> uploadKeys( @@ -1436,53 +406,6 @@ class MatrixApi { return Map.from(response['one_time_key_counts']); } - /// Returns the current devices and identity keys for the given users. - /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-keys-query - Future queryKeys( - Map deviceKeys, { - int timeout, - String token, - }) async { - final response = await request( - RequestType.POST, - '/client/r0/keys/query', - data: { - 'device_keys': deviceKeys, - if (timeout != null) 'timeout': timeout, - if (token != null) 'token': token, - }, - ); - return KeysQueryResponse.fromJson(response); - } - - /// Claims one-time keys for use in pre-key messages. - /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-keys-claim - Future claimKeys( - Map> oneTimeKeys, { - int timeout, - }) async { - final response = await request( - RequestType.POST, - '/client/r0/keys/claim', - data: { - 'one_time_keys': oneTimeKeys, - if (timeout != null) 'timeout': timeout, - }, - ); - return OneTimeKeysClaimResponse.fromJson(response); - } - - /// Gets a list of users who have updated their device identity keys since a previous sync token. - /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-keys-upload - Future getKeysChanges(String from, String to) async { - final response = - await request(RequestType.GET, '/client/r0/keys/changes', query: { - 'from': from, - 'to': to, - }); - return DeviceListsUpdate.fromJson(response); - } - /// Uploads your own cross-signing keys. /// https://github.com/matrix-org/matrix-doc/pull/2536 Future uploadDeviceSigningKeys({ @@ -1534,18 +457,6 @@ class MatrixApi { return UploadKeySignaturesResponse.fromJson(response); } - /// Gets all currently active pushers for the authenticated user. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-pushers - Future> getPushers() async { - final response = await request( - RequestType.GET, - '/client/r0/pushers', - ); - return (response['pushers'] as List) - .map((i) => Pusher.fromJson(i)) - .toList(); - } - /// This endpoint allows the creation, modification and deletion of pushers /// for this user ID. The behaviour of this endpoint varies depending on the /// values in the JSON body. @@ -1563,169 +474,6 @@ class MatrixApi { return; } - /// This API is used to paginate through the list of events that the user has - /// been, or would have been notified about. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-notifications - Future getNotifications({ - String from, - int limit, - String only, - }) async { - final response = await request( - RequestType.GET, - '/client/r0/notifications', - query: { - if (from != null) 'from': from, - if (limit != null) 'limit': limit.toString(), - if (only != null) 'only': only, - }, - ); - return NotificationsQueryResponse.fromJson(response); - } - - /// Retrieve all push rulesets for this user. Clients can "drill-down" - /// on the rulesets by suffixing a scope to this path e.g. /pushrules/global/. - /// This will return a subset of this data under the specified key e.g. the global key. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-pushrules - Future getPushRules() async { - final response = await request( - RequestType.GET, - '/client/r0/pushrules', - ); - return PushRuleSet.fromJson(response['global']); - } - - /// Retrieve a single specified push rule. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-pushrules-scope-kind-ruleid - Future getPushRule( - String scope, - PushRuleKind kind, - String ruleId, - ) async { - final response = await request( - RequestType.GET, - '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(describeEnum(kind))}/${Uri.encodeComponent(ruleId)}', - ); - return PushRule.fromJson(response); - } - - /// This endpoint removes the push rule defined in the path. - /// https://matrix.org/docs/spec/client_server/r0.6.1#delete-matrix-client-r0-pushrules-scope-kind-ruleid - Future deletePushRule( - String scope, - PushRuleKind kind, - String ruleId, - ) async { - await request( - RequestType.DELETE, - '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(describeEnum(kind))}/${Uri.encodeComponent(ruleId)}', - ); - return; - } - - /// This endpoint allows the creation, modification and deletion of pushers for this user ID. - /// The behaviour of this endpoint varies depending on the values in the JSON body. - /// https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-pushrules-scope-kind-ruleid - Future setPushRule( - String scope, - PushRuleKind kind, - String ruleId, - List actions, { - String before, - String after, - List conditions, - String pattern, - }) async { - await request(RequestType.PUT, - '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(describeEnum(kind))}/${Uri.encodeComponent(ruleId)}', - query: { - if (before != null) 'before': before, - if (after != null) 'after': after, - }, - data: { - 'actions': actions.map(describeEnum).toList(), - if (conditions != null) - 'conditions': conditions.map((c) => c.toJson()).toList(), - if (pattern != null) 'pattern': pattern, - }); - return; - } - - /// This endpoint gets whether the specified push rule is enabled. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-pushrules-scope-kind-ruleid-enabled - Future isPushRuleEnabled( - String scope, - PushRuleKind kind, - String ruleId, - ) async { - final response = await request( - RequestType.GET, - '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(describeEnum(kind))}/${Uri.encodeComponent(ruleId)}/enabled', - ); - return response['enabled']; - } - - /// This endpoint allows clients to enable or disable the specified push rule. - /// https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-pushrules-scope-kind-ruleid-enabled - Future setPushRuleEnabled( - String scope, - PushRuleKind kind, - String ruleId, - bool enabled, - ) async { - await request( - RequestType.PUT, - '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(describeEnum(kind))}/${Uri.encodeComponent(ruleId)}/enabled', - data: {'enabled': enabled}, - ); - return; - } - - /// This endpoint get the actions for the specified push rule. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-pushrules-scope-kind-ruleid-actions - Future> getPushRuleActions( - String scope, - PushRuleKind kind, - String ruleId, - ) async { - final response = await request( - RequestType.GET, - '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(describeEnum(kind))}/${Uri.encodeComponent(ruleId)}/actions', - ); - return (response['actions'] as List) - .map((i) => - PushRuleAction.values.firstWhere((a) => describeEnum(a) == i)) - .toList(); - } - - /// This endpoint allows clients to change the actions of a push rule. This can be used to change the actions of builtin rules. - /// https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-pushrules-scope-kind-ruleid-actions - Future setPushRuleActions( - String scope, - PushRuleKind kind, - String ruleId, - List actions, - ) async { - await request( - RequestType.PUT, - '/client/r0/pushrules/${Uri.encodeComponent(scope)}/${Uri.encodeComponent(describeEnum(kind))}/${Uri.encodeComponent(ruleId)}/actions', - data: {'actions': actions.map((a) => describeEnum(a)).toList()}, - ); - return; - } - - /// Performs a full text search across different categories. - /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-search - /// Please note: The specification is not 100% clear what it is expecting and sending here. - /// So we stick with pure json until we have more information. - Future> search(Map query) async { - return await request( - RequestType.POST, - '/client/r0/search', - data: query, - ); - } - /// This will listen for new events related to a particular room and return them to the /// caller. This will block until an event is received, or until the timeout is reached. /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-events @@ -1743,147 +491,6 @@ class MatrixApi { return EventsSyncUpdate.fromJson(response); } - /// List the tags set by a user on a room. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-user-userid-rooms-roomid-tags - Future> getRoomTags(String userId, String roomId) async { - final response = await request( - RequestType.GET, - '/client/r0/user/${Uri.encodeComponent(userId)}/rooms/${Uri.encodeComponent(roomId)}/tags', - ); - return (response['tags'] as Map).map( - (k, v) => MapEntry(k, Tag.fromJson(v)), - ); - } - - /// Add a tag to the room. - /// https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-user-userid-rooms-roomid-tags-tag - Future setRoomTag( - String userId, - String roomId, - String tag, { - double order, - }) async { - await request(RequestType.PUT, - '/client/r0/user/${Uri.encodeComponent(userId)}/rooms/${Uri.encodeComponent(roomId)}/tags/${Uri.encodeComponent(tag)}', - data: { - if (order != null) 'order': order, - }); - return; - } - - /// Remove a tag from the room. - /// https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-user-userid-rooms-roomid-tags-tag - Future deleteRoomTag(String userId, String roomId, String tag) async { - await request( - RequestType.DELETE, - '/client/r0/user/${Uri.encodeComponent(userId)}/rooms/${Uri.encodeComponent(roomId)}/tags/${Uri.encodeComponent(tag)}', - ); - return; - } - - /// Set some account_data for the client. This config is only visible to the user that set the account_data. - /// The config will be synced to clients in the top-level account_data. - /// https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-user-userid-account-data-type - Future setAccountData( - String userId, - String type, - Map content, - ) async { - await request( - RequestType.PUT, - '/client/r0/user/${Uri.encodeComponent(userId)}/account_data/${Uri.encodeComponent(type)}', - data: content, - ); - return; - } - - /// Get some account_data for the client. This config is only visible to the user that set the account_data. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-user-userid-account-data-type - Future> getAccountData( - String userId, - String type, - ) async { - return await request( - RequestType.GET, - '/client/r0/user/${Uri.encodeComponent(userId)}/account_data/${Uri.encodeComponent(type)}', - ); - } - - /// Set some account_data for the client on a given room. This config is only visible to the user that set - /// the account_data. The config will be synced to clients in the per-room account_data. - /// https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-user-userid-rooms-roomid-account-data-type - Future setAccountDataPerRoom( - String userId, - String roomId, - String type, - Map content, - ) async { - await request( - RequestType.PUT, - '/client/r0/user/${Uri.encodeComponent(userId)}/rooms/${Uri.encodeComponent(roomId)}/account_data/${Uri.encodeComponent(type)}', - data: content, - ); - return; - } - - /// Get some account_data for the client on a given room. This config is only visible to the user that set the account_data. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-user-userid-rooms-roomid-account-data-type - Future> getAccountDataPerRoom( - String userId, - String roomId, - String type, - ) async { - return await request( - RequestType.GET, - '/client/r0/user/${Uri.encodeComponent(userId)}/rooms/${Uri.encodeComponent(roomId)}/account_data/${Uri.encodeComponent(type)}', - ); - } - - /// Gets information about a particular user. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-admin-whois-userid - Future getWhoIs(String userId) async { - final response = await request( - RequestType.GET, - '/client/r0/admin/whois/${Uri.encodeComponent(userId)}', - ); - return WhoIsInfo.fromJson(response); - } - - /// 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. - /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-rooms-roomid-context-eventid - Future getEventContext( - String roomId, - String eventId, { - int limit, - String filter, - }) async { - final response = await request(RequestType.GET, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/context/${Uri.encodeComponent(eventId)}', - query: { - if (filter != null) 'filter': filter, - if (limit != null) 'limit': limit.toString(), - }); - return EventContext.fromJson(response); - } - - /// Reports an event as inappropriate to the server, which may then notify the appropriate people. - /// https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-rooms-roomid-report-eventid - Future reportContent( - String roomId, - String eventId, - String reason, - int score, - ) async { - await request(RequestType.POST, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/report/${Uri.encodeComponent(eventId)}', - data: { - 'reason': reason, - 'score': score, - }); - return; - } - /// Fetches the overall metadata about protocols supported by the homeserver. Includes /// both the available protocols and all fields required for queries against each protocol. /// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-thirdparty-protocols @@ -1959,68 +566,6 @@ class MatrixApi { .toList(); } - Future requestOpenIdToken(String userId) async { - final response = await request( - RequestType.POST, - '/client/r0/user/${Uri.encodeComponent(userId)}/openid/request_token', - data: {}, - ); - return OpenIdCredentials.fromJson(response); - } - - Future upgradeRoom(String roomId, String version) async { - await request( - RequestType.POST, - '/client/r0/rooms/${Uri.encodeComponent(roomId)}/upgrade', - data: {'new_version': version}, - ); - return; - } - - /// Create room keys backup - /// https://matrix.org/docs/spec/client_server/unstable#post-matrix-client-r0-room-keys-version - Future createRoomKeysBackup( - RoomKeysAlgorithmType algorithm, Map authData) async { - final ret = await request( - RequestType.POST, - '/client/unstable/room_keys/version', - data: { - 'algorithm': algorithm.algorithmString, - 'auth_data': authData, - }, - ); - return ret['version']; - } - - /// Gets a room key backup - /// https://matrix.org/docs/spec/client_server/unstable#get-matrix-client-r0-room-keys-version - Future getRoomKeysBackup([String version]) async { - var url = '/client/unstable/room_keys/version'; - if (version != null) { - url += '/${Uri.encodeComponent(version)}'; - } - final ret = await request( - RequestType.GET, - url, - ); - return RoomKeysVersionResponse.fromJson(ret); - } - - /// Updates a room key backup - /// https://matrix.org/docs/spec/client_server/unstable#put-matrix-client-r0-room-keys-version-version - Future updateRoomKeysBackup(String version, - RoomKeysAlgorithmType algorithm, Map authData) async { - await request( - RequestType.PUT, - '/client/unstable/room_keys/version/${Uri.encodeComponent(version)}', - data: { - 'algorithm': algorithm.algorithmString, - 'auth_data': authData, - 'version': version, - }, - ); - } - /// Deletes a room key backup /// https://matrix.org/docs/spec/client_server/unstable#delete-matrix-client-r0-room-keys-version-version Future deleteRoomKeysBackup(String version) async { @@ -2030,19 +575,6 @@ class MatrixApi { ); } - /// Stores a single room key - /// https://matrix.org/docs/spec/client_server/unstable#put-matrix-client-r0-room-keys-keys-roomid-sessionid - Future storeRoomKeysSingleKey(String roomId, - String sessionId, String version, RoomKeysSingleKey session) async { - final ret = await request( - RequestType.PUT, - '/client/unstable/room_keys/keys/${Uri.encodeComponent(roomId)}/${Uri.encodeComponent(sessionId)}', - query: {'version': version}, - data: session.toJson(), - ); - return RoomKeysUpdateResponse.fromJson(ret); - } - /// Gets a single room key /// https://matrix.org/docs/spec/client_server/unstable#get-matrix-client-r0-room-keys-keys-roomid-sessionid Future getRoomKeysSingleKey( @@ -2067,19 +599,6 @@ class MatrixApi { return RoomKeysUpdateResponse.fromJson(ret); } - /// Stores room keys for a room - /// https://matrix.org/docs/spec/client_server/unstable#put-matrix-client-r0-room-keys-keys-roomid - Future storeRoomKeysRoom( - String roomId, String version, RoomKeysRoom keys) async { - final ret = await request( - RequestType.PUT, - '/client/unstable/room_keys/keys/${Uri.encodeComponent(roomId)}', - query: {'version': version}, - data: keys.toJson(), - ); - return RoomKeysUpdateResponse.fromJson(ret); - } - /// Gets room keys for a room /// https://matrix.org/docs/spec/client_server/unstable#get-matrix-client-r0-room-keys-keys-roomid Future getRoomKeysRoom(String roomId, String version) async { @@ -2103,19 +622,6 @@ class MatrixApi { return RoomKeysUpdateResponse.fromJson(ret); } - /// Store multiple room keys - /// https://matrix.org/docs/spec/client_server/unstable#put-matrix-client-r0-room-keys-keys - Future storeRoomKeys( - String version, RoomKeys keys) async { - final ret = await request( - RequestType.PUT, - '/client/unstable/room_keys/keys', - query: {'version': version}, - data: keys.toJson(), - ); - return RoomKeysUpdateResponse.fromJson(ret); - } - /// get all room keys /// https://matrix.org/docs/spec/client_server/unstable#get-matrix-client-r0-room-keys-keys Future getRoomKeys(String version) async { diff --git a/lib/src/model/algorithm_types.dart b/lib/src/model/algorithm_types.dart index e4f8548b..207ccd96 100644 --- a/lib/src/model/algorithm_types.dart +++ b/lib/src/model/algorithm_types.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/auth/authentication_data.dart b/lib/src/model/auth/authentication_data.dart index 2d8e0632..68441c43 100644 --- a/lib/src/model/auth/authentication_data.dart +++ b/lib/src/model/auth/authentication_data.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/auth/authentication_identifier.dart b/lib/src/model/auth/authentication_identifier.dart index 29242a83..14047d42 100644 --- a/lib/src/model/auth/authentication_identifier.dart +++ b/lib/src/model/auth/authentication_identifier.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/auth/authentication_password.dart b/lib/src/model/auth/authentication_password.dart index f727c6c0..99d2c26d 100644 --- a/lib/src/model/auth/authentication_password.dart +++ b/lib/src/model/auth/authentication_password.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/auth/authentication_phone_identifier.dart b/lib/src/model/auth/authentication_phone_identifier.dart index d45a3eab..7ae42bf6 100644 --- a/lib/src/model/auth/authentication_phone_identifier.dart +++ b/lib/src/model/auth/authentication_phone_identifier.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/auth/authentication_recaptcha.dart b/lib/src/model/auth/authentication_recaptcha.dart index a98ec159..256f1931 100644 --- a/lib/src/model/auth/authentication_recaptcha.dart +++ b/lib/src/model/auth/authentication_recaptcha.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/auth/authentication_third_party_identifier.dart b/lib/src/model/auth/authentication_third_party_identifier.dart index e8dabf3b..3cb44fe3 100644 --- a/lib/src/model/auth/authentication_third_party_identifier.dart +++ b/lib/src/model/auth/authentication_third_party_identifier.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/auth/authentication_three_pid_creds.dart b/lib/src/model/auth/authentication_three_pid_creds.dart index 41c04d6c..faaef644 100644 --- a/lib/src/model/auth/authentication_three_pid_creds.dart +++ b/lib/src/model/auth/authentication_three_pid_creds.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/auth/authentication_token.dart b/lib/src/model/auth/authentication_token.dart index d8e96301..32d42dd3 100644 --- a/lib/src/model/auth/authentication_token.dart +++ b/lib/src/model/auth/authentication_token.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/auth/authentication_types.dart b/lib/src/model/auth/authentication_types.dart index ea181e40..2a667ee6 100644 --- a/lib/src/model/auth/authentication_types.dart +++ b/lib/src/model/auth/authentication_types.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/auth/authentication_user_identifier.dart b/lib/src/model/auth/authentication_user_identifier.dart index 7531bdd8..0e1a98dc 100644 --- a/lib/src/model/auth/authentication_user_identifier.dart +++ b/lib/src/model/auth/authentication_user_identifier.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/basic_event.dart b/lib/src/model/basic_event.dart index cd708d48..0be5741f 100644 --- a/lib/src/model/basic_event.dart +++ b/lib/src/model/basic_event.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/basic_event_with_sender.dart b/lib/src/model/basic_event_with_sender.dart index 8a99781c..78a7979b 100644 --- a/lib/src/model/basic_event_with_sender.dart +++ b/lib/src/model/basic_event_with_sender.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/basic_room_event.dart b/lib/src/model/basic_room_event.dart index 3a3dbb86..4e9a0cf5 100644 --- a/lib/src/model/basic_room_event.dart +++ b/lib/src/model/basic_room_event.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/device.dart b/lib/src/model/device.dart deleted file mode 100644 index 825c828d..00000000 --- a/lib/src/model/device.dart +++ /dev/null @@ -1,51 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -class Device { - String deviceId; - String displayName; - String lastSeenIp; - DateTime lastSeenTs; - - Device.fromJson(Map json) - : deviceId = json['device_id'], - displayName = json['display_name'], - lastSeenIp = json['last_seen_ip'], - lastSeenTs = - DateTime.fromMillisecondsSinceEpoch(json['last_seen_ts'] ?? 0); - - Map toJson() { - final data = {}; - data['device_id'] = deviceId; - if (displayName != null) { - data['display_name'] = displayName; - } - if (lastSeenIp != null) { - data['last_seen_ip'] = lastSeenIp; - } - if (lastSeenTs != null) { - data['last_seen_ts'] = lastSeenTs.millisecondsSinceEpoch; - } - return data; - } -} diff --git a/lib/src/model/event_context.dart b/lib/src/model/event_context.dart deleted file mode 100644 index 90620915..00000000 --- a/lib/src/model/event_context.dart +++ /dev/null @@ -1,75 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -import 'matrix_event.dart'; - -class EventContext { - String end; - List eventsAfter; - MatrixEvent event; - List eventsBefore; - String start; - List state; - - EventContext.fromJson(Map json) - : end = json['end'], - eventsAfter = (json['events_after'] != null) - ? (json['events_after'] as List) - .map((v) => MatrixEvent.fromJson(v)) - .toList() - : null, - event = - json['event'] != null ? MatrixEvent.fromJson(json['event']) : null, - eventsBefore = (json['events_before'] != null) - ? (json['events_before'] as List) - .map((v) => MatrixEvent.fromJson(v)) - .toList() - : null, - start = json['start'], - state = (json['state'] != null) - ? (json['state'] as List) - .map((v) => MatrixEvent.fromJson(v)) - .toList() - : null; - - Map toJson() { - final data = {}; - if (end != null) { - data['end'] = end; - } - if (eventsAfter != null) { - data['events_after'] = eventsAfter.map((v) => v.toJson()).toList(); - } - if (event != null) { - data['event'] = event.toJson(); - } - if (eventsBefore != null) { - data['events_before'] = eventsBefore.map((v) => v.toJson()).toList(); - } - data['start'] = start; - if (state != null) { - data['state'] = state.map((v) => v.toJson()).toList(); - } - return data; - } -} diff --git a/lib/src/model/event_types.dart b/lib/src/model/event_types.dart index 69251296..50840346 100644 --- a/lib/src/model/event_types.dart +++ b/lib/src/model/event_types.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/events/forwarded_room_key_content.dart b/lib/src/model/events/forwarded_room_key_content.dart index 73eac32e..a9b238fc 100644 --- a/lib/src/model/events/forwarded_room_key_content.dart +++ b/lib/src/model/events/forwarded_room_key_content.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/events/olm_plaintext_payload.dart b/lib/src/model/events/olm_plaintext_payload.dart index c4a918d5..55f377f3 100644 --- a/lib/src/model/events/olm_plaintext_payload.dart +++ b/lib/src/model/events/olm_plaintext_payload.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/events/room_encrypted_content.dart b/lib/src/model/events/room_encrypted_content.dart index def336dc..0b132541 100644 --- a/lib/src/model/events/room_encrypted_content.dart +++ b/lib/src/model/events/room_encrypted_content.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/events/room_encryption_content.dart b/lib/src/model/events/room_encryption_content.dart index 15ea46f0..33afcda2 100644 --- a/lib/src/model/events/room_encryption_content.dart +++ b/lib/src/model/events/room_encryption_content.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/events/room_key_content.dart b/lib/src/model/events/room_key_content.dart index 4a78e36f..8686db21 100644 --- a/lib/src/model/events/room_key_content.dart +++ b/lib/src/model/events/room_key_content.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/events/room_key_request_content.dart b/lib/src/model/events/room_key_request_content.dart index c48a1fba..ca690e52 100644 --- a/lib/src/model/events/room_key_request_content.dart +++ b/lib/src/model/events/room_key_request_content.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/events/secret_storage_default_key_content.dart b/lib/src/model/events/secret_storage_default_key_content.dart index f5067a34..a8630813 100644 --- a/lib/src/model/events/secret_storage_default_key_content.dart +++ b/lib/src/model/events/secret_storage_default_key_content.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/events/secret_storage_key_content.dart b/lib/src/model/events/secret_storage_key_content.dart index 899fead4..de7e3618 100644 --- a/lib/src/model/events/secret_storage_key_content.dart +++ b/lib/src/model/events/secret_storage_key_content.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/events/tombstone_content.dart b/lib/src/model/events/tombstone_content.dart index dfc8beef..9e939223 100644 --- a/lib/src/model/events/tombstone_content.dart +++ b/lib/src/model/events/tombstone_content.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/events_sync_update.dart b/lib/src/model/events_sync_update.dart index 1e53d9ee..1a215473 100644 --- a/lib/src/model/events_sync_update.dart +++ b/lib/src/model/events_sync_update.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/filter.dart b/lib/src/model/filter.dart deleted file mode 100644 index 68146542..00000000 --- a/lib/src/model/filter.dart +++ /dev/null @@ -1,219 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -enum EventFormat { client, federation } - -class Filter { - RoomFilter room; - EventFilter presence; - EventFilter accountData; - EventFormat eventFormat; - List eventFields; - - Filter({ - this.room, - this.presence, - this.accountData, - this.eventFormat, - this.eventFields, - }); - - Filter.fromJson(Map json) - : room = json['room'] != null ? RoomFilter.fromJson(json['room']) : null, - presence = json['presence'] != null - ? EventFilter.fromJson(json['presence']) - : null, - accountData = json['account_data'] != null - ? EventFilter.fromJson(json['account_data']) - : null, - eventFormat = json['event_format'] != null - ? EventFormat.values.firstWhere( - (e) => e.toString().split('.').last == json['event_format']) - : null, - eventFields = json['event_fields'] != null - ? json['event_fields'].cast() - : null; - - Map toJson() { - final data = {}; - if (room != null) { - data['room'] = room.toJson(); - } - if (presence != null) { - data['presence'] = presence.toJson(); - } - if (eventFormat != null) { - data['event_format'] = eventFormat.toString().split('.').last; - } - if (eventFields != null) { - data['event_fields'] = eventFields; - } - if (accountData != null) { - data['account_data'] = accountData.toJson(); - } - return data; - } -} - -class RoomFilter { - List notRooms; - List rooms; - StateFilter ephemeral; - bool includeLeave; - StateFilter state; - StateFilter timeline; - StateFilter accountData; - - RoomFilter({ - this.notRooms, - this.rooms, - this.ephemeral, - this.includeLeave, - this.state, - this.timeline, - this.accountData, - }); - - RoomFilter.fromJson(Map json) { - notRooms = json['not_rooms']?.cast(); - rooms = json['rooms']?.cast(); - state = json['state'] != null ? StateFilter.fromJson(json['state']) : null; - includeLeave = json['include_leave']; - timeline = json['timeline'] != null - ? StateFilter.fromJson(json['timeline']) - : null; - ephemeral = json['ephemeral'] != null - ? StateFilter.fromJson(json['ephemeral']) - : null; - accountData = json['account_data'] != null - ? StateFilter.fromJson(json['account_data']) - : null; - } - - Map toJson() { - final data = {}; - if (notRooms != null) { - data['not_rooms'] = notRooms; - } - if (rooms != null) { - data['rooms'] = rooms; - } - if (ephemeral != null) { - data['ephemeral'] = ephemeral.toJson(); - } - if (includeLeave != null) { - data['include_leave'] = includeLeave; - } - if (state != null) { - data['state'] = state.toJson(); - } - if (timeline != null) { - data['timeline'] = timeline.toJson(); - } - if (accountData != null) { - data['account_data'] = accountData.toJson(); - } - return data; - } -} - -class EventFilter { - int limit; - List senders; - List types; - List notRooms; - List notSenders; - - EventFilter( - {this.limit, this.senders, this.types, this.notRooms, this.notSenders}); - - EventFilter.fromJson(Map json) { - limit = json['limit']; - types = json['senders']?.cast(); - types = json['types']?.cast(); - notRooms = json['not_rooms']?.cast(); - notSenders = json['not_senders']?.cast(); - } - - Map toJson() { - final data = {}; - if (limit != null) data['limit'] = limit; - if (types != null) data['types'] = types; - if (notRooms != null) data['not_rooms'] = notRooms; - if (notSenders != null) data['not_senders'] = notSenders; - return data; - } -} - -class StateFilter extends EventFilter { - List notTypes; - bool lazyLoadMembers; - bool includeRedundantMembers; - bool containsUrl; - - StateFilter({ - this.notTypes, - this.lazyLoadMembers, - this.includeRedundantMembers, - this.containsUrl, - int limit, - List senders, - List types, - List notRooms, - List notSenders, - }) : super( - limit: limit, - senders: senders, - types: types, - notRooms: notRooms, - notSenders: notSenders, - ); - - StateFilter.fromJson(Map json) : super.fromJson(json) { - notTypes = json['not_types']?.cast(); - lazyLoadMembers = json['lazy_load_members']; - includeRedundantMembers = json['include_redundant_members']; - containsUrl = json['contains_url']; - } - - @override - Map toJson() { - final data = super.toJson(); - if (limit != null) { - data['limit'] = limit; - } - if (notTypes != null) { - data['not_types'] = notTypes; - } - if (lazyLoadMembers != null) { - data['lazy_load_members'] = lazyLoadMembers; - } - if (includeRedundantMembers != null) { - data['include_redundant_members'] = includeRedundantMembers; - } - if (containsUrl != null) { - data['contains_url'] = containsUrl; - } - return data; - } -} diff --git a/lib/src/model/keys_query_response.dart b/lib/src/model/keys_query_response.dart deleted file mode 100644 index ccbc80ff..00000000 --- a/lib/src/model/keys_query_response.dart +++ /dev/null @@ -1,118 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -import 'matrix_keys.dart'; -import '../utils/map_copy_extension.dart'; - -class KeysQueryResponse { - Map failures; - Map> deviceKeys; - Map masterKeys; - Map selfSigningKeys; - Map userSigningKeys; - - KeysQueryResponse.fromJson(Map json) - : failures = (json['failures'] as Map)?.copy(), - deviceKeys = json['device_keys'] != null - ? (json['device_keys'] as Map).map( - (k, v) => MapEntry( - k, - (v as Map).map( - (k, v) => MapEntry( - k, - MatrixDeviceKeys.fromJson(v), - ), - ), - ), - ) - : null, - masterKeys = json['master_keys'] != null - ? (json['master_keys'] as Map).map( - (k, v) => MapEntry( - k, - MatrixCrossSigningKey.fromJson(v), - ), - ) - : null, - selfSigningKeys = json['self_signing_keys'] != null - ? (json['self_signing_keys'] as Map).map( - (k, v) => MapEntry( - k, - MatrixCrossSigningKey.fromJson(v), - ), - ) - : null, - userSigningKeys = json['user_signing_keys'] != null - ? (json['user_signing_keys'] as Map).map( - (k, v) => MapEntry( - k, - MatrixCrossSigningKey.fromJson(v), - ), - ) - : null; - - Map toJson() { - final data = {}; - if (failures != null) { - data['failures'] = failures; - } - if (deviceKeys != null) { - data['device_keys'] = deviceKeys.map( - (k, v) => MapEntry( - k, - v.map( - (k, v) => MapEntry( - k, - v.toJson(), - ), - ), - ), - ); - } - if (masterKeys != null) { - data['master_keys'] = masterKeys.map( - (k, v) => MapEntry( - k, - v.toJson(), - ), - ); - } - if (selfSigningKeys != null) { - data['self_signing_keys'] = selfSigningKeys.map( - (k, v) => MapEntry( - k, - v.toJson(), - ), - ); - } - if (userSigningKeys != null) { - data['user_signing_keys'] = userSigningKeys.map( - (k, v) => MapEntry( - k, - v.toJson(), - ), - ); - } - return data; - } -} diff --git a/lib/src/model/login_response.dart b/lib/src/model/login_response.dart deleted file mode 100644 index 625739e7..00000000 --- a/lib/src/model/login_response.dart +++ /dev/null @@ -1,50 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -import 'well_known_information.dart'; - -class LoginResponse { - String userId; - String accessToken; - String deviceId; - WellKnownInformation wellKnownInformation; - - LoginResponse.fromJson(Map json) - : userId = json['user_id'], - accessToken = json['access_token'], - deviceId = json['device_id'], - wellKnownInformation = (json['well_known'] is Map) - ? WellKnownInformation.fromJson(json['well_known']) - : null; - - Map toJson() { - final data = {}; - if (userId != null) data['user_id'] = userId; - if (accessToken != null) data['access_token'] = accessToken; - if (deviceId != null) data['device_id'] = deviceId; - if (wellKnownInformation != null) { - data['well_known'] = wellKnownInformation.toJson(); - } - return data; - } -} diff --git a/lib/src/model/login_types.dart b/lib/src/model/login_types.dart deleted file mode 100644 index de8dca7f..00000000 --- a/lib/src/model/login_types.dart +++ /dev/null @@ -1,54 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -class LoginTypes { - List flows; - - LoginTypes.fromJson(Map json) { - if (json['flows'] != null) { - flows = (json['flows'] as List).map((v) => Flows.fromJson(v)).toList(); - } - } - - Map toJson() { - final data = {}; - if (flows != null) { - data['flows'] = flows.map((v) => v.toJson()).toList(); - } - return data; - } -} - -class Flows { - String type; - - Flows.fromJson(Map json) { - type = json['type']; - } - - Map toJson() { - final data = {}; - data['type'] = type; - return data; - } -} diff --git a/lib/src/model/matrix_connection_exception.dart b/lib/src/model/matrix_connection_exception.dart index a7046525..d9cfb113 100644 --- a/lib/src/model/matrix_connection_exception.dart +++ b/lib/src/model/matrix_connection_exception.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/matrix_event.dart b/lib/src/model/matrix_event.dart index c45e2615..a2aba791 100644 --- a/lib/src/model/matrix_event.dart +++ b/lib/src/model/matrix_event.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/matrix_exception.dart b/lib/src/model/matrix_exception.dart index 1e1b3bf4..4365d4ef 100644 --- a/lib/src/model/matrix_exception.dart +++ b/lib/src/model/matrix_exception.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/matrix_keys.dart b/lib/src/model/matrix_keys.dart index 44ebbc8e..9f179480 100644 --- a/lib/src/model/matrix_keys.dart +++ b/lib/src/model/matrix_keys.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/message_types.dart b/lib/src/model/message_types.dart index d6745350..0a9b240c 100644 --- a/lib/src/model/message_types.dart +++ b/lib/src/model/message_types.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/notifications_query_response.dart b/lib/src/model/notifications_query_response.dart deleted file mode 100644 index 83e0d767..00000000 --- a/lib/src/model/notifications_query_response.dart +++ /dev/null @@ -1,75 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -import 'matrix_event.dart'; - -class NotificationsQueryResponse { - String nextToken; - List notifications; - - NotificationsQueryResponse.fromJson(Map json) - : nextToken = json['next_token'], - notifications = (json['notifications'] as List) - .map((v) => Notification.fromJson(v)) - .toList(); - - Map toJson() { - final data = {}; - if (nextToken != null) { - data['next_token'] = nextToken; - } - data['notifications'] = notifications.map((v) => v.toJson()).toList(); - return data; - } -} - -class Notification { - List actions; - String profileTag; - bool read; - String roomId; - int ts; - MatrixEvent event; - - Notification.fromJson(Map json) { - actions = json['actions'].cast(); - profileTag = json['profile_tag']; - read = json['read']; - roomId = json['room_id']; - ts = json['ts']; - event = MatrixEvent.fromJson(json['event']); - } - - Map toJson() { - final data = {}; - data['actions'] = actions; - if (profileTag != null) { - data['profile_tag'] = profileTag; - } - data['read'] = read; - data['room_id'] = roomId; - data['ts'] = ts; - data['event'] = event.toJson(); - return data; - } -} diff --git a/lib/src/model/one_time_keys_claim_response.dart b/lib/src/model/one_time_keys_claim_response.dart deleted file mode 100644 index 525d2c9c..00000000 --- a/lib/src/model/one_time_keys_claim_response.dart +++ /dev/null @@ -1,46 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -import '../utils/map_copy_extension.dart'; - -class OneTimeKeysClaimResponse { - Map failures; - Map> oneTimeKeys; - - OneTimeKeysClaimResponse.fromJson(Map json) - : failures = (json['failures'] as Map)?.copy() ?? {}, - // We still need a Map<...>.from(...) to ensure all second-level entries are also maps - oneTimeKeys = Map>.from( - (json['one_time_keys'] as Map).copy()); - - Map toJson() { - final data = {}; - if (failures != null) { - data['failures'] = failures; - } - if (oneTimeKeys != null) { - data['one_time_keys'] = oneTimeKeys; - } - return data; - } -} diff --git a/lib/src/model/open_graph_data.dart b/lib/src/model/open_graph_data.dart deleted file mode 100644 index 48a8b1f4..00000000 --- a/lib/src/model/open_graph_data.dart +++ /dev/null @@ -1,67 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -class OpenGraphData { - String ogTitle; - String ogDescription; - String ogImage; - String ogImageType; - int ogImageHeight; - int ogImageWidth; - int matrixImageSize; - - OpenGraphData.fromJson(Map json) - : ogTitle = json['og:title'], - ogDescription = json['og:description'], - ogImage = json['og:image'], - ogImageType = json['og:image:type'], - ogImageHeight = json['og:image:height'], - ogImageWidth = json['og:image:width'], - matrixImageSize = json['matrix:image:size']; - - Map toJson() { - final data = {}; - if (ogTitle != null) { - data['og:title'] = ogTitle; - } - if (ogDescription != null) { - data['og:description'] = ogDescription; - } - if (ogImage != null) { - data['og:image'] = ogImage; - } - if (ogImageType != null) { - data['og:image:type'] = ogImageType; - } - if (ogImageHeight != null) { - data['og:image:height'] = ogImageHeight; - } - if (ogImageWidth != null) { - data['og:image:width'] = ogImageWidth; - } - if (matrixImageSize != null) { - data['matrix:image:size'] = matrixImageSize; - } - return data; - } -} diff --git a/lib/src/model/open_id_credentials.dart b/lib/src/model/open_id_credentials.dart deleted file mode 100644 index e398ffa3..00000000 --- a/lib/src/model/open_id_credentials.dart +++ /dev/null @@ -1,44 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -class OpenIdCredentials { - String accessToken; - String tokenType; - String matrixServerName; - double expiresIn; - - OpenIdCredentials.fromJson(Map json) - : accessToken = json['access_token'], - tokenType = json['token_type'], - matrixServerName = json['matrix_server_name'], - expiresIn = json['expires_in']; - - Map toJson() { - final data = {}; - data['access_token'] = accessToken; - data['token_type'] = tokenType; - data['matrix_server_name'] = matrixServerName; - data['expires_in'] = expiresIn; - return data; - } -} diff --git a/lib/src/model/presence.dart b/lib/src/model/presence.dart index 73848c2e..c5091d5c 100644 --- a/lib/src/model/presence.dart +++ b/lib/src/model/presence.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/presence_content.dart b/lib/src/model/presence_content.dart index 597082f3..b7bab947 100644 --- a/lib/src/model/presence_content.dart +++ b/lib/src/model/presence_content.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH @@ -21,7 +22,7 @@ * SOFTWARE. */ -enum PresenceType { online, offline, unavailable } +import '../generated/model.dart'; class PresenceContent { PresenceType presence; diff --git a/lib/src/model/profile.dart b/lib/src/model/profile.dart deleted file mode 100644 index 79c6a38e..00000000 --- a/lib/src/model/profile.dart +++ /dev/null @@ -1,49 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -class Profile { - /// The user's avatar URL if they have set one, otherwise null. - Uri avatarUrl; - - /// The user's display name if they have set one, otherwise null. - String displayname; - - /// The matrix ID of this user. May be omitted. - String userId; - - Map additionalContent; - - Profile(this.displayname, this.avatarUrl, - {this.additionalContent = const {}}); - - Profile.fromJson(Map json) - : avatarUrl = - json['avatar_url'] != null ? Uri.parse(json['avatar_url']) : null, - displayname = json['display_name'] ?? json['displayname'], - userId = json['user_id'], - additionalContent = json; - - Map toJson() { - return additionalContent; - } -} diff --git a/lib/src/model/public_rooms_response.dart b/lib/src/model/public_rooms_response.dart deleted file mode 100644 index 7fdfabdd..00000000 --- a/lib/src/model/public_rooms_response.dart +++ /dev/null @@ -1,98 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -class PublicRoomsResponse { - List chunk; - String nextBatch; - String prevBatch; - int totalRoomCountEstimate; - - PublicRoomsResponse.fromJson(Map json) - : chunk = - (json['chunk'] as List).map((v) => PublicRoom.fromJson(v)).toList(), - nextBatch = json['next_batch'], - prevBatch = json['prev_batch'], - totalRoomCountEstimate = json['total_room_count_estimate']; - - Map toJson() { - final data = {}; - data['chunk'] = chunk.map((v) => v.toJson()).toList(); - if (nextBatch != null) { - data['next_batch'] = nextBatch; - } - if (prevBatch != null) { - data['prev_batch'] = prevBatch; - } - if (totalRoomCountEstimate != null) { - data['total_room_count_estimate'] = totalRoomCountEstimate; - } - return data; - } -} - -class PublicRoom { - List aliases; - String avatarUrl; - bool guestCanJoin; - String name; - int numJoinedMembers; - String roomId; - String topic; - bool worldReadable; - String canonicalAlias; - - PublicRoom.fromJson(Map json) - : aliases = json['aliases']?.cast(), - avatarUrl = json['avatar_url'], - guestCanJoin = json['guest_can_join'], - canonicalAlias = json['canonical_alias'], - name = json['name'], - numJoinedMembers = json['num_joined_members'], - roomId = json['room_id'], - topic = json['topic'], - worldReadable = json['world_readable']; - - Map toJson() { - final data = {}; - if (aliases != null) { - data['aliases'] = aliases; - } - if (canonicalAlias != null) { - data['canonical_alias'] = canonicalAlias; - } - if (avatarUrl != null) { - data['avatar_url'] = avatarUrl; - } - data['guest_can_join'] = guestCanJoin; - if (name != null) { - data['name'] = name; - } - data['num_joined_members'] = numJoinedMembers; - data['room_id'] = roomId; - if (topic != null) { - data['topic'] = topic; - } - data['world_readable'] = worldReadable; - return data; - } -} diff --git a/lib/src/model/push_rule_set.dart b/lib/src/model/push_rule_set.dart deleted file mode 100644 index 0055e5ad..00000000 --- a/lib/src/model/push_rule_set.dart +++ /dev/null @@ -1,148 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -enum PushRuleKind { content, override, room, sender, underride } -enum PushRuleAction { notify, dont_notify, coalesce, set_tweak } - -class PushRuleSet { - List content; - List override; - List room; - List sender; - List underride; - - PushRuleSet.fromJson(Map json) { - if (json['content'] != null) { - content = - (json['content'] as List).map((i) => PushRule.fromJson(i)).toList(); - } - if (json['override'] != null) { - override = - (json['override'] as List).map((i) => PushRule.fromJson(i)).toList(); - } - if (json['room'] != null) { - room = (json['room'] as List).map((i) => PushRule.fromJson(i)).toList(); - } - if (json['sender'] != null) { - sender = - (json['sender'] as List).map((i) => PushRule.fromJson(i)).toList(); - } - if (json['underride'] != null) { - underride = - (json['underride'] as List).map((i) => PushRule.fromJson(i)).toList(); - } - } - - Map toJson() { - final data = {}; - if (content != null) { - data['content'] = content.map((v) => v.toJson()).toList(); - } - if (override != null) { - data['override'] = override.map((v) => v.toJson()).toList(); - } - if (room != null) { - data['room'] = room.map((v) => v.toJson()).toList(); - } - if (sender != null) { - data['sender'] = sender.map((v) => v.toJson()).toList(); - } - if (underride != null) { - data['underride'] = underride.map((v) => v.toJson()).toList(); - } - return data; - } -} - -class PushRule { - List actions; - List conditions; - bool isDefault; - bool enabled; - String pattern; - String ruleId; - - PushRule.fromJson(Map json) { - actions = json['actions']; - isDefault = json['default']; - enabled = json['enabled']; - pattern = json['pattern']; - ruleId = json['rule_id']; - conditions = json['conditions'] != null - ? (json['conditions'] as List) - .map((i) => PushConditions.fromJson(i)) - .toList() - : null; - } - - Map toJson() { - final data = {}; - data['actions'] = actions; - data['default'] = isDefault; - data['enabled'] = enabled; - if (pattern != null) { - data['pattern'] = pattern; - } - if (conditions != null) { - data['conditions'] = conditions.map((i) => i.toJson()).toList(); - } - data['rule_id'] = ruleId; - return data; - } -} - -class PushConditions { - String key; - String kind; - String pattern; - String isOperator; - - PushConditions( - this.kind, { - this.key, - this.pattern, - this.isOperator, - }); - - PushConditions.fromJson(Map json) { - key = json['key']; - kind = json['kind']; - pattern = json['pattern']; - isOperator = json['is']; - } - - Map toJson() { - final data = {}; - if (key != null) { - data['key'] = key; - } - data['kind'] = kind; - if (pattern != null) { - data['pattern'] = pattern; - } - if (isOperator != null) { - data['is'] = isOperator; - } - return data; - } -} diff --git a/lib/src/model/pusher.dart b/lib/src/model/pusher.dart deleted file mode 100644 index 08d36577..00000000 --- a/lib/src/model/pusher.dart +++ /dev/null @@ -1,94 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -class Pusher { - String pushkey; - String kind; - String appId; - String appDisplayName; - String deviceDisplayName; - String profileTag; - String lang; - PusherData data; - - Pusher( - this.pushkey, - this.appId, - this.appDisplayName, - this.deviceDisplayName, - this.lang, - this.data, { - this.profileTag, - this.kind, - }); - - Pusher.fromJson(Map json) - : pushkey = json['pushkey'], - kind = json['kind'], - appId = json['app_id'], - appDisplayName = json['app_display_name'], - deviceDisplayName = json['device_display_name'], - profileTag = json['profile_tag'], - lang = json['lang'], - data = PusherData.fromJson(json['data']); - - Map toJson() { - final data = {}; - data['pushkey'] = pushkey; - data['kind'] = kind; - data['app_id'] = appId; - data['app_display_name'] = appDisplayName; - data['device_display_name'] = deviceDisplayName; - if (profileTag != null) { - data['profile_tag'] = profileTag; - } - data['lang'] = lang; - data['data'] = this.data.toJson(); - return data; - } -} - -class PusherData { - Uri url; - String format; - - PusherData({ - this.url, - this.format, - }); - - PusherData.fromJson(Map json) - : format = json['format'], - url = json.containsKey('url') ? Uri.parse(json['url']) : null; - - Map toJson() { - final data = {}; - if (url != null) { - data['url'] = url.toString(); - } - if (format != null) { - data['format'] = format; - } - return data; - } -} diff --git a/lib/src/model/request_token_response.dart b/lib/src/model/request_token_response.dart index e2001826..00dd1e68 100644 --- a/lib/src/model/request_token_response.dart +++ b/lib/src/model/request_token_response.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/room_alias_information.dart b/lib/src/model/room_alias_information.dart deleted file mode 100644 index 050b6b2c..00000000 --- a/lib/src/model/room_alias_information.dart +++ /dev/null @@ -1,38 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -class RoomAliasInformation { - String roomId; - List servers; - - RoomAliasInformation.fromJson(Map json) - : roomId = json['room_id'], - servers = json['servers'].cast(); - - Map toJson() { - final data = {}; - data['room_id'] = roomId; - data['servers'] = servers; - return data; - } -} diff --git a/lib/src/model/room_creation_types.dart b/lib/src/model/room_creation_types.dart index 703f0ce1..fb41cb6c 100644 --- a/lib/src/model/room_creation_types.dart +++ b/lib/src/model/room_creation_types.dart @@ -1,3 +1,4 @@ +// @dart=2.9 abstract class RoomCreationTypes { static const String mSpace = 'm.space'; } diff --git a/lib/src/model/room_keys_info.dart b/lib/src/model/room_keys_info.dart deleted file mode 100644 index c300b298..00000000 --- a/lib/src/model/room_keys_info.dart +++ /dev/null @@ -1,73 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -import '../../matrix_api_lite.dart'; - -enum RoomKeysAlgorithmType { v1Curve25519AesSha2 } - -extension RoomKeysAlgorithmTypeExtension on RoomKeysAlgorithmType { - String get algorithmString { - switch (this) { - case RoomKeysAlgorithmType.v1Curve25519AesSha2: - return AlgorithmTypes.megolmBackupV1Curve25519AesSha2; - default: - return null; - } - } - - static RoomKeysAlgorithmType fromAlgorithmString(String s) { - switch (s) { - case AlgorithmTypes.megolmBackupV1Curve25519AesSha2: - return RoomKeysAlgorithmType.v1Curve25519AesSha2; - default: - return null; - } - } -} - -class RoomKeysVersionResponse { - RoomKeysAlgorithmType algorithm; - Map authData; - int count; - String etag; - String version; - - RoomKeysVersionResponse.fromJson(Map json) - : algorithm = RoomKeysAlgorithmTypeExtension.fromAlgorithmString( - json['algorithm']), - authData = json['auth_data'], - count = json['count'], - etag = json['etag'] - .toString(), // synapse replies an int but docs say string? - version = json['version']; - - Map toJson() { - final data = {}; - data['algorithm'] = algorithm?.algorithmString; - data['auth_data'] = authData; - data['count'] = count; - data['etag'] = etag; - data['version'] = version; - return data; - } -} diff --git a/lib/src/model/room_keys_keys.dart b/lib/src/model/room_keys_keys.dart index 54c2f102..0e8122ba 100644 --- a/lib/src/model/room_keys_keys.dart +++ b/lib/src/model/room_keys_keys.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH @@ -67,24 +68,6 @@ class RoomKeysRoom { } } -class RoomKeys { - Map rooms; - - RoomKeys({this.rooms}) { - rooms ??= {}; - } - - RoomKeys.fromJson(Map json) - : rooms = (json['rooms'] as Map) - .map((k, v) => MapEntry(k, RoomKeysRoom.fromJson(v))); - - Map toJson() { - final data = {}; - data['rooms'] = rooms.map((k, v) => MapEntry(k, v.toJson())); - return data; - } -} - class RoomKeysUpdateResponse { String etag; int count; diff --git a/lib/src/model/room_summary.dart b/lib/src/model/room_summary.dart index 664cd229..24a9d444 100644 --- a/lib/src/model/room_summary.dart +++ b/lib/src/model/room_summary.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/room_types.dart b/lib/src/model/room_types.dart index ba551ae9..6a84114f 100644 --- a/lib/src/model/room_types.dart +++ b/lib/src/model/room_types.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/server_capabilities.dart b/lib/src/model/server_capabilities.dart deleted file mode 100644 index b7053f84..00000000 --- a/lib/src/model/server_capabilities.dart +++ /dev/null @@ -1,95 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -import '../utils/map_copy_extension.dart'; - -enum RoomVersionStability { stable, unstable } - -class ServerCapabilities { - MChangePassword mChangePassword; - MRoomVersions mRoomVersions; - Map customCapabilities; - - ServerCapabilities.fromJson(Map json) - : mChangePassword = json['m.change_password'] != null - ? MChangePassword.fromJson(json['m.change_password']) - : null, - mRoomVersions = json['m.room_versions'] != null - ? MRoomVersions.fromJson(json['m.room_versions']) - : null, - customCapabilities = json.copy() - ..remove('m.change_password') - ..remove('m.room_versions'); - - Map toJson() { - final data = {}; - if (mChangePassword != null) { - data['m.change_password'] = mChangePassword.toJson(); - } - if (mRoomVersions != null) { - data['m.room_versions'] = mRoomVersions.toJson(); - } - for (final entry in customCapabilities.entries) { - data[entry.key] = entry.value; - } - return data; - } -} - -class MChangePassword { - bool enabled; - - MChangePassword.fromJson(Map json) { - enabled = json['enabled']; - } - - Map toJson() { - final data = {}; - data['enabled'] = enabled; - return data; - } -} - -class MRoomVersions { - String defaultVersion; - Map available; - - MRoomVersions.fromJson(Map json) { - defaultVersion = json['default']; - available = (json['available'] as Map).map( - (k, v) => MapEntry( - k, - RoomVersionStability.values - .firstWhere((r) => r.toString().split('.').last == v), - ), - ); - } - - Map toJson() { - final data = {}; - data['default'] = defaultVersion; - data['available'] = available.map( - (k, v) => MapEntry(k, v.toString().split('.').last)); - return data; - } -} diff --git a/lib/src/model/stripped_state_event.dart b/lib/src/model/stripped_state_event.dart index bb8ad374..cf222869 100644 --- a/lib/src/model/stripped_state_event.dart +++ b/lib/src/model/stripped_state_event.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/supported_protocol.dart b/lib/src/model/supported_protocol.dart index b9e4ad35..5a168f06 100644 --- a/lib/src/model/supported_protocol.dart +++ b/lib/src/model/supported_protocol.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/supported_versions.dart b/lib/src/model/supported_versions.dart deleted file mode 100644 index 42b8bc6b..00000000 --- a/lib/src/model/supported_versions.dart +++ /dev/null @@ -1,41 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -class SupportedVersions { - List versions; - Map unstableFeatures; - - SupportedVersions.fromJson(Map json) - : versions = json['versions'].cast(), - unstableFeatures = - Map.from(json['unstable_features'] ?? {}); - - Map toJson() { - final data = {}; - data['versions'] = versions; - if (unstableFeatures != null) { - data['unstable_features'] = unstableFeatures; - } - return data; - } -} diff --git a/lib/src/model/sync_update.dart b/lib/src/model/sync_update.dart index a847eed5..c4d158a5 100644 --- a/lib/src/model/sync_update.dart +++ b/lib/src/model/sync_update.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/tag.dart b/lib/src/model/tag.dart deleted file mode 100644 index 3329b551..00000000 --- a/lib/src/model/tag.dart +++ /dev/null @@ -1,46 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -class Tag { - double order; - - Tag.fromJson(Map json) - : order = double.tryParse(json['order'].toString()); - - Map toJson() { - final data = {}; - if (order != null) { - data['order'] = order; - } - return data; - } -} - -abstract class TagType { - static const String Favourite = 'm.favourite'; - static const String LowPriority = 'm.lowpriority'; - static const String ServerNotice = 'm.server_notice'; - static bool isValid(String tag) => tag.startsWith('m.') - ? [Favourite, LowPriority, ServerNotice].contains(tag) - : true; -} diff --git a/lib/src/model/third_party_identifier.dart b/lib/src/model/third_party_identifier.dart deleted file mode 100644 index b6ab7b90..00000000 --- a/lib/src/model/third_party_identifier.dart +++ /dev/null @@ -1,47 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -import '../matrix_api.dart'; - -class ThirdPartyIdentifier { - ThirdPartyIdentifierMedium medium; - String address; - int validatedAt; - int addedAt; - - ThirdPartyIdentifier.fromJson(Map json) - : medium = ThirdPartyIdentifierMedium.values - .firstWhere((medium) => describeEnum(medium) == json['medium']), - address = json['address'], - validatedAt = json['validated_at'], - addedAt = json['added_at']; - - Map toJson() { - final data = {}; - data['medium'] = describeEnum(medium); - data['address'] = address; - data['validated_at'] = validatedAt; - data['added_at'] = addedAt; - return data; - } -} diff --git a/lib/src/model/third_party_location.dart b/lib/src/model/third_party_location.dart index a2271f9b..cfcad4d4 100644 --- a/lib/src/model/third_party_location.dart +++ b/lib/src/model/third_party_location.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/third_party_user.dart b/lib/src/model/third_party_user.dart index a4289b2a..65a23dc5 100644 --- a/lib/src/model/third_party_user.dart +++ b/lib/src/model/third_party_user.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/timeline_history_response.dart b/lib/src/model/timeline_history_response.dart deleted file mode 100644 index e9806b89..00000000 --- a/lib/src/model/timeline_history_response.dart +++ /dev/null @@ -1,54 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -import 'matrix_event.dart'; - -class TimelineHistoryResponse { - String start; - String end; - List chunk; - List state; - - TimelineHistoryResponse.fromJson(Map json) - : start = json['start'], - end = json['end'], - chunk = json['chunk'] != null - ? (json['chunk'] as List) - .map((i) => MatrixEvent.fromJson(i)) - .toList() - : null, - state = json['state'] != null - ? (json['state'] as List) - .map((i) => MatrixEvent.fromJson(i)) - .toList() - : null; - - Map toJson() { - final data = {}; - if (start != null) data['start'] = start; - if (end != null) data['end'] = end; - if (chunk != null) data['chunk'] = chunk.map((i) => i.toJson()); - if (state != null) data['state'] = state.map((i) => i.toJson()); - return data; - } -} diff --git a/lib/src/model/turn_server_credentials.dart b/lib/src/model/turn_server_credentials.dart deleted file mode 100644 index 81b36c9e..00000000 --- a/lib/src/model/turn_server_credentials.dart +++ /dev/null @@ -1,44 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -class TurnServerCredentials { - String username; - String password; - List uris; - num ttl; - - TurnServerCredentials.fromJson(Map json) - : username = json['username'], - password = json['password'], - uris = json['uris'].cast(), - ttl = json['ttl']; - - Map toJson() { - final data = {}; - data['username'] = username; - data['password'] = password; - data['uris'] = uris; - data['ttl'] = ttl; - return data; - } -} diff --git a/lib/src/model/upload_key_signatures_response.dart b/lib/src/model/upload_key_signatures_response.dart index b53e01a2..f5b46015 100644 --- a/lib/src/model/upload_key_signatures_response.dart +++ b/lib/src/model/upload_key_signatures_response.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/model/user_search_result.dart b/lib/src/model/user_search_result.dart deleted file mode 100644 index 8da4b82a..00000000 --- a/lib/src/model/user_search_result.dart +++ /dev/null @@ -1,42 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -import 'profile.dart'; - -class UserSearchResult { - List results; - bool limited; - - UserSearchResult.fromJson(Map json) - : results = - (json['results'] as List).map((v) => Profile.fromJson(v)).toList(), - limited = json['limited']; - - Map toJson() { - final data = {}; - data['results'] = results.map((v) => v.toJson()).toList(); - - data['limited'] = limited; - return data; - } -} diff --git a/lib/src/model/well_known_information.dart b/lib/src/model/well_known_information.dart deleted file mode 100644 index dbeb1a84..00000000 --- a/lib/src/model/well_known_information.dart +++ /dev/null @@ -1,73 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -import '../utils/try_get_map_extension.dart'; - -class WellKnownInformation { - MHomeserver mHomeserver; - MHomeserver mIdentityServer; - Map content; - - factory WellKnownInformation.fromJson(Map json) => - WellKnownInformation._fromJson( - json, - json.tryGetMap('m.homeserver'), - json.tryGetMap('m.identity_server')); - - WellKnownInformation._fromJson( - Map json, - Map mHomeserverMap, - Map mIdentityServerMap) - : content = json, - mHomeserver = mHomeserverMap != null - ? MHomeserver.fromJson(mHomeserverMap) - : null, - mIdentityServer = mIdentityServerMap != null - ? MHomeserver.fromJson(mIdentityServerMap) - : null; - - Map toJson() { - final data = content; - if (mHomeserver != null) { - data['m.homeserver'] = mHomeserver.toJson(); - } - if (mIdentityServer != null) { - data['m.identity_server'] = mIdentityServer.toJson(); - } - return data; - } -} - -class MHomeserver { - String baseUrl; - - MHomeserver.fromJson(Map json) { - baseUrl = json.tryGet('base_url'); - } - - Map toJson() { - final data = {}; - if (baseUrl != null) data['base_url'] = baseUrl; - return data; - } -} diff --git a/lib/src/model/who_is_info.dart b/lib/src/model/who_is_info.dart deleted file mode 100644 index 3d47930c..00000000 --- a/lib/src/model/who_is_info.dart +++ /dev/null @@ -1,108 +0,0 @@ -/* MIT License -* -* Copyright (C) 2019, 2020, 2021 Famedly GmbH -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in all -* copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - -class WhoIsInfo { - String userId; - Map devices; - - WhoIsInfo.fromJson(Map json) - : userId = json['user_id'], - devices = json['devices'] != null - ? (json['devices'] as Map) - .map((k, v) => MapEntry(k, DeviceInfo.fromJson(v))) - : null; - - Map toJson() { - final data = {}; - data['user_id'] = userId; - if (devices != null) { - data['devices'] = devices.map((k, v) => MapEntry(k, v.toJson())); - } - return data; - } -} - -class DeviceInfo { - List sessions; - - DeviceInfo.fromJson(Map json) { - if (json['sessions'] != null) { - sessions = - (json['sessions'] as List).map((v) => Sessions.fromJson(v)).toList(); - } - } - - Map toJson() { - final data = {}; - if (sessions != null) { - data['sessions'] = sessions.map((v) => v.toJson()).toList(); - } - return data; - } -} - -class Sessions { - List connections; - - Sessions.fromJson(Map json) { - if (json['connections'] != null) { - connections = (json['connections'] as List) - .map((v) => Connections.fromJson(v)) - .toList(); - } - } - - Map toJson() { - final data = {}; - if (connections != null) { - data['connections'] = connections.map((v) => v.toJson()).toList(); - } - return data; - } -} - -class Connections { - String ip; - int lastSeen; - String userAgent; - - Connections.fromJson(Map json) { - ip = json['ip']; - lastSeen = json['last_seen']; - userAgent = json['user_agent']; - } - - Map toJson() { - final data = {}; - if (ip != null) { - data['ip'] = ip; - } - if (lastSeen != null) { - data['last_seen'] = lastSeen; - } - if (userAgent != null) { - data['user_agent'] = userAgent; - } - return data; - } -} diff --git a/lib/src/utils/logs.dart b/lib/src/utils/logs.dart index 298e1985..b9179146 100644 --- a/lib/src/utils/logs.dart +++ b/lib/src/utils/logs.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/utils/map_copy_extension.dart b/lib/src/utils/map_copy_extension.dart index 2cf95989..be21bf01 100644 --- a/lib/src/utils/map_copy_extension.dart +++ b/lib/src/utils/map_copy_extension.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/utils/try_get_map_extension.dart b/lib/src/utils/try_get_map_extension.dart index 850a3a45..b9ab614c 100644 --- a/lib/src/utils/try_get_map_extension.dart +++ b/lib/src/utils/try_get_map_extension.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/lib/src/values.dart b/lib/src/values.dart new file mode 100644 index 00000000..b7f1c0c5 --- /dev/null +++ b/lib/src/values.dart @@ -0,0 +1,20 @@ +// OpenAPI only supports real enums (modeled as enum in generated/model.dart). + +// In this file, possible values are defined manually, +// for cases where other values are allowed too. + +class PushRuleAction { + static final notify = 'notify'; + static final dontNotify = 'dont_notify'; + static final coalesce = 'coalesce'; + static final setTweak = 'set_tweak'; +} + +class TagType { + static final favourite = 'm.favourite'; + static final lowPriority = 'm.lowpriority'; + static final serverNotice = 'm.server_notice'; + static bool isValid(String tag) => tag.startsWith('m.') + ? [favourite, lowPriority, serverNotice].contains(tag) + : true; +} diff --git a/pubspec.yaml b/pubspec.yaml index 828a9cbf..ce5eddc1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ version: 0.3.3 homepage: https://famedly.com environment: - sdk: ">=2.10.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" dependencies: http: ^0.13.0 diff --git a/test/event_content_test.dart b/test/event_content_test.dart index a9969989..750f7581 100644 --- a/test/event_content_test.dart +++ b/test/event_content_test.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/test/map_copy_extension_test.dart b/test/map_copy_extension_test.dart index 329771d9..442aaa62 100644 --- a/test/map_copy_extension_test.dart +++ b/test/map_copy_extension_test.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH diff --git a/test/matrix_api_test.dart b/test/matrix_api_test.dart index e58464a6..45eaf147 100644 --- a/test/matrix_api_test.dart +++ b/test/matrix_api_test.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH @@ -132,7 +133,7 @@ void main() { matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting'); final wellKnownInformation = await matrixApi.getWellknown(); expect(wellKnownInformation.mHomeserver.baseUrl, - 'https://fakeserver.notexisting'); + Uri.parse('https://fakeserver.notexisting')); expect(wellKnownInformation.toJson(), { 'm.homeserver': {'base_url': 'https://fakeserver.notexisting'}, 'm.identity_server': { @@ -146,14 +147,15 @@ void main() { test('getLoginTypes', () async { matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting'); final loginTypes = await matrixApi.getLoginFlows(); - expect(loginTypes.flows.first.type, 'm.login.password'); + expect(loginTypes.first.type, 'm.login.password'); expect(FakeMatrixApi.api['GET']['/client/r0/login']({}), - loginTypes.toJson()); + {'flows': loginTypes.map((x) => x.toJson()).toList()}); matrixApi.homeserver = null; }); test('login', () async { matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting'); final loginResponse = await matrixApi.login( + LoginType.mLoginPassword, identifier: AuthenticationUserIdentifier(user: 'username'), ); expect(FakeMatrixApi.api['POST']['/client/r0/login']({}), @@ -175,7 +177,7 @@ void main() { test('register', () async { matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting'); final registerResponse = - await matrixApi.register(kind: 'guest', username: 'test'); + await matrixApi.register(kind: AccountKind.guest, username: 'test'); expect(FakeMatrixApi.api['POST']['/client/r0/register?kind=guest']({}), registerResponse.toJson()); matrixApi.homeserver = null; @@ -319,7 +321,7 @@ void main() { final response = await matrixApi.unbind3pidFromAccount( 'alice@example.com', ThirdPartyIdentifierMedium.email, - 'https://example.com', + idServer: 'https://example.com', ); expect(response, IdServerUnbindResult.success); matrixApi.homeserver = matrixApi.accessToken = null; @@ -355,10 +357,10 @@ void main() { matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting'); matrixApi.accessToken = '1234'; final response = await matrixApi.getTokenOwner(); - expect(response, 'alice@example.com'); + expect(response.userId, 'alice@example.com'); matrixApi.homeserver = matrixApi.accessToken = null; }); - test('getServerCapabilities', () async { + test('getCapabilities', () async { matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting'); matrixApi.accessToken = '1234'; final response = await matrixApi.getCapabilities(); @@ -392,7 +394,7 @@ void main() { timeline: StateFilter(), accountData: StateFilter(limit: 10, types: ['type1']), ), - presence: EventFilter( + presence: StateFilter( limit: 10, senders: ['@alice:example.com'], types: ['type1'], @@ -412,6 +414,7 @@ void main() { 'rooms': ['!1234'], 'ephemeral': { 'limit': 10, + 'senders': ['@alice:example.com'], 'types': ['type1'], 'not_rooms': ['!1234'], 'not_senders': ['@bob:example.com'], @@ -430,6 +433,7 @@ void main() { }, 'presence': { 'limit': 10, + 'senders': ['@alice:example.com'], 'types': ['type1'], 'not_rooms': ['!1234'], 'not_senders': ['@bob:example.com'] @@ -573,7 +577,7 @@ void main() { expect( FakeMatrixApi.api['GET'][ - '/client/r0/rooms/!localpart%3Aserver.abc/messages?from=1234&dir=b&to=1234&limit=10&filter=%7B%22lazy_load_members%22%3Atrue%7D']( + '/client/r0/rooms/!localpart%3Aserver.abc/messages?from=1234&to=1234&dir=b&limit=10&filter=%7B%22lazy_load_members%22%3Atrue%7D']( {}) as Map, timelineHistoryResponse.toJson()); @@ -584,7 +588,7 @@ void main() { matrixApi.accessToken = '1234'; final eventId = await matrixApi.setRoomStateWithKey( - '!localpart:server.abc', 'm.room.avatar', {'url': 'mxc://1234'}); + '!localpart:server.abc', 'm.room.avatar', '', {'url': 'mxc://1234'}); expect(eventId, 'YUwRidLecu:example.com'); @@ -634,7 +638,7 @@ void main() { roomVersion: '2', creationContent: {}, initialState: [], - preset: CreateRoomPreset.public_chat, + preset: CreateRoomPreset.publicChat, isDirect: false, powerLevelContentOverride: {}, ); @@ -695,12 +699,11 @@ void main() { matrixApi.homeserver = matrixApi.accessToken = null; }); - test('inviteToRoom', () async { + test('inviteUser', () async { matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting'); matrixApi.accessToken = '1234'; - await matrixApi.inviteToRoom( - '!localpart:example.com', '@bob:example.com'); + await matrixApi.inviteUser('!localpart:example.com', '@bob:example.com'); matrixApi.homeserver = matrixApi.accessToken = null; }); @@ -711,12 +714,14 @@ void main() { final roomId = '!localpart:example.com'; final response = await matrixApi.joinRoomById( roomId, - thirdPidSignedSender: '@bob:example.com', - thirdPidSignedmxid: '@alice:example.com', - thirdPidSignedToken: '1234', - thirdPidSignedSiganture: { - 'example.org': {'ed25519:0': 'some9signature'} - }, + thirdPartySigned: ThirdPartySigned( + sender: '@bob:example.com', + mxid: '@alice:example.com', + token: '1234', + signatures: { + 'example.org': {'ed25519:0': 'some9signature'} + }, + ), ); expect(response, roomId); @@ -729,13 +734,15 @@ void main() { final roomId = '!localpart:example.com'; final response = await matrixApi.joinRoom( roomId, - servers: ['example.com', 'example.abc'], - thirdPidSignedSender: '@bob:example.com', - thirdPidSignedmxid: '@alice:example.com', - thirdPidSignedToken: '1234', - thirdPidSignedSiganture: { - 'example.org': {'ed25519:0': 'some9signature'} - }, + serverName: ['example.com', 'example.abc'], + thirdPartySigned: ThirdPartySigned( + sender: '@bob:example.com', + mxid: '@alice:example.com', + token: '1234', + signatures: { + 'example.org': {'ed25519:0': 'some9signature'} + }, + ), ); expect(response, roomId); @@ -836,7 +843,9 @@ void main() { limit: 10, since: '1234', server: 'example.com', - genericSearchTerm: 'test', + filter: PublicRoomQueryFilter( + genericSearchTerm: 'test', + ), includeAllNetworks: false, thirdPartyInstanceId: 'id', ); @@ -939,7 +948,9 @@ void main() { await matrixApi.postReceipt( '!localpart:example.com', + ReceiptType.mRead, '\$1234:example.com', + {}, ); matrixApi.homeserver = matrixApi.accessToken = null; @@ -951,7 +962,7 @@ void main() { await matrixApi.setReadMarker( '!localpart:example.com', '\$1234:example.com', - readReceiptLocationEventId: '\$1234:example.com', + mRead: '\$1234:example.com', ); matrixApi.homeserver = matrixApi.accessToken = null; @@ -984,12 +995,14 @@ void main() { }); test('upload', () async { matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting'); - final response = await matrixApi.uploadContent(Uint8List(0), 'file.jpeg'); + matrixApi.accessToken = '1234'; + final response = + await matrixApi.uploadContent(Uint8List(0), filename: 'file.jpeg'); expect(response, 'mxc://example.com/AQwafuaFswefuhsfAFAgsw'); var throwsException = false; try { - await matrixApi.uploadContent(Uint8List(0), 'file.jpg'); - } on MatrixException catch (_) { + await matrixApi.uploadContent(Uint8List(0), filename: 'file.jpg'); + } catch (_) { throwsException = true; } expect(throwsException, true); @@ -1010,12 +1023,12 @@ void main() { matrixApi.homeserver = matrixApi.accessToken = null; }); - test('requestMaxUploadSize', () async { + test('getConfig', () async { matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting'); matrixApi.accessToken = '1234'; final response = await matrixApi.getConfig(); - expect(response, 50000000); + expect(response.mUploadSize, 50000000); matrixApi.homeserver = matrixApi.accessToken = null; }); @@ -1243,12 +1256,12 @@ void main() { await matrixApi.postPusher( Pusher( - '1234', - 'app.id', - 'appDisplayName', - 'deviceDisplayName', - 'en', - PusherData( + pushkey: '1234', + appId: 'app.id', + appDisplayName: 'appDisplayName', + deviceDisplayName: 'deviceDisplayName', + lang: 'en', + data: PusherData( format: 'event_id_only', url: Uri.parse('https://matrix.org')), profileTag: 'tag', kind: 'http', @@ -1321,11 +1334,11 @@ void main() { before: '1', after: '2', conditions: [ - PushConditions( - 'event_match', + PushCondition( + kind: 'event_match', key: 'key', pattern: 'pattern', - isOperator: '+', + is$: '+', ) ], pattern: 'pattern', @@ -1374,7 +1387,7 @@ void main() { 'global', PushRuleKind.content, 'nocake', - [PushRuleAction.dont_notify], + [PushRuleAction.dontNotify], ); matrixApi.homeserver = matrixApi.accessToken = null; @@ -1383,7 +1396,7 @@ void main() { matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting'); matrixApi.accessToken = '1234'; - await matrixApi.search({}); + await matrixApi.search(Categories()); matrixApi.homeserver = matrixApi.accessToken = null; }); @@ -1509,7 +1522,7 @@ void main() { limit: 10, filter: '{}'); expect( FakeMatrixApi.api['GET'] - ['/client/r0/rooms/1234/context/1234?filter=%7B%7D&limit=10']({}), + ['/client/r0/rooms/1234/context/1234?limit=10&filter=%7B%7D']({}), response.toJson(), ); @@ -1522,8 +1535,8 @@ void main() { await matrixApi.reportContent( '1234', '1234', - 'test', - -100, + reason: 'test', + score: -100, ); matrixApi.homeserver = matrixApi.accessToken = null; @@ -1606,7 +1619,7 @@ void main() { matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting'); matrixApi.accessToken = '1234'; - final response = await matrixApi.requestOpenIdToken('1234'); + final response = await matrixApi.requestOpenIdToken('1234', {}); expect( FakeMatrixApi.api['POST'] ['/client/r0/user/1234/openid/request_token']({}), @@ -1623,39 +1636,39 @@ void main() { matrixApi.homeserver = matrixApi.accessToken = null; }); - test('createRoomKeysBackup', () async { + test('postRoomKeysVersion', () async { matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting'); matrixApi.accessToken = '1234'; - final algorithm = RoomKeysAlgorithmType.v1Curve25519AesSha2; + final algorithm = BackupAlgorithm.mMegolmBackupV1Curve25519AesSha2; final authData = { 'public_key': 'GXYaxqhNhUK28zUdxOmEsFRguz+PzBsDlTLlF0O0RkM', 'signatures': {}, }; - final ret = await matrixApi.createRoomKeysBackup(algorithm, authData); + final ret = await matrixApi.postRoomKeysVersion(algorithm, authData); expect( FakeMatrixApi.api['POST'] ['/client/unstable/room_keys/version']({})['version'], ret); }); - test('getRoomKeysBackup', () async { + test('getRoomKeysVersionCurrent', () async { matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting'); matrixApi.accessToken = '1234'; - final ret = await matrixApi.getRoomKeysBackup(); + final ret = await matrixApi.getRoomKeysVersionCurrent(); expect(FakeMatrixApi.api['GET']['/client/unstable/room_keys/version']({}), ret.toJson()); }); - test('updateRoomKeysBackup', () async { + test('putRoomKeysVersion', () async { matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting'); matrixApi.accessToken = '1234'; - final algorithm = RoomKeysAlgorithmType.v1Curve25519AesSha2; + final algorithm = BackupAlgorithm.mMegolmBackupV1Curve25519AesSha2; final authData = { 'public_key': 'GXYaxqhNhUK28zUdxOmEsFRguz+PzBsDlTLlF0O0RkM', 'signatures': {}, }; - await matrixApi.updateRoomKeysBackup('5', algorithm, authData); + await matrixApi.putRoomKeysVersion('5', algorithm, authData); }); test('deleteRoomKeysBackup', () async { matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting'); @@ -1663,13 +1676,13 @@ void main() { await matrixApi.deleteRoomKeysBackup('5'); }); - test('storeRoomKeysSingleKey', () async { + test('postRoomKeysKeyRoomIdSessionId', () async { matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting'); matrixApi.accessToken = '1234'; final roomId = '!726s6s6q:example.com'; final sessionId = 'ciM/JWTPrmiWPPZNkRLDPQYf9AW/I46bxyLSr+Bx5oU'; - final session = RoomKeysSingleKey.fromJson({ + final session = KeyBackupData.fromJson({ 'first_message_index': 0, 'forwarded_count': 0, 'is_verified': true, @@ -1680,7 +1693,7 @@ void main() { 'mac': 'QzKV/fgAs4U', }, }); - final ret = await matrixApi.storeRoomKeysSingleKey( + final ret = await matrixApi.postRoomKeysKeyRoomIdSessionId( roomId, sessionId, '5', session); expect( FakeMatrixApi.api['PUT'][ @@ -1712,13 +1725,13 @@ void main() { '/client/unstable/room_keys/keys/${Uri.encodeComponent('!726s6s6q:example.com')}/${Uri.encodeComponent('ciM/JWTPrmiWPPZNkRLDPQYf9AW/I46bxyLSr+Bx5oU')}?version=5']({}), ret.toJson()); }); - test('storeRoomKeysRoom', () async { + test('postRoomKeysKeyRoomId', () async { matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting'); matrixApi.accessToken = '1234'; final roomId = '!726s6s6q:example.com'; final sessionId = 'ciM/JWTPrmiWPPZNkRLDPQYf9AW/I46bxyLSr+Bx5oU'; - final session = RoomKeysRoom.fromJson({ + final session = RoomKeyBackup.fromJson({ 'sessions': { sessionId: { 'first_message_index': 0, @@ -1733,7 +1746,7 @@ void main() { }, }, }); - final ret = await matrixApi.storeRoomKeysRoom(roomId, '5', session); + final ret = await matrixApi.postRoomKeysKeyRoomId(roomId, '5', session); expect( FakeMatrixApi.api['PUT'][ '/client/unstable/room_keys/keys/${Uri.encodeComponent('!726s6s6q:example.com')}?version=5']({}), @@ -1761,7 +1774,7 @@ void main() { '/client/unstable/room_keys/keys/${Uri.encodeComponent('!726s6s6q:example.com')}?version=5']({}), ret.toJson()); }); - test('storeRoomKeys', () async { + test('postRoomKeysKey', () async { matrixApi.homeserver = Uri.parse('https://fakeserver.notexisting'); matrixApi.accessToken = '1234'; @@ -1786,7 +1799,7 @@ void main() { }, }, }); - final ret = await matrixApi.storeRoomKeys('5', session); + final ret = await matrixApi.postRoomKeysKey('5', session); expect( FakeMatrixApi.api['PUT'] ['/client/unstable/room_keys/keys?version=5']({}), diff --git a/test/try_get_map_extension_test.dart b/test/try_get_map_extension_test.dart index d38a1e68..dca18807 100644 --- a/test/try_get_map_extension_test.dart +++ b/test/try_get_map_extension_test.dart @@ -1,3 +1,4 @@ +// @dart=2.9 /* MIT License * * Copyright (C) 2019, 2020, 2021 Famedly GmbH