Add 'ruma-client-api/' from commit '632eb9d520028816c5fb7224bd0aca8d1e3793f1'

git-subtree-dir: ruma-client-api
git-subtree-mainline: e5233c49f610f866e3c9bf8529a0613171fc2fe4
git-subtree-split: 632eb9d520028816c5fb7224bd0aca8d1e3793f1
This commit is contained in:
Jonas Platte 2020-06-05 17:11:09 +02:00
commit 6329cd471e
164 changed files with 8429 additions and 0 deletions

View File

@ -0,0 +1,30 @@
image: archlinux
packages:
- rustup
sources:
- https://github.com/ruma/ruma-client-api
tasks:
- rustup: |
# We specify --profile minimal because we'd otherwise download docs
rustup toolchain install beta --profile minimal -c rustfmt -c clippy
rustup default beta
- test: |
cd ruma-client-api
# We don't want the build to stop on individual failure of independent
# tools, so capture tool exit codes and set the task exit code manually
set +e
cargo fmt -- --check
fmt_exit=$?
cargo clippy --all-targets --all-features -- -D warnings
clippy_exit=$?
cargo test --no-default-features --verbose
test1_exit=$?
cargo test --all-features --verbose
test2_exit=$?
exit $(( $fmt_exit || $clippy_exit || $test1_exit || $test2_exit ))

View File

@ -0,0 +1,26 @@
image: archlinux
packages:
- rustup
sources:
- https://github.com/ruma/ruma-client-api
tasks:
- rustup: |
# We specify --profile minimal because we'd otherwise download docs
rustup toolchain install 1.40.0 --profile minimal
rustup default 1.40.0
- test: |
cd ruma-client-api
# We don't want the build to stop on individual failure of independent
# tools, so capture tool exit codes and set the task exit code manually
set +e
# Only make sure the code builds with the MSRV. Tests can require later
# Rust versions, don't compile or run them.
cargo build --no-default-features --verbose
build1_exit=$?
cargo build --all-features --verbose
build2_exit=$?
exit $(( $build1_exit || $build2_exit ))

View File

@ -0,0 +1,32 @@
image: archlinux
packages:
- rustup
sources:
- https://github.com/ruma/ruma-client-api
tasks:
- rustup: |
rustup toolchain install nightly --profile minimal
rustup default nightly
# Try installing rustfmt & clippy for nightly, but don't fail the build
# if they are not available
rustup component add rustfmt || true
rustup component add clippy || true
- test: |
cd ruma-client-api
# We don't want the build to stop on individual failure of independent
# tools, so capture tool exit codes and set the task exit code manually
set +e
if ( rustup component list | grep -q rustfmt ); then
cargo fmt -- --check
fi
fmt_exit=$?
if ( rustup component list | grep -q clippy ); then
cargo clippy --all-targets --all-features -- -D warnings
fi
clippy_exit=$?
exit $(( $fmt_exit || $clippy_exit ))

View File

@ -0,0 +1,32 @@
image: archlinux
packages:
- rustup
sources:
- https://github.com/ruma/ruma-client-api
tasks:
- rustup: |
# We specify --profile minimal because we'd otherwise download docs
rustup toolchain install stable --profile minimal -c rustfmt -c clippy
rustup default stable
- test: |
cd ruma-client-api
# We don't want the build to stop on individual failure of independent
# tools, so capture tool exit codes and set the task exit code manually
set +e
cargo fmt -- --check
fmt_exit=$?
cargo clippy --all-targets --all-features -- -D warnings
clippy_exit=$?
cargo test --no-default-features --verbose
test1_exit=$?
cargo test --all-features --verbose
test2_exit=$?
exit $(( $fmt_exit || $clippy_exit || $test1_exit || $test2_exit ))
# TODO: Add audit task once cargo-audit binary releases are available.
# See https://github.com/RustSec/cargo-audit/issues/66

2
ruma-client-api/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
Cargo.lock
target

View File

@ -0,0 +1,202 @@
# [unreleased]
Breaking changes:
* Make `avatar_url` in `r0::profile::set_avatar_url::Request` an `Option`
* Update type of `canonical_alias` in `r0::directory::PublicRoomsChunk` from
`Option<String>` to `Option<RoomAliasId>`
* Update `r0::room::create_room::CreationContent`
* Change `federated`s type from `Option<bool>` to `bool`
* Add `predecessor` field
* Update `r0::push::get_pushrules_all` and `r0::push::get_pushrules_global_scope` to use the
`Ruleset` type from `ruma_events`
* Fix event types in `r0::context::get_context`
Improvements:
* Add method `into_event_content` for `r0::room::create_room::CreationContent`
* Add room visibility endpoints: `r0::directory::{get_room_visibility, set_room_visibility}`.
Deprecations:
* `r0::sync::sync_events::SetPresence` has been renamed to `PresenceState`. It is still available
under its previous name, but only for one release.
# 0.9.0
Bug fixes:
* Fix (de)serialization for `r0::media::get_content_thumnail::Response`
* Make `r0::device::get_devices::Response::devices` public
Breaking changes:
* The `event_id` in the response for the message and state sending endpoints is now required
* r0.6.0 doesn't say they are required, but this has been fixed for the next version of the spec
* Updated the type of `r0::sync::sync_events::DeviceLists` fields
* Change `r0::device::Device` fields according to the spec
Improvements:
* `r0::keys::AlgorithmAndDeviceId` now implements `Display`
# 0.8.0
Breaking changes:
* Update all endpoints to r0.6.0
* Some of the changes from that might not be listed below, but it should be
easy to figure out what changed from the documentation and compiler errors
if you are using any of the affected endpoints.
* Add `server_name` parameter to `r0::join::join_room_by_id_or_alias`
* Modify `r0::account::AuthenticationData`:
* Rename to `AuthData`
* Change to an enum to facilitate fallback auth acknowledgements
* Add `auth_parameters` field
* Move to `r0::uiaa` module
* Add `room_network` parameter to `r0::directory::get_public_rooms_filtered` to
represent `include_all_networks` and `third_party_instance_id` Matrix fields
* Update `r0::account::register` endpoint:
* Remove `bind_email` request field (removed in r0.6.0)
* Remove `inhibit_login` request field, make `access_token` and `device_id` response fields optional (added in r0.4.0)
* Remove deprecated `home_server` response field (removed in r0.4.0)
* Update `r0::contact::get_contacts` endpoint to r0.6.0
* Change `UInt` timestamps to `SystemTime` in:
* `media::get_media_preview::Request`
* `push::get_notifications::Notification`
* `server::get_user_info::ConnectionInfo`
* `device::Device`
* Change all usages of `HashMap` to `BTreeMap`
* Change the messages type that gets sent out using the `r0::client_exchange::send_event_to_device`
request.
* Add `M_USER_DEACTIVATED` to `error::ErrorKind`
* Make `display_name` field of `r0::membership::joined_events::RoomMember` optional
* Update `r0::search::search_events` to r0.6.0
* Add `account_data` field to `r0::sync::sync_events`
* Rename `r0::client_exchange` to `r0::to_device`
Improvements:
* Add types for User-Interactive Authentication API: `r0::uiaa::{AuthFlow, UiaaInfo, UiaaResponse}`
* Add missing serde attributes to `get_content_thumbnail` query parameters
* Add missing `state` response field to `r0::message::get_message_events`
* Normalize `serde_json` imports
* Remove dependeny on the `url` crate
# 0.7.2
Bug fixes:
* Fix `create_room` requests without an `initial_state` field failing deserialization
* Fix `sync_events` responses without a `device_one_time_keys_count` field failing deserialization
# 0.7.1
Bug fixes:
* Fix deserialization of `sync_events::Request`
* Fix (de)serialization of `sync_events::RoomSummary`
# 0.7.0
Breaking changes:
* Update ruma-api to 0.15.0
* Update ruma-events to 0.18.0
* Fix `r0::session::get_login_types`
* Add `allow_remote` parameter to `r0::media::get_content`
* Add missing parameters for `r0::room::create_room`
* Moved `r0::room::create_room::Invite3pid` to `r0::membership::Invite3pid`
* Replaced `user_id` parameter of `r0::membership::invite_user` with `recipient`
to allow invitation of users by either Matrix or third party identifiers.
* Remove deprecated endpoint `r0::contact::create_contact` (deprecated in r0.6.0)
* Add lazy-loading options to `r0::filter::RoomEventFilter` (introduced in r0.5.0)
* Change type for `limit` request parameter of `r0::context::get_context` from `u8` to `Option<js_int::UInt>`
* Use `std::time::Duration` for appropriate fields on several endpoints:
```
r0::{
account::request_openid_token,
keys::{claim_keys, get_keys},
presence::get_presence,
sync::sync_events,
typing::create_typing_event,
voip::get_turn_server_info
}
```
Improvements:
* Add an `Error` type that represents the well-known errors in the client-server API
* the response deserialization code will try to create an instance of this type from http responses that indicate an error
* Add OpenID token request endpoint.
* Add `r0::client_exchange::send_event_to_device` (introduced in r0.3.0)
* Add endpoints to retrieve account_data (introduced in r0.5.0)
* Add media endpoints: `r0::media::{get_media_config, get_media_preview, get_content_as_filename}`
* Add `unstable_features` to `unversioned::get_supported_versions` (introduced in r0.5.0)
* Add request and response parameters for `r0::account::deactivate`
* Add `r0::session::sso_login` (introduced in r0.5.0)
* Add `filter` type for `r0::context::get_context`
# 0.6.0
Breaking changes:
* Update ruma-api to 0.13.0
* Our Minimum Supported Rust Version is now 1.40.0
* Remove presence list endpoints `r0::presence::{get_subscribed_presences, update_presence_subscriptions}` (removed in r0.5.0)
* Refactor `r0::send` endpoints and remove module:
* Move `r0::send::send_message_event` to `r0::message::create_message_event`
* Move `r0::send::send_state_event_for_empty_key` to `r0::state:create_state_event_for_empty_key`
* Move `r0::send::send_state_event_for_key` to `r0::state:create_state_event_for_key`
* Refactor `r0::sync` endpoints:
* Move `r0::sync::get_member_events` to `r0::membership::get_member_events`
* Move `r0::sync::get_message_events` to `r0::message::get_message_events`
* Move `r0::sync::get_state_events` to `r0::state::get_state_events`
* Move `r0::sync::get_state_events_for_empty_key` to `r0::state::get_state_events_for_empty_key`
* Move `r0::sync::get_state_events_for_key` to `r0::state::get_state_events_for_key`
* Update endpoints for requesting account management tokens via email:
* Move `r0::account::request_password_change_token` to `r0::account::request_password_change_token_via_email`
* Move `r0::account::request_register_token` to `r0::account::request_registration_token_via_email`
* Modify `r0::account::request_registration_token_via_email` not to be rate-limited and require authentication
* Merge duplicate enums `r0::contact::get_contact::Medium` and `r0::session::login::Medium` and move them to `r0::thirdparty`
Improvements:
* Add `r0::device` endpoints
* Add `r0::room::get_room_event` (introduced in r0.4.0)
* Add `r0::read_marker::set_read_marker` (introduced in r0.4.0)
* Add `r0::capabilities::get_capabilities` (introduced in r0.5.0)
* Add `r0::keys` endpoints (introduced in r0.3.0)
* Add `r0::session::get_login_types` (introduced in r0.4.0)
* Add `r0::account::get_username_availability` (introduced in r0.4.0)
* Add endpoints to request management tokens (introduced upstream in r0.4.0):
* `r0::account::request_3pid_management_token_via_msisdn`
* `r0::account::request_password_change_token_via_msisdn`
* `r0::account::request_registration_token_via_msisdn`
* `r0::acount::request_3pid_management_token_via_email`
* Update `r0::presence_get_presence` from r0.4.0 to r0.6.0
* Add `r0::account::bind_3pid`
* Add `r0::account::delete_3pid`
* Add `r0::account::unbind_3pid`
* Add `r0::push` endpoints
* Add `r0::room::upgrade_room` (introduced upstream in r0.5.0)
# 0.5.0
Breaking changes:
* Our Minimum Supported Rust Version is now 1.39.0
* Update ruma-api from 0.11.0 to 0.12.0
* Move `r0::directory::get_public_rooms::PublicRoomsChunk` to `r0::directory::PublicRoomsChunk`
* Move `r0::room::create_room::Visibility` to `r0::room::Visibility`
* Move `r0::account::register::AuthenticationData` to `r0::account::AuthenticationData`
Improvements:
* Update `r0::directory::get_public_rooms` from r0.3.0 to r0.6.0
* Add `r0::directory::get_public_rooms_filtered` (introduced upstream in r0.3.0)
* Add `filter` optional parameter to `r0::sync::get_message_events` (introduced upstream in r0.3.0)
* Add `r0::appservice::set_room_visibility` (part of application service extensions for the client-server API)
* Add `contains_url` to `r0::filter::RoomEventFilter` (introduced upstream in r0.3.0)
* Update `r0::account::change_password` from r0.3.0 to r0.6.0
* Add optional `auth` field

View File

@ -0,0 +1,203 @@
Welcome! Thanks for looking into contributing to our project!
# Table of Contents
- [Looking for Help?](#looking-for-help)
- [Documentation](#documentation)
- [Chat Rooms](#chat-rooms)
- [Reporting Issues](#reporting-issues)
- [Submitting Code](#submitting-code)
- [Coding Style](#coding-style)
- [Modifying Endpoints](#modifying-endpoints)
- [Submitting PRs](#submitting-prs)
- [Where do I start?](#where-do-i-start)
- [Testing](#testing)
- [Contact](#contact)
# Looking for Help?
Here is a list of helpful resources you can consult:
## Documentation
- [Matrix spec Documentation](https://matrix.org/docs/spec/client_server/latest)
- Documentation to other Ruma modules:
- [ruma-events](https://docs.rs/ruma-events/)
- [ruma-api](https://docs.rs/ruma-api/)
- [ruma-client](https://docs.rs/ruma-client/)
## Chat Rooms
- Ruma Matrix room: [#ruma:matrix.org](https://matrix.to/#/#ruma:matrix.org)
- Matrix Developer room: [#matrix-dev:matrix.org](https://matrix.to/#/#matrix-dev:matrix.org)
# Reporting Issues
If you find any bugs, inconsistencies or other problems, feel free to submit
a GitHub [issue](issues).
If you have a quick question, it may be easier to leave a message on
[#ruma:matrix.org](https://matrix.to/#/#ruma:matrix.org).
Also, if you have trouble getting on board, let us know so we can help future
contributors to the project overcome that hurdle too.
# Submitting Code
Ready to write some code? Great! Here are some guidelines to follow to
help you on your way:
## Coding Style
### Common types
When writing endpoint definitions, use the following mapping from request /
response field types listed in the specification to Rust types:
Specification type | Rust type
-------------------|---------------------------------------------------------------------------------------------------------------------
`boolean` | `bool`
`integer` | `js_int::UInt` (unless denoted as signed, then `js_int::Int`)
`string` | If for an identifier (e.g. user ID, room ID), use one of the types from `ruma-identifiers`. Otherwise, use `String`.
`object` | `serde_json::Value`
`[…]` | `Vec<…>`
`{string: …}` | `BTreeMap<String, …>` (or `BTreeMap<SomeId, …>`)
### Import Formatting
Organize your imports into three groups separated by blank lines:
1. `std` imports
1. External imports (from other crates)
1. Local imports (`self::`, `super::`, `crate::` and things like `LocalType::*`)
For example,
```rust
use std::collections::BTreeMap;
use ruma_api::ruma_api;
use super::MyType;
```
Also, group imports by module. For example, do this:
```rust
use std::{
collections::BTreeMap,
convert::TryFrom,
fmt::{self, Debug, Display, Formatter},
};
```
as opposed to:
```rust
use std::collections::BTreeMap;
use std::convert::TryFrom;
use std::fmt::{self, Debug, Display, Formatter};
```
### Serde Imports
When importing methods and types from `serde_json`, methods should be such as
`serde_json::{from,to}_{slice,string,value,vec}` should be imported as
`{from,to}_json_{slice,string,value,vec}`.
For example:
```rust
use serde_json::{
from_value as from_json_value,
to_str as to_json_str,
};
```
Also, `serde_json::Value` should be imported as `JsonValue`.
### Code Formatting and Linting
Use `rustfmt` to format your code and `clippy` to lint your code. Before
committing your changes, go ahead and run `cargo fmt` and `cargo clippy
--all-targets --all-features` on the repository to make sure that the
formatting and linting checks pass in CI. Note that `clippy` warnings are
reported as errors in CI builds, so make sure to handle those before
comitting as well. (To install the tools, run `rustup component add rustfmt
clippy`.)
### Commit Messages
Write commit messages using the imperative mood, as if completing the sentence:
"If applied, this commit will \_\_\_." For example, use "Fix some bug" instead
of "Fixed some bug" or "Add a feature" instead of "Added a feature".
(Take a look at this
[blog post](https://www.freecodecamp.org/news/writing-good-commit-messages-a-practical-guide/)
for more information on writing good commit messages.)
## Modifying Endpoints
### Matrix Spec Version
Use the latest r0.x.x documentation when adding or modifying code. We target
the latest minor version of the Matrix specification. (Note: We might
reconsider this when the Client-Server API hits r1.0.0.)
### Endpoint Documentation Header
Add a comment to the top of each endpoint file that includes the path
and a link to the documentation of the spec. You can use the latest
version at the time of the commit. For example:
```rust
//! [GET /.well-known/matrix/client](https://matrix.org/docs/spec/client_server/r0.4.0#get-well-known-matrix-client)
```
### Naming Endpoints
When adding new endpoints, select the module that fits the purpose of the
endpoint. When naming the endpoint itself, you can use the following
guidelines:
- The name should be a verb describing what the client is requesting, e.g.
`get_some_resource`.
- Endpoints which are basic CRUD operations should use the prefixes
`create`, `get`, `update`, and `delete`.
- The prefix `set` is preferred to create if the resource is a singleton.
In other words, when there's no distinction between `create` and `update`.
- Try to use names that are as descriptive as possible and distinct from
other endpoints in all other modules. (For example, instead of
`r0::room::get_event`, use `r0::room::get_room_event`).
- If you're not sure what to name it, pick any name and we can help you
with it.
### Tracking Changes
Add your changes to the [change log](CHANGELOG.md). If possible, try to
find and denote the version of the spec that included the change you are
making.
## Submitting PRs
Once you're ready to submit your code, create a pull request, and one of our
maintainers will review it. Once your PR has passed review, a maintainer will
merge the request and you're done! 🎉
## Where do I start?
If this is your first contribution to the project, we recommend taking a look
at one of the [open issues][] we've marked for new contributors.
It may be helpful to peruse some of the documentation for `ruma-events` and
`ruma-api` listed above for some context.
[open issues]: https://github.com/ruma/ruma-client-api/issues?q=is%3Aopen+is%3Aissue+label%3Aeffort%2Feasy
# Testing
Before committing, run `cargo check` to make sure that your changes can build, as well as running the formatting and linting tools [mentioned above](#code-formatting-and-linting).
# Contact
Thanks again for being a contributor! If you have any questions, join us at
[#ruma:matrix.org](https://matrix.to/#/#ruma:matrix.org).

View File

@ -0,0 +1,33 @@
[package]
authors = [
"Jimmy Cuadra <jimmy@jimmycuadra.com>",
"Jonas Platte <jplatte@posteo.de>",
"Isaiah Inuwa <isaiah.inuwa@gmail.com>",
]
categories = ["api-bindings", "web-programming"]
description = "Types for the endpoints in the Matrix client-server API."
documentation = "https://docs.rs/ruma-client-api"
homepage = "https://github.com/ruma/ruma-client-api"
keywords = ["matrix", "chat", "messaging", "ruma"]
license = "MIT"
name = "ruma-client-api"
readme = "README.md"
repository = "https://github.com/ruma/ruma-client-api"
version = "0.9.0"
edition = "2018"
[dependencies]
http = "0.2.1"
js_int = { version = "0.1.5", features = ["serde"] }
ruma-api = "0.16.1"
ruma-common = "0.1.3"
ruma-events = { git = "https://github.com/ruma/ruma-events", rev = "c1ee72d" }
ruma-identifiers = "0.16.2"
ruma-serde = "0.2.2"
serde = { version = "1.0.111", features = ["derive"] }
serde_json = "1.0.53"
strum = { version = "0.18.0", features = ["derive"] }
[dev-dependencies]
maplit = "1.0.2"
matches = "0.1.8"

19
ruma-client-api/LICENSE Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2016 Jimmy Cuadra
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.

17
ruma-client-api/README.md Normal file
View File

@ -0,0 +1,17 @@
# ruma-client-api
[![crates.io page](https://img.shields.io/crates/v/ruma-client-api.svg)](https://crates.io/crates/ruma-client-api)
[![docs.rs page](https://docs.rs/ruma-client-api/badge.svg)](https://docs.rs/ruma-client-api/)
[![build status](https://travis-ci.org/ruma/ruma-client-api.svg?branch=master)](https://travis-ci.org/ruma/ruma-client-api)
![license: MIT](https://img.shields.io/crates/l/ruma-client-api.svg)
**ruma-client-api** contains serializable types for the requests and responses for each endpoint in the [Matrix](https://matrix.org/) client API specification.
These types can be shared by client and server code.
## Minimum Rust version
ruma-client-api requires Rust 1.40.0 or later.
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md).

View File

@ -0,0 +1,245 @@
//! Errors that can be sent from the homeserver.
use std::fmt::{self, Display, Formatter};
use ruma_api::{error::ResponseDeserializationError, EndpointError};
use serde::{Deserialize, Serialize};
use serde_json::{from_slice as from_json_slice, to_vec as to_json_vec};
use strum::{AsRefStr, Display, EnumString};
/// An enum for the error kind. Items may contain additional information.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, AsRefStr, Display, EnumString)]
#[serde(tag = "errcode")]
#[cfg_attr(test, derive(PartialEq))]
pub enum ErrorKind {
/// M_FORBIDDEN
#[serde(rename = "M_FORBIDDEN")]
#[strum(to_string = "M_FORBIDDEN")]
Forbidden,
/// M_UNKNOWN_TOKEN
#[serde(rename = "M_UNKNOWN_TOKEN")]
#[strum(to_string = "M_UNKNOWN_TOKEN")]
UnknownToken,
/// M_MISSING_TOKEN
#[serde(rename = "M_MISSING_TOKEN")]
#[strum(to_string = "M_MISSING_TOKEN")]
MissingToken,
/// M_BAD_JSON
#[serde(rename = "M_BAD_JSON")]
#[strum(to_string = "M_BAD_JSON")]
BadJson,
/// M_NOT_JSON
#[serde(rename = "M_NOT_JSON")]
#[strum(to_string = "M_NOT_JSON")]
NotJson,
/// M_NOT_FOUND
#[serde(rename = "M_NOT_FOUND")]
#[strum(to_string = "M_NOT_FOUND")]
NotFound,
/// M_LIMIT_EXCEEDED
#[serde(rename = "M_LIMIT_EXCEEDED")]
#[strum(to_string = "M_LIMIT_EXCEEDED")]
LimitExceeded,
/// M_UNKNOWN
#[serde(rename = "M_UNKNOWN")]
#[strum(to_string = "M_UNKNOWN")]
Unknown,
/// M_UNRECOGNIZED
#[serde(rename = "M_UNRECOGNIZED")]
#[strum(to_string = "M_UNRECOGNIZED")]
Unrecognized,
/// M_UNAUTHORIZED
#[serde(rename = "M_UNAUTHORIZED")]
#[strum(to_string = "M_UNAUTHORIZED")]
Unauthorized,
/// M_USER_DEACTIVATED
#[serde(rename = "M_USER_DEACTIVATED")]
#[strum(to_string = "M_USER_DEACTIVATED")]
UserDeactivated,
/// M_USER_IN_USE
#[serde(rename = "M_USER_IN_USE")]
#[strum(to_string = "M_USER_IN_USE")]
UserInUse,
/// M_INVALID_USERNAME
#[serde(rename = "M_INVALID_USERNAME")]
#[strum(to_string = "M_INVALID_USERNAME")]
InvalidUsername,
/// M_ROOM_IN_USE
#[serde(rename = "M_ROOM_IN_USE")]
#[strum(to_string = "M_ROOM_IN_USE")]
RoomInUse,
/// M_INVALID_ROOM_STATE
#[serde(rename = "M_INVALID_ROOM_STATE")]
#[strum(to_string = "M_INVALID_ROOM_STATE")]
InvalidRoomState,
/// M_THREEPID_IN_USE
#[serde(rename = "M_THREEPID_IN_USE")]
#[strum(to_string = "M_THREEPID_IN_USE")]
ThreepidInUse,
/// M_THREEPID_NOT_FOUND
#[serde(rename = "M_THREEPID_NOT_FOUND")]
#[strum(to_string = "M_THREEPID_NOT_FOUND")]
ThreepidNotFound,
/// M_THREEPID_AUTH_FAILED
#[serde(rename = "M_THREEPID_AUTH_FAILED")]
#[strum(to_string = "M_THREEPID_AUTH_FAILED")]
ThreepidAuthFailed,
/// M_THREEPID_DENIED
#[serde(rename = "M_THREEPID_DENIED")]
#[strum(to_string = "M_THREEPID_DENIED")]
ThreepidDenied,
/// M_SERVER_NOT_TRUSTED
#[serde(rename = "M_SERVER_NOT_TRUSTED")]
#[strum(to_string = "M_SERVER_NOT_TRUSTED")]
ServerNotTrusted,
/// M_UNSUPPORTED_ROOM_VERSION
#[serde(rename = "M_UNSUPPORTED_ROOM_VERSION")]
#[strum(to_string = "M_UNSUPPORTED_ROOM_VERSION")]
UnsupportedRoomVersion,
/// M_INCOMPATIBLE_ROOM_VERSION
#[serde(rename = "M_INCOMPATIBLE_ROOM_VERSION")]
#[strum(to_string = "M_INCOMPATIBLE_ROOM_VERSION")]
IncompatibleRoomVersion,
/// M_BAD_STATE
#[serde(rename = "M_BAD_STATE")]
#[strum(to_string = "M_BAD_STATE")]
BadState,
/// M_GUEST_ACCESS_FORBIDDEN
#[serde(rename = "M_GUEST_ACCESS_FORBIDDEN")]
#[strum(to_string = "M_GUEST_ACCESS_FORBIDDEN")]
GuestAccessForbidden,
/// M_CAPTCHA_NEEDED
#[serde(rename = "M_CAPTCHA_NEEDED")]
#[strum(to_string = "M_CAPTCHA_NEEDED")]
CaptchaNeeded,
/// M_CAPTCHA_INVALID
#[serde(rename = "M_CAPTCHA_INVALID")]
#[strum(to_string = "M_CAPTCHA_INVALID")]
CaptchaInvalid,
/// M_MISSING_PARAM
#[serde(rename = "M_MISSING_PARAM")]
#[strum(to_string = "M_MISSING_PARAM")]
MissingParam,
/// M_INVALID_PARAM
#[serde(rename = "M_INVALID_PARAM")]
#[strum(to_string = "M_INVALID_PARAM")]
InvalidParam,
/// M_TOO_LARGE
#[serde(rename = "M_TOO_LARGE")]
#[strum(to_string = "M_TOO_LARGE")]
TooLarge,
/// M_EXCLUSIVE
#[serde(rename = "M_EXCLUSIVE")]
#[strum(to_string = "M_EXCLUSIVE")]
Exclusive,
}
/// A Matrix Error without a status code
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(test, derive(PartialEq))]
pub struct ErrorBody {
/// A value which can be used to handle an error message
#[serde(flatten)]
pub kind: ErrorKind,
/// A human-readable error message, usually a sentence explaining what went wrong.
#[serde(rename = "error")]
pub message: String,
}
/// A Matrix Error
#[derive(Debug, Clone)]
pub struct Error {
/// A value which can be used to handle an error message
pub kind: ErrorKind,
/// A human-readable error message, usually a sentence explaining what went wrong.
pub message: String,
/// The http status code
pub status_code: http::StatusCode,
}
impl EndpointError for Error {
fn try_from_response(
response: http::Response<Vec<u8>>,
) -> Result<Self, ResponseDeserializationError> {
match from_json_slice::<ErrorBody>(response.body()) {
Ok(error_body) => Ok(error_body.into_error(response.status())),
Err(de_error) => Err(ResponseDeserializationError::new(de_error, response)),
}
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(
f,
"[{} / {}] {}",
self.status_code.as_u16(),
self.kind,
self.message
)
}
}
impl std::error::Error for Error {}
impl From<Error> for ErrorBody {
fn from(error: Error) -> Self {
Self {
kind: error.kind,
message: error.message,
}
}
}
impl ErrorBody {
/// Convert the ErrorBody into an Error by adding the http status code.
pub fn into_error(self, status_code: http::StatusCode) -> Error {
Error {
kind: self.kind,
message: self.message,
status_code,
}
}
}
impl From<Error> for http::Response<Vec<u8>> {
fn from(error: Error) -> http::Response<Vec<u8>> {
http::Response::builder()
.header(http::header::CONTENT_TYPE, "application/json")
.status(error.status_code)
.body(to_json_vec(&ErrorBody::from(error)).unwrap())
.unwrap()
}
}

View File

@ -0,0 +1,15 @@
//! Crate ruma_client_api contains serializable types for the requests and responses for each
//! endpoint in the [Matrix](https://matrix.org/) client API specification. These types can be
//! shared by client and server code.
#![deny(
missing_copy_implementations,
missing_debug_implementations,
missing_docs
)]
pub mod error;
pub mod r0;
pub mod unversioned;
pub use error::Error;

35
ruma-client-api/src/r0.rs Normal file
View File

@ -0,0 +1,35 @@
//! Endpoints for the r0.x.x versions of the client API specification.
pub mod account;
pub mod alias;
pub mod appservice;
pub mod capabilities;
pub mod config;
pub mod contact;
pub mod context;
pub mod device;
pub mod directory;
pub mod filter;
pub mod keys;
pub mod media;
pub mod membership;
pub mod message;
pub mod presence;
pub mod profile;
pub mod push;
pub mod read_marker;
pub mod receipt;
pub mod redact;
pub mod room;
pub mod search;
pub mod server;
pub mod session;
pub mod state;
pub mod sync;
pub mod tag;
pub mod thirdparty;
pub mod to_device;
pub mod typing;
pub mod uiaa;
pub mod user_directory;
pub mod voip;

View File

@ -0,0 +1,43 @@
//! Endpoints for account registration and management.
pub mod bind_3pid;
pub mod change_password;
pub mod deactivate;
pub mod delete_3pid;
pub mod get_username_availability;
pub mod register;
pub mod request_3pid_management_token_via_email;
pub mod request_3pid_management_token_via_msisdn;
pub mod request_openid_token;
pub mod request_password_change_token_via_email;
pub mod request_password_change_token_via_msisdn;
pub mod request_registration_token_via_email;
pub mod request_registration_token_via_msisdn;
pub mod unbind_3pid;
pub mod whoami;
use serde::{Deserialize, Serialize};
/// Additional authentication information for requestToken endpoints.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct IdentityServerInfo {
/// The ID server to send the onward request to as a hostname with an
/// appended colon and port number if the port is not the default.
pub id_server: String,
/// Access token previously registered with identity server.
pub id_access_token: String,
}
/// Possible values for deleting or unbinding 3PIDs
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum ThirdPartyIdRemovalStatus {
/// Either the homeserver couldn't determine the right identity server to contact, or the
/// identity server refused the operation.
NoSupport,
/// Success.
Success,
}

View File

@ -0,0 +1,32 @@
//! [POST /_matrix/client/r0/account/3pid/add](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-account-3pid-add)
use ruma_api::ruma_api;
use crate::r0::uiaa::{AuthData, UiaaResponse};
ruma_api! {
metadata {
description: "Add contact information to a user's account",
method: POST,
name: "add_3pid",
path: "/_matrix/client/r0/account/3pid/add",
rate_limited: true,
requires_authentication: true,
}
request {
/// Additional information for the User-Interactive Authentication API.
#[serde(skip_serializing_if = "Option::is_none")]
pub auth: Option<AuthData>,
/// Client-generated secret string used to protect this session.
pub client_secret: String,
/// The session identifier given by the identity server.
pub sid: String,
}
response {}
error: UiaaResponse
}

View File

@ -0,0 +1,33 @@
//! [POST /_matrix/client/r0/account/3pid/bind](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-account-3pid-bind)
use ruma_api::ruma_api;
use super::IdentityServerInfo;
ruma_api! {
metadata {
description: "Bind a 3PID to a user's account on an identity server",
method: POST,
name: "bind_3pid",
path: "/_matrix/client/r0/account/3pid/bind",
rate_limited: true,
requires_authentication: true,
}
request {
/// Client-generated secret string used to protect this session.
pub client_secret: String,
/// The ID server to send the onward request to as a hostname with an
/// appended colon and port number if the port is not the default.
#[serde(flatten)]
pub identity_server_info: IdentityServerInfo,
/// The session identifier given by the identity server.
pub sid: String,
}
response {}
error: crate::Error
}

View File

@ -0,0 +1,28 @@
//! [POST /_matrix/client/r0/account/password](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-account-password)
use ruma_api::ruma_api;
use crate::r0::uiaa::{AuthData, UiaaResponse};
ruma_api! {
metadata {
description: "Change the password of the current user's account.",
method: POST,
name: "change_password",
path: "/_matrix/client/r0/account/password",
rate_limited: true,
requires_authentication: true,
}
request {
/// The new password for the account.
pub new_password: String,
/// Additional authentication information for the user-interactive authentication API.
pub auth: Option<AuthData>,
}
response {}
error: UiaaResponse
}

View File

@ -0,0 +1,36 @@
//! [POST /_matrix/client/r0/account/deactivate](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-account-deactivate)
use ruma_api::ruma_api;
use crate::r0::uiaa::{AuthData, UiaaResponse};
use super::ThirdPartyIdRemovalStatus;
ruma_api! {
metadata {
description: "Deactivate the current user's account.",
method: POST,
name: "deactivate",
path: "/_matrix/client/r0/account/deactivate",
rate_limited: true,
requires_authentication: true,
}
request {
/// Additional authentication information for the user-interactive authentication API.
#[serde(skip_serializing_if = "Option::is_none")]
pub auth: Option<AuthData>,
/// Identity server from which to unbind the user's third party
/// identifier.
#[serde(skip_serializing_if = "Option::is_none")]
pub id_server: Option<String>,
}
response {
/// Result of unbind operation.
pub id_server_unbind_result: ThirdPartyIdRemovalStatus,
}
error: UiaaResponse
}

View File

@ -0,0 +1,37 @@
//! [POST /_matrix/client/r0/account/3pid/delete](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-account-3pid-delete)
use ruma_api::ruma_api;
use super::ThirdPartyIdRemovalStatus;
use crate::r0::thirdparty::Medium;
ruma_api! {
metadata {
description: "Delete a 3PID from a user's account on an identity server.",
method: POST,
name: "delete_3pid",
path: "/_matrix/client/r0/account/3pid/delete",
rate_limited: false,
requires_authentication: true,
}
request {
/// Identity server to delete from.
#[serde(skip_serializing_if = "Option::is_none")]
pub id_server: Option<String>,
/// Medium of the 3PID to be removed.
pub medium: Medium,
/// Third-party address being removed.
pub address: String,
}
response {
/// Result of unbind operation.
pub id_server_unbind_result: ThirdPartyIdRemovalStatus,
}
error: crate::Error
}

View File

@ -0,0 +1,28 @@
//! [GET /_matrix/client/r0/register/available](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-register-available)
use ruma_api::ruma_api;
ruma_api! {
metadata {
description: "Checks to see if a username is available, and valid, for the server.",
method: GET,
name: "get_username_availability",
path: "/_matrix/client/r0/register/available",
rate_limited: true,
requires_authentication: false,
}
request {
/// The username to check the availability of.
#[ruma_api(query)]
pub username: String,
}
response {
/// A flag to indicate that the username is available.
/// This should always be true when the server replies with 200 OK.
pub available: bool
}
error: crate::Error
}

View File

@ -0,0 +1,98 @@
//! [POST /_matrix/client/r0/register](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-register)
use ruma_api::ruma_api;
use ruma_identifiers::{DeviceId, UserId};
use serde::{Deserialize, Serialize};
use crate::r0::uiaa::{AuthData, UiaaResponse};
ruma_api! {
metadata {
description: "Register an account on this homeserver.",
method: POST,
name: "register",
path: "/_matrix/client/r0/register",
rate_limited: true,
requires_authentication: false,
}
request {
/// The desired password for the account.
///
/// May be empty for accounts that should not be able to log in again
/// with a password, e.g., for guest or application service accounts.
#[serde(skip_serializing_if = "Option::is_none")]
pub password: Option<String>,
/// local part of the desired Matrix ID.
///
/// If omitted, the homeserver MUST generate a Matrix ID local part.
#[serde(skip_serializing_if = "Option::is_none")]
pub username: Option<String>,
/// 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.
#[serde(skip_serializing_if = "Option::is_none")]
pub device_id: Option<DeviceId>,
/// A display name to assign to the newly-created device.
///
/// Ignored if `device_id` corresponds to a known device.
#[serde(skip_serializing_if = "Option::is_none")]
pub initial_device_display_name: Option<String>,
/// Additional authentication information for the user-interactive authentication API.
///
/// Note that this information is not used to define how the registered user should be
/// authenticated, but is instead used to authenticate the register call itself.
/// It should be left empty, or omitted, unless an earlier call returned an response
/// with status code 401.
#[serde(skip_serializing_if = "Option::is_none")]
pub auth: Option<AuthData>,
/// Kind of account to register
///
/// Defaults to `User` if omitted.
#[ruma_api(query)]
#[serde(skip_serializing_if = "Option::is_none")]
pub kind: Option<RegistrationKind>,
/// If `true`, an `access_token` and `device_id` should not be returned
/// from this call, therefore preventing an automatic login.
#[serde(default, skip_serializing_if = "ruma_serde::is_default")]
pub inhibit_login: bool,
}
response {
/// An access token for the account.
///
/// This access token can then be used to authorize other requests.
#[serde(skip_serializing_if = "Option::is_none")]
pub access_token: Option<String>,
/// The fully-qualified Matrix ID that has been registered.
pub user_id: UserId,
/// ID of the registered device.
///
/// Will be the same as the corresponding parameter in the request, if one was specified.
pub device_id: Option<DeviceId>,
}
error: UiaaResponse
}
/// The kind of account being registered.
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum RegistrationKind {
/// A guest account
///
/// These accounts may have limited permissions and may not be supported by all servers.
Guest,
/// A regular user account
User,
}

View File

@ -0,0 +1,48 @@
//! [POST /_matrix/client/r0/account/3pid/email/requestToken](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-account-3pid-email-requesttoken)
use js_int::UInt;
use ruma_api::ruma_api;
use super::IdentityServerInfo;
ruma_api! {
metadata {
description: "Request a 3PID management token with a 3rd party email.",
method: POST,
name: "request_3pid_association_token_via_email",
path: "/_matrix/client/r0/account/3pid/email/requestToken",
rate_limited: false,
requires_authentication: false,
}
request {
/// Client-generated secret string used to protect this session.
pub client_secret: String,
/// The email address.
pub email: String,
/// Used to distinguish protocol level retries from requests to re-send the email.
pub send_attempt: UInt,
/// Return URL for identity server to redirect the client back to.
#[serde(skip_serializing_if = "Option::is_none")]
pub next_link: Option<String>,
/// Optional identity server hostname and access token. Deprecated since r0.6.0.
#[serde(flatten)]
#[serde(skip_serializing_if = "Option::is_none")]
pub identity_server_info: Option<IdentityServerInfo>,
}
response {
/// The session identifier given by the identity server.
pub sid: String,
/// URL to submit validation token to. If omitted, verification happens without client.
#[serde(skip_serializing_if = "Option::is_none")]
pub submit_url: Option<String>
}
error: crate::Error
}

View File

@ -0,0 +1,51 @@
//! [POST /_matrix/client/r0/account/3pid/msisdn/requestToken](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-account-3pid-msisdn-requesttoken)
use js_int::UInt;
use ruma_api::ruma_api;
use super::IdentityServerInfo;
ruma_api! {
metadata {
description: "Request a 3PID management token with a phone number.",
method: POST,
name: "request_3pid_association_token_via_msisdn",
path: "/_matrix/client/r0/account/3pid/msisdn/requestToken",
rate_limited: false,
requires_authentication: false,
}
request {
/// Client-generated secret string used to protect this session.
pub client_secret: String,
/// Two-letter ISO 3166 country code for the phone number.
pub country: String,
/// Phone number to validate.
pub phone_number: String,
/// Used to distinguish protocol level retries from requests to re-send the SMS.
pub send_attempt: UInt,
/// Return URL for identity server to redirect the client back to.
#[serde(skip_serializing_if = "Option::is_none")]
pub next_link: Option<String>,
/// Optional identity server hostname and access token. Deprecated since r0.6.0.
#[serde(flatten)]
#[serde(skip_serializing_if = "Option::is_none")]
pub identity_server_info: Option<IdentityServerInfo>,
}
response {
/// The session identifier given by the identity server.
pub sid: String,
/// URL to submit validation token to. If omitted, verification happens without client.
#[serde(skip_serializing_if = "Option::is_none")]
pub submit_url: Option<String>
}
error: crate::Error
}

View File

@ -0,0 +1,48 @@
//! [POST /_matrix/client/r0/user/{userId}/openid/request_token](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-user-userid-openid-request-token)
use std::time::Duration;
use ruma_api::ruma_api;
use ruma_identifiers::UserId;
use serde::{Deserialize, Serialize};
ruma_api! {
metadata {
description: "Request an OpenID 1.0 token to verify identity with a third party.",
name: "request_openid_token",
method: POST,
path: "/_matrix/client/r0/user/:user_id/openid/request_token",
rate_limited: true,
requires_authentication: true,
}
request {
/// User ID of authenticated user.
#[ruma_api(path)]
pub user_id: UserId,
}
response {
/// Access token for verifying user's identity.
pub access_token: String,
/// Access token type.
pub token_type: TokenType,
/// Homeserver domain for verification of user's identity.
pub matrix_server_name: String,
/// Seconds until token expiration.
#[serde(with = "ruma_serde::duration::secs")]
pub expires_in: Duration,
}
error: crate::Error
}
/// Access token types.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub enum TokenType {
/// Bearer token type
Bearer,
}

View File

@ -0,0 +1,48 @@
//! [POST /_matrix/client/r0/account/password/email/requestToken](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-account-password-email-requesttoken)
use js_int::UInt;
use ruma_api::ruma_api;
use super::IdentityServerInfo;
ruma_api! {
metadata {
description: "Request that a password change token is sent to the given email address.",
method: POST,
name: "request_password_change_token_via_email",
path: "/_matrix/client/r0/account/password/email/requestToken",
rate_limited: false,
requires_authentication: false,
}
request {
/// Client-generated secret string used to protect this session.
pub client_secret: String,
/// The email address.
pub email: String,
/// Used to distinguish protocol level retries from requests to re-send the email.
pub send_attempt: UInt,
/// Return URL for identity server to redirect the client back to.
#[serde(skip_serializing_if = "Option::is_none")]
pub next_link: Option<String>,
/// Optional identity server hostname and access token. Deprecated since r0.6.0.
#[serde(flatten)]
#[serde(skip_serializing_if = "Option::is_none")]
pub identity_server_info: Option<IdentityServerInfo>,
}
response {
/// The session identifier given by the identity server.
pub sid: String,
/// URL to submit validation token to. If omitted, verification happens without client.
#[serde(skip_serializing_if = "Option::is_none")]
pub submit_url: Option<String>
}
error: crate::Error
}

View File

@ -0,0 +1,44 @@
//! [POST /_matrix/client/r0/account/password/msisdn/requestToken](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-account-password-msisdn-requesttoken)
use js_int::UInt;
use ruma_api::ruma_api;
ruma_api! {
metadata {
description: "Request that a password change token is sent to the given phone number.",
method: POST,
name: "request_password_change_token_via_msisdn",
path: "/_matrix/client/r0/account/password/msisdn/requestToken",
rate_limited: false,
requires_authentication: false,
}
request {
/// Client-generated secret string used to protect this session.
pub client_secret: String,
/// Two-letter ISO 3166 country code for the phone number.
pub country: String,
/// Phone number to validate.
pub phone_number: String,
/// Used to distinguish protocol level retries from requests to re-send the SMS.
pub send_attempt: UInt,
/// Return URL for identity server to redirect the client back to.
#[serde(skip_serializing_if = "Option::is_none")]
pub next_link: Option<String>,
}
response {
/// The session identifier given by the identity server.
pub sid: String,
/// URL to submit validation token to. If omitted, verification happens without client.
#[serde(skip_serializing_if = "Option::is_none")]
pub submit_url: Option<String>
}
error: crate::Error
}

View File

@ -0,0 +1,48 @@
//! [POST /_matrix/client/r0/register/email/requestToken](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-register-email-requesttoken)
use js_int::UInt;
use ruma_api::ruma_api;
use super::IdentityServerInfo;
ruma_api! {
metadata {
description: "Request a registration token with a 3rd party email.",
method: POST,
name: "request_registration_token_via_email",
path: "/_matrix/client/r0/register/email/requestToken",
rate_limited: false,
requires_authentication: false,
}
request {
/// Client-generated secret string used to protect this session.
pub client_secret: String,
/// The email address.
pub email: String,
/// Used to distinguish protocol level retries from requests to re-send the email.
pub send_attempt: UInt,
/// Return URL for identity server to redirect the client back to.
#[serde(skip_serializing_if = "Option::is_none")]
pub next_link: Option<String>,
/// Optional identity server hostname and access token. Deprecated since r0.6.0.
#[serde(flatten)]
#[serde(skip_serializing_if = "Option::is_none")]
pub identity_server_info: Option<IdentityServerInfo>,
}
response {
/// The session identifier given by the identity server.
pub sid: String,
/// URL to submit validation token to. If omitted, verification happens without client.
#[serde(skip_serializing_if = "Option::is_none")]
pub submit_url: Option<String>
}
error: crate::Error
}

View File

@ -0,0 +1,51 @@
//! [POST /_matrix/client/r0/register/msisdn/requestToken](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-register-msisdn-requesttoken)
use js_int::UInt;
use ruma_api::ruma_api;
use super::IdentityServerInfo;
ruma_api! {
metadata {
description: "Request a registration token with a phone number.",
method: POST,
name: "request_registration_token_via_msisdn",
path: "/_matrix/client/r0/register/msisdn/requestToken",
rate_limited: false,
requires_authentication: false,
}
request {
/// Client-generated secret string used to protect this session.
pub client_secret: String,
/// Two-letter ISO 3166 country code for the phone number.
pub country: String,
/// Phone number to validate.
pub phone_number: String,
/// Return URL for identity server to redirect the client back to.
#[serde(skip_serializing_if = "Option::is_none")]
pub next_link: Option<String>,
/// Used to distinguish protocol level retries from requests to re-send the SMS.
pub send_attempt: UInt,
/// Optional identity server hostname and access token. Deprecated since r0.6.0.
#[serde(flatten)]
#[serde(skip_serializing_if = "Option::is_none")]
pub identity_server_info: Option<IdentityServerInfo>,
}
response {
/// The session identifier given by the identity server.
pub sid: String,
/// URL to submit validation token to. If omitted, verification happens without client.
#[serde(skip_serializing_if = "Option::is_none")]
pub submit_url: Option<String>
}
error: crate::Error
}

View File

@ -0,0 +1,36 @@
//! [POST /_matrix/client/r0/account/3pid/unbind](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-account-3pid-unbind)
use ruma_api::ruma_api;
use super::ThirdPartyIdRemovalStatus;
use crate::r0::thirdparty::Medium;
ruma_api! {
metadata {
description: "Unbind a 3PID from a user's account on an identity server.",
method: POST,
name: "unbind_3pid",
path: "/_matrix/client/r0/account/3pid/unbind",
rate_limited: false,
requires_authentication: true,
}
request {
/// Identity server to unbind from.
#[serde(skip_serializing_if = "Option::is_none")]
pub id_server: Option<String>,
/// Medium of the 3PID to be removed.
pub medium: Medium,
/// Third-party address being removed.
pub address: String,
}
response {
/// Result of unbind operation.
pub id_server_unbind_result: ThirdPartyIdRemovalStatus,
}
error: crate::Error
}

View File

@ -0,0 +1,23 @@
//! [GET /_matrix/client/r0/account/whoami](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-account-whoami)
use ruma_api::ruma_api;
ruma_api! {
metadata {
description: "Get information about the owner of a given access token.",
method: GET,
name: "whoami",
path: "/_matrix/client/r0/account/whoami",
rate_limited: true,
requires_authentication: true,
}
request {}
response {
/// The id of the user that owns the access token.
pub user_id: String,
}
error: crate::Error
}

View File

@ -0,0 +1,5 @@
//! Endpoints for room aliases.
pub mod create_alias;
pub mod delete_alias;
pub mod get_alias;

View File

@ -0,0 +1,28 @@
//! [PUT /_matrix/client/r0/directory/room/{roomAlias}](https://matrix.org/docs/spec/client_server/r0.6.0#put-matrix-client-r0-directory-room-roomalias)
use ruma_api::ruma_api;
use ruma_identifiers::{RoomAliasId, RoomId};
ruma_api! {
metadata {
description: "Add an alias to a room.",
method: PUT,
name: "create_alias",
path: "/_matrix/client/r0/directory/room/:room_alias",
rate_limited: false,
requires_authentication: true,
}
request {
/// The room alias to set.
#[ruma_api(path)]
pub room_alias: RoomAliasId,
/// The room ID to set.
pub room_id: RoomId,
}
response {}
error: crate::Error
}

View File

@ -0,0 +1,25 @@
//! [DELETE /_matrix/client/r0/directory/room/{roomAlias}](https://matrix.org/docs/spec/client_server/r0.6.0#delete-matrix-client-r0-directory-room-roomalias)
use ruma_api::ruma_api;
use ruma_identifiers::RoomAliasId;
ruma_api! {
metadata {
description: "Remove an alias from a room.",
method: DELETE,
name: "delete_alias",
path: "/_matrix/client/r0/directory/room/:room_alias",
rate_limited: false,
requires_authentication: true,
}
request {
/// The room alias to remove.
#[ruma_api(path)]
pub room_alias: RoomAliasId,
}
response {}
error: crate::Error
}

View File

@ -0,0 +1,31 @@
//! [GET /_matrix/client/r0/directory/room/{roomAlias}](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-directory-room-roomalias)
use ruma_api::ruma_api;
use ruma_identifiers::{RoomAliasId, RoomId};
ruma_api! {
metadata {
description: "Resolve a room alias to a room ID.",
method: GET,
name: "get_alias",
path: "/_matrix/client/r0/directory/room/:room_alias",
rate_limited: false,
requires_authentication: true,
}
request {
/// The room alias.
#[ruma_api(path)]
pub room_alias: RoomAliasId,
}
response {
/// The room ID for this room alias.
pub room_id: RoomId,
/// A list of servers that are aware of this room ID.
pub servers: Vec<String>,
}
error: crate::Error
}

View File

@ -0,0 +1,3 @@
//! Endpoints part of the application service extension of the client-server API
pub mod set_room_visibility;

View File

@ -0,0 +1,34 @@
//! [PUT /_matrix/client/r0/directory/list/appservice/{networkId}/{roomId}](https://matrix.org/docs/spec/application_service/r0.1.2#put-matrix-client-r0-directory-list-appservice-networkid-roomid)
use ruma_api::ruma_api;
use ruma_identifiers::RoomId;
use crate::r0::room::Visibility;
ruma_api! {
metadata {
description: "Updates the visibility of a given room on the application service's room directory.",
method: PUT,
name: "set_room_visibility",
path: "/_matrix/client/r0/directory/list/appservice/:network_id/:room_id",
rate_limited: false,
requires_authentication: true,
}
request {
/// The protocol (network) ID to update the room list for.
#[ruma_api(path)]
pub network_id: String,
/// The room ID to add to the directory.
#[ruma_api(path)]
pub room_id: RoomId,
/// Whether the room should be visible (public) in the directory or not (private).
pub visibility: Visibility,
}
response {}
error: crate::Error
}

View File

@ -0,0 +1,3 @@
//! Endpoints for querying the server's supported feature set
pub mod get_capabilities;

View File

@ -0,0 +1,73 @@
//! [GET /_matrix/client/r0/capabilities](https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-capabilities)
use ruma_api::ruma_api;
use ruma_identifiers::RoomVersionId;
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
use std::collections::BTreeMap;
ruma_api! {
metadata {
description: "Gets information about the server's supported feature set and other relevant capabilities.",
method: GET,
name: "get_capabilities",
path: "/_matrix/client/r0/capabilities",
rate_limited: true,
requires_authentication: true
}
request {}
response {
/// The capabilities the server supports
pub capabilities: Capabilities,
}
error: crate::Error
}
/// Contains information about all the capabilities that the server supports.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Capabilities {
/// Capability to indicate if the user can change their password.
#[serde(rename = "m.change_password", skip_serializing_if = "Option::is_none")]
pub change_password: Option<ChangePasswordCapability>,
/// The room versions the server supports.
#[serde(rename = "m.room_versions", skip_serializing_if = "Option::is_none")]
pub room_versions: Option<RoomVersionsCapability>,
/// Any other custom capabilities that the server supports outside of the specification,
/// labeled using the Java package naming convention and stored as arbitrary JSON values.
#[serde(flatten)]
pub custom_capabilities: BTreeMap<String, JsonValue>,
}
/// Information about the m.change_password capability
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct ChangePasswordCapability {
/// True if the user can change their password, false otherwise.
pub enabled: bool,
}
/// Information about the m.room_versions capability
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RoomVersionsCapability {
/// The default room version the server is using for new rooms.
pub default: String,
/// A detailed description of the room versions the server supports.
pub available: BTreeMap<RoomVersionId, RoomVersionStability>,
}
/// The stability of a room version
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub enum RoomVersionStability {
/// Support for the given version is stable.
#[serde(rename = "stable")]
Stable,
/// Support for the given version is unstable.
#[serde(rename = "unstable")]
Unstable,
}

View File

@ -0,0 +1,6 @@
//! Endpoints for client configuration.
pub mod get_global_account_data;
pub mod get_room_account_data;
pub mod set_global_account_data;
pub mod set_room_account_data;

View File

@ -0,0 +1,34 @@
//! [GET /_matrix/client/r0/user/{userId}/account_data/{type}](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-user-userid-account-data-type)
use ruma_api::ruma_api;
use ruma_events::{collections::only, EventJson};
use ruma_identifiers::UserId;
ruma_api! {
metadata {
description: "Gets global account data for a user.",
name: "get_global_account_data",
method: GET,
path: "/_matrix/client/r0/user/:user_id/account_data/:event_type",
rate_limited: false,
requires_authentication: true,
}
request {
/// User ID of user for whom to retrieve data.
#[ruma_api(path)]
pub user_id: UserId,
/// Type of data to retrieve.
#[ruma_api(path)]
pub event_type: String,
}
response {
/// Account data content for the given type.
#[ruma_api(body)]
pub account_data: EventJson<only::Event>,
}
error: crate::Error
}

View File

@ -0,0 +1,38 @@
//! [GET /_matrix/client/r0/user/{userId}/rooms/{roomId}/account_data/{type}](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-user-userid-rooms-roomid-account-data-type)
use ruma_api::ruma_api;
use ruma_events::{collections::only, EventJson};
use ruma_identifiers::{RoomId, UserId};
ruma_api! {
metadata {
description: "Gets account data room for a user for a given room",
name: "get_room_account_data",
method: GET,
path: "/_matrix/client/r0/user/:user_id/rooms/:room_id/account_data/:event_type",
rate_limited: false,
requires_authentication: true,
}
request {
/// User ID of user for whom to retrieve data.
#[ruma_api(path)]
pub user_id: UserId,
/// Room ID for which to retrieve data.
#[ruma_api(path)]
pub room_id: RoomId,
/// Type of data to retrieve.
#[ruma_api(path)]
pub event_type: String,
}
response {
/// Account data content for the given type.
#[ruma_api(body)]
pub account_data: EventJson<only::Event>,
}
error: crate::Error
}

View File

@ -0,0 +1,40 @@
//! [PUT /_matrix/client/r0/user/{userId}/account_data/{type}](https://matrix.org/docs/spec/client_server/r0.6.0#put-matrix-client-r0-user-userid-account-data-type)
use ruma_api::ruma_api;
use ruma_identifiers::UserId;
use serde_json::value::RawValue as RawJsonValue;
ruma_api! {
metadata {
description: "Sets global account data.",
method: PUT,
name: "set_global_account_data",
path: "/_matrix/client/r0/user/:user_id/account_data/:event_type",
rate_limited: false,
requires_authentication: true,
}
request {
/// Arbitrary JSON to store as config data.
///
/// To create a `Box<RawJsonValue>`, use `serde_json::value::to_raw_value`.
#[ruma_api(body)]
pub data: Box<RawJsonValue>,
/// The event type of the account_data to set.
///
/// Custom types should be namespaced to avoid clashes.
#[ruma_api(path)]
pub event_type: String,
/// The ID of the user to set account_data for.
///
/// The access token must be authorized to make requests for this user ID.
#[ruma_api(path)]
pub user_id: UserId,
}
response {}
error: crate::Error
}

View File

@ -0,0 +1,44 @@
//! [PUT /_matrix/client/r0/user/{userId}/rooms/{roomId}/account_data/{type}](https://matrix.org/docs/spec/client_server/r0.6.0#put-matrix-client-r0-user-userid-rooms-roomid-account-data-type)
use ruma_api::ruma_api;
use ruma_identifiers::{RoomId, UserId};
use serde_json::value::RawValue as RawJsonValue;
ruma_api! {
metadata {
description: "Associate account data with a room.",
method: PUT,
name: "set_room_account_data",
path: "/_matrix/client/r0/user/:user_id/rooms/:room_id/account_data/:event_type",
rate_limited: false,
requires_authentication: true,
}
request {
/// Arbitrary JSON to store as config data.
///
/// To create a `Box<RawJsonValue>`, use `serde_json::value::to_raw_value`.
#[ruma_api(body)]
pub data: Box<RawJsonValue>,
/// The event type of the account_data to set.
///
/// Custom types should be namespaced to avoid clashes.
#[ruma_api(path)]
pub event_type: String,
/// The ID of the room to set account_data on.
#[ruma_api(path)]
pub room_id: RoomId,
/// The ID of the user to set account_data for.
///
/// The access token must be authorized to make requests for this user ID.
#[ruma_api(path)]
pub user_id: UserId,
}
response {}
error: crate::Error
}

View File

@ -0,0 +1,4 @@
//! Endpoints for account contact information.
pub mod get_contacts;
pub mod request_contact_verification_token;

View File

@ -0,0 +1,84 @@
//! [GET /_matrix/client/r0/account/3pid](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-account-3pid)
use std::time::SystemTime;
use ruma_api::ruma_api;
use serde::{Deserialize, Serialize};
use crate::r0::thirdparty::Medium;
ruma_api! {
metadata {
description: "Get a list of 3rd party contacts associated with the user's account.",
method: GET,
name: "get_contacts",
path: "/_matrix/client/r0/account/3pid",
rate_limited: false,
requires_authentication: true,
}
request {}
response {
/// A list of third party identifiers the homeserver has associated with the user's
/// account.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub threepids: Vec<ThirdPartyIdentifier>,
}
error: crate::Error
}
/// An identifier external to Matrix.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(test, derive(PartialEq))]
pub struct ThirdPartyIdentifier {
/// The third party identifier address.
pub address: String,
/// The medium of third party identifier.
pub medium: Medium,
/// The time when the identifier was validated by the identity server.
#[serde(with = "ruma_serde::time::ms_since_unix_epoch")]
pub validated_at: SystemTime,
/// The time when the homeserver associated the third party identifier with the user.
#[serde(with = "ruma_serde::time::ms_since_unix_epoch")]
pub added_at: SystemTime,
}
#[cfg(test)]
mod tests {
use std::time::{Duration, UNIX_EPOCH};
use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
use super::{Medium, ThirdPartyIdentifier};
#[test]
fn third_party_identifier_serde() {
let third_party_id = ThirdPartyIdentifier {
address: "monkey@banana.island".into(),
medium: Medium::Email,
validated_at: UNIX_EPOCH + Duration::from_millis(1_535_176_800_000),
added_at: UNIX_EPOCH + Duration::from_millis(1_535_336_848_756),
};
let third_party_id_serialized = json!({
"medium": "email",
"address": "monkey@banana.island",
"validated_at": 1_535_176_800_000u64,
"added_at": 1_535_336_848_756u64
});
assert_eq!(
to_json_value(third_party_id.clone()).unwrap(),
third_party_id_serialized
);
assert_eq!(
third_party_id,
from_json_value(third_party_id_serialized).unwrap()
);
}
}

View File

@ -0,0 +1,47 @@
//! [POST /_matrix/client/r0/account/3pid/email/requestToken](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-account-3pid-email-requesttoken)
use js_int::UInt;
use ruma_api::ruma_api;
ruma_api! {
metadata {
description: "Ask for a verification token for a given 3rd party ID.",
method: POST,
name: "request_contact_verification_token",
path: "/_matrix/client/r0/account/3pid/email/requestToken",
rate_limited: false,
requires_authentication: false,
}
request {
/// Client-generated secret string used to protect this session.
pub client_secret: String,
/// The email address.
pub email: String,
/// A URL for the identity server to redirect the user to after
/// validation is completed.
#[serde(skip_serializing_if = "Option::is_none")]
pub next_link: Option<String>,
/// Used to distinguish protocol level retries from requests to re-send
/// the email.
pub send_attempt: UInt,
/// The identity server to send the onward request to as a hostname with
/// an appended colon and port number if the port is not the default.
#[serde(skip_serializing_if = "Option::is_none")]
pub id_server: Option<String>,
/// An access token previously registered with the identity server.
///
/// Required if an `id_server` is supplied.
#[serde(skip_serializing_if = "Option::is_none")]
pub id_access_token: Option<String>,
}
response {}
error: crate::Error
}

View File

@ -0,0 +1,3 @@
//! Endpoints for event context.
pub mod get_context;

View File

@ -0,0 +1,84 @@
//! [GET /_matrix/client/r0/rooms/{roomId}/context/{eventId}](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-rooms-roomid-context-eventid)
use js_int::UInt;
use ruma_api::ruma_api;
use ruma_events::{collections::all, EventJson};
use ruma_identifiers::{EventId, RoomId};
use crate::r0::filter::RoomEventFilter;
ruma_api! {
metadata {
description: "Get the events immediately preceding and following a given event.",
method: GET,
path: "/_matrix/client/r0/rooms/:room_id/context/:event_id",
name: "get_context",
rate_limited: false,
requires_authentication: true,
}
request {
/// The room to get events from.
#[ruma_api(path)]
pub room_id: RoomId,
/// The event to get context around.
#[ruma_api(path)]
pub event_id: EventId,
/// The maximum number of events to return.
///
/// Defaults to 10.
#[ruma_api(query)]
#[serde(default = "default_limit", skip_serializing_if = "is_default_limit")]
pub limit: UInt,
/// A RoomEventFilter to filter returned events with.
#[ruma_api(query)]
#[serde(
with = "ruma_serde::json_string",
default,
skip_serializing_if = "Option::is_none"
)]
pub filter: Option<RoomEventFilter>,
}
response {
/// A token that can be used to paginate backwards with.
#[serde(skip_serializing_if = "Option::is_none")]
pub start: Option<String>,
/// A token that can be used to paginate forwards with.
#[serde(skip_serializing_if = "Option::is_none")]
pub end: Option<String>,
/// A list of room events that happened just before the requested event,
/// in reverse-chronological order.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub events_before: Vec<EventJson<all::RoomEvent>>,
/// Details of the requested event.
#[serde(skip_serializing_if = "Option::is_none")]
pub event: Option<EventJson<all::RoomEvent>>,
/// A list of room events that happened just after the requested event,
/// in chronological order.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub events_after: Vec<EventJson<all::RoomEvent>>,
/// The state of the room at the last event returned.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub state: Vec<EventJson<all::StateEvent>>,
}
error: crate::Error
}
fn default_limit() -> UInt {
UInt::from(10u32)
}
#[allow(clippy::trivially_copy_pass_by_ref)]
fn is_default_limit(val: &UInt) -> bool {
*val == default_limit()
}

View File

@ -0,0 +1,33 @@
//! Endpoints for managing devices.
use std::time::SystemTime;
use ruma_identifiers::DeviceId;
use serde::{Deserialize, Serialize};
pub mod delete_device;
pub mod delete_devices;
pub mod get_device;
pub mod get_devices;
pub mod update_device;
/// Information about a registered device.
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
pub struct Device {
/// Device ID
pub device_id: DeviceId,
/// Public display name of the device.
pub display_name: Option<String>,
/// Most recently seen IP address of the session.
pub last_seen_ip: Option<String>,
/// Unix timestamp that the session was last active.
#[serde(
with = "ruma_serde::time::opt_ms_since_unix_epoch",
default,
skip_serializing_if = "Option::is_none"
)]
pub last_seen_ts: Option<SystemTime>,
}

View File

@ -0,0 +1,31 @@
//! [DELETE /_matrix/client/r0/devices/{deviceId}](https://matrix.org/docs/spec/client_server/r0.6.0#delete-matrix-client-r0-devices-deviceid)
use ruma_api::ruma_api;
use ruma_identifiers::DeviceId;
use crate::r0::uiaa::{AuthData, UiaaResponse};
ruma_api! {
metadata {
description: "Delete a device for authenticated user.",
method: DELETE,
name: "delete_device",
path: "/_matrix/client/r0/devices/:device_id",
rate_limited: false,
requires_authentication: true,
}
request {
/// The device to delete.
#[ruma_api(path)]
pub device_id: DeviceId,
/// Additional authentication information for the user-interactive authentication API.
#[serde(skip_serializing_if = "Option::is_none")]
pub auth: Option<AuthData>,
}
response {}
error: UiaaResponse
}

View File

@ -0,0 +1,30 @@
//! [POST /_matrix/client/r0/delete_devices](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-delete-devices)
use ruma_api::ruma_api;
use ruma_identifiers::DeviceId;
use crate::r0::uiaa::{AuthData, UiaaResponse};
ruma_api! {
metadata {
description: "Delete specified devices.",
method: POST,
path: "/_matrix/client/r0/delete_devices",
name: "delete_devices",
rate_limited: false,
requires_authentication: true,
}
request {
/// List of devices to delete.
pub devices: Vec<DeviceId>,
/// Additional authentication information for the user-interactive authentication API.
#[serde(skip_serializing_if = "Option::is_none")]
pub auth: Option<AuthData>,
}
response {}
error: UiaaResponse
}

View File

@ -0,0 +1,30 @@
//! [GET /_matrix/client/r0/devices/{deviceId}](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-devices-deviceid)
use super::Device;
use ruma_api::ruma_api;
use ruma_identifiers::DeviceId;
ruma_api! {
metadata {
description: "Get a device for authenticated user.",
method: GET,
name: "get_device",
path: "/_matrix/client/r0/devices/:device_id",
rate_limited: false,
requires_authentication: true,
}
request {
/// The device to retrieve.
#[ruma_api(path)]
pub device_id: DeviceId,
}
response {
/// Information about the device.
#[ruma_api(body)]
pub device: Device,
}
error: crate::Error
}

View File

@ -0,0 +1,24 @@
//! [GET /_matrix/client/r0/devices](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-devices)
use super::Device;
use ruma_api::ruma_api;
ruma_api! {
metadata {
description: "Get registered devices for authenticated user.",
method: GET,
name: "get_devices",
path: "/_matrix/client/r0/devices",
rate_limited: false,
requires_authentication: true,
}
request {}
response {
/// A list of all registered devices for this user
pub devices: Vec<Device>,
}
error: crate::Error
}

View File

@ -0,0 +1,30 @@
//! [PUT /_matrix/client/r0/devices/{deviceId}](https://matrix.org/docs/spec/client_server/r0.6.0#put-matrix-client-r0-devices-deviceid)
use ruma_api::ruma_api;
use ruma_identifiers::DeviceId;
ruma_api! {
metadata {
description: "Update metadata for a device.",
method: PUT,
name: "update_device",
path: "/_matrix/client/r0/devices/:device_id",
rate_limited: false,
requires_authentication: true,
}
request {
/// The device to update.
#[ruma_api(path)]
pub device_id: DeviceId,
/// The new display name for this device. If this is `None`, the display name won't be
/// changed.
#[serde(skip_serializing_if = "Option::is_none")]
pub display_name: Option<String>,
}
response {}
error: crate::Error
}

View File

@ -0,0 +1,48 @@
//! Endpoints for the public room directory.
pub mod get_public_rooms;
pub mod get_public_rooms_filtered;
pub mod get_room_visibility;
pub mod set_room_visibility;
use js_int::UInt;
use ruma_identifiers::{RoomAliasId, RoomId};
use serde::{Deserialize, Serialize};
/// A chunk of a room list response, describing one room
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct PublicRoomsChunk {
/// Aliases of the room.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub aliases: Vec<RoomAliasId>,
/// The canonical alias of the room, if any.
#[serde(skip_serializing_if = "Option::is_none")]
pub canonical_alias: Option<RoomAliasId>,
/// The name of the room, if any.
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
/// The number of members joined to the room.
pub num_joined_members: UInt,
/// The ID of the room.
pub room_id: RoomId,
/// The topic of the room, if any.
#[serde(skip_serializing_if = "Option::is_none")]
pub topic: Option<String>,
/// Whether the room may be viewed by guest users without joining.
pub world_readable: bool,
/// 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.
pub guest_can_join: bool,
/// The URL for the room's avatar, if one is set.
#[serde(skip_serializing_if = "Option::is_none")]
pub avatar_url: Option<String>,
}

View File

@ -0,0 +1,52 @@
//! [GET /_matrix/client/r0/publicRooms](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-publicrooms)
use js_int::UInt;
use ruma_api::ruma_api;
use super::PublicRoomsChunk;
ruma_api! {
metadata {
description: "Get the list of rooms in this homeserver's public directory.",
method: GET,
name: "get_public_rooms",
path: "/_matrix/client/r0/publicRooms",
rate_limited: false,
requires_authentication: false,
}
request {
/// Limit for the number of results to return.
#[serde(skip_serializing_if = "Option::is_none")]
#[ruma_api(query)]
pub limit: Option<UInt>,
/// Pagination token from a previous request.
#[serde(skip_serializing_if = "Option::is_none")]
#[ruma_api(query)]
pub since: Option<String>,
/// The server to fetch the public room lists from.
///
/// `None` means the server this request is sent to.
#[serde(skip_serializing_if = "Option::is_none")]
#[ruma_api(query)]
pub server: Option<String>,
}
response {
/// A paginated chunk of public rooms.
pub chunk: Vec<PublicRoomsChunk>,
/// A pagination token for the response.
pub next_batch: Option<String>,
/// A pagination token that allows fetching previous results.
pub prev_batch: Option<String>,
/// An estimate on the total number of public rooms, if the server has an estimate.
pub total_room_count_estimate: Option<UInt>,
}
error: crate::Error
}

View File

@ -0,0 +1,255 @@
//! [POST /_matrix/client/r0/publicRooms](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-publicrooms)
use std::fmt;
use js_int::UInt;
use ruma_api::ruma_api;
use serde::{
de::{MapAccess, Visitor},
ser::SerializeStruct,
Deserialize, Deserializer, Serialize, Serializer,
};
use serde_json::Value as JsonValue;
use super::PublicRoomsChunk;
ruma_api! {
metadata {
description: "Get the list of rooms in this homeserver's public directory.",
method: POST,
name: "get_public_rooms_filtered",
path: "/_matrix/client/r0/publicRooms",
rate_limited: false,
requires_authentication: true,
}
request {
/// The server to fetch the public room lists from.
///
/// `None` means the server this request is sent to.
#[serde(skip_serializing_if = "Option::is_none")]
#[ruma_api(query)]
pub server: Option<String>,
/// Limit for the number of results to return.
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<UInt>,
/// Pagination token from a previous request.
#[serde(skip_serializing_if = "Option::is_none")]
pub since: Option<String>,
/// Filter to apply to the results.
#[serde(skip_serializing_if = "Option::is_none")]
pub filter: Option<Filter>,
/// Network to fetch the public room lists from.
#[serde(flatten, skip_serializing_if = "ruma_serde::is_default")]
pub room_network: RoomNetwork,
}
response {
/// A paginated chunk of public rooms.
pub chunk: Vec<PublicRoomsChunk>,
/// A pagination token for the response.
pub next_batch: Option<String>,
/// A pagination token that allows fetching previous results.
pub prev_batch: Option<String>,
/// An estimate on the total number of public rooms, if the server has an estimate.
pub total_room_count_estimate: Option<UInt>,
}
error: crate::Error
}
/// A filter for public rooms lists
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Filter {
/// A string to search for in the room metadata, e.g. name, topic, canonical alias etc.
#[serde(skip_serializing_if = "Option::is_none")]
pub generic_search_term: Option<String>,
}
/// Information about which networks/protocols from application services on the
/// homeserver from which to request rooms.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RoomNetwork {
/// Return rooms from the Matrix network.
Matrix,
/// Return rooms from all the networks/protocols the homeserver knows about.
All,
/// Return rooms from a specific third party network/protocol.
ThirdParty(String),
}
impl Default for RoomNetwork {
fn default() -> Self {
RoomNetwork::Matrix
}
}
impl Serialize for RoomNetwork {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state;
match self {
Self::Matrix => {
state = serializer.serialize_struct("RoomNetwork", 0)?;
}
Self::All => {
state = serializer.serialize_struct("RoomNetwork", 1)?;
state.serialize_field("include_all_networks", &true)?;
}
Self::ThirdParty(network) => {
state = serializer.serialize_struct("RoomNetwork", 1)?;
state.serialize_field("third_party_instance_id", network)?;
}
}
state.end()
}
}
impl<'de> Deserialize<'de> for RoomNetwork {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_map(RoomNetworkVisitor)
}
}
struct RoomNetworkVisitor;
impl<'de> Visitor<'de> for RoomNetworkVisitor {
type Value = RoomNetwork;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("Network selection")
}
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut include_all_networks = false;
let mut third_party_instance_id = None;
while let Some((key, value)) = access.next_entry::<String, JsonValue>()? {
match key.as_str() {
"include_all_networks" => {
include_all_networks = match value.as_bool() {
Some(b) => b,
_ => false,
}
}
"third_party_instance_id" => {
third_party_instance_id = value.as_str().map(|v| v.to_owned())
}
_ => {}
};
}
if include_all_networks {
if third_party_instance_id.is_none() {
Ok(RoomNetwork::All)
} else {
Err(M::Error::custom(
"`include_all_networks = true` and `third_party_instance_id` are mutually exclusive.",
))
}
} else {
Ok(match third_party_instance_id {
Some(network) => RoomNetwork::ThirdParty(network),
None => RoomNetwork::Matrix,
})
}
}
}
#[cfg(test)]
mod tests {
use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
use super::RoomNetwork;
#[test]
fn test_serialize_matrix_network_only() {
let json = json!({});
assert_eq!(to_json_value(RoomNetwork::Matrix).unwrap(), json);
}
#[test]
fn test_deserialize_matrix_network_only() {
let json = json!({ "include_all_networks": false });
assert_eq!(
from_json_value::<RoomNetwork>(json).unwrap(),
RoomNetwork::Matrix
);
}
#[test]
fn test_serialize_default_network_is_empty() {
let json = json!({});
assert_eq!(to_json_value(RoomNetwork::default()).unwrap(), json);
}
#[test]
fn test_deserialize_empty_network_is_default() {
let json = json!({});
assert_eq!(
from_json_value::<RoomNetwork>(json).unwrap(),
RoomNetwork::default()
);
}
#[test]
fn test_serialize_include_all_networks() {
let json = json!({ "include_all_networks": true });
assert_eq!(to_json_value(RoomNetwork::All).unwrap(), json);
}
#[test]
fn test_deserialize_include_all_networks() {
let json = json!({ "include_all_networks": true });
assert_eq!(
from_json_value::<RoomNetwork>(json).unwrap(),
RoomNetwork::All
);
}
#[test]
fn test_serialize_third_party_network() {
let json = json!({ "third_party_instance_id": "freenode" });
assert_eq!(
to_json_value(RoomNetwork::ThirdParty("freenode".to_string())).unwrap(),
json
);
}
#[test]
fn test_deserialize_third_party_network() {
let json = json!({ "third_party_instance_id": "freenode" });
assert_eq!(
from_json_value::<RoomNetwork>(json).unwrap(),
RoomNetwork::ThirdParty("freenode".to_string())
);
}
#[test]
fn test_deserialize_include_all_networks_and_third_party_exclusivity() {
let json = json!({ "include_all_networks": true, "third_party_instance_id": "freenode" });
assert_eq!(
from_json_value::<RoomNetwork>(json)
.unwrap_err()
.to_string()
.as_str(),
"`include_all_networks = true` and `third_party_instance_id` are mutually exclusive."
);
}
}

View File

@ -0,0 +1,30 @@
//! [GET /_matrix/client/r0/directory/list/room/{roomId}](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-directory-list-room-roomid)
use ruma_api::ruma_api;
use ruma_identifiers::RoomId;
use crate::r0::room::Visibility;
ruma_api! {
metadata {
description: "Get the visibility of a public room on a directory.",
name: "get_room_visibility",
method: GET,
path: "/_matrix/client/r0/directory/list/room/:room_id",
rate_limited: false,
requires_authentication: false,
}
request {
/// The ID of the room of which to request the visibility.
#[ruma_api(path)]
pub room_id: RoomId,
}
response {
/// Visibility of the room.
pub visibility: Visibility,
}
error: crate::Error
}

View File

@ -0,0 +1,30 @@
//! [PUT /_matrix/client/r0/directory/list/room/{roomId}](https://matrix.org/docs/spec/client_server/r0.6.0#put-matrix-client-r0-directory-list-room-roomid)
use ruma_api::ruma_api;
use ruma_identifiers::RoomId;
use crate::r0::room::Visibility;
ruma_api! {
metadata {
description: "Set the visibility of a public room on a directory.",
name: "set_room_visibility",
method: PUT,
path: "/_matrix/client/r0/directory/list/room/:room_id",
rate_limited: false,
requires_authentication: true,
}
request {
/// The ID of the room of which to set the visibility.
#[ruma_api(path)]
pub room_id: RoomId,
/// New visibility setting for the room.
pub visibility: Visibility,
}
response {}
error: crate::Error
}

View File

@ -0,0 +1,381 @@
//! Endpoints for event filters.
pub mod create_filter;
pub mod get_filter;
use std::fmt;
use js_int::UInt;
use ruma_identifiers::{RoomId, UserId};
use serde::{
de::{MapAccess, Visitor},
ser::SerializeStruct,
Deserialize, Deserializer, Serialize, Serializer,
};
/// Format to use for returned events
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum EventFormat {
/// Client format, as described in the Client API.
Client,
/// Raw events from federation.
Federation,
}
/// Filters to be applied to room events
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct RoomEventFilter {
/// 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.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub not_types: Vec<String>,
/// 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.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub not_rooms: Vec<String>,
/// The maximum number of events to return.
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<UInt>,
/// A list of room IDs to include.
///
/// If this list is absent then all rooms are included.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub rooms: Option<Vec<RoomId>>,
/// 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.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub not_senders: Vec<UserId>,
/// A list of senders IDs to include.
///
/// If this list is absent then all senders are included.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub senders: Option<Vec<UserId>>,
/// 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.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub types: Option<Vec<String>>,
/// If `true` include only events with a URL key in their content.
/// If `false`, exclude such events.
///
/// If this item is absent then all event types are included.
#[serde(skip_serializing_if = "Option::is_none")]
pub contains_url: Option<bool>,
/// Options to control lazy-loading of membership events.
#[serde(flatten)]
pub lazy_load_options: LazyLoadOptions,
}
impl RoomEventFilter {
/// A filter that can be used to ignore all room events
pub fn ignore_all() -> Self {
Self {
types: Some(vec![]),
..Default::default()
}
}
}
/// Filters to be applied to room data
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct RoomFilter {
/// Include rooms that the user has left in the sync.
///
/// Defaults to false if not included.
#[serde(skip_serializing_if = "Option::is_none")]
pub include_leave: Option<bool>,
/// The per user account data to include for rooms.
#[serde(skip_serializing_if = "Option::is_none")]
pub account_data: Option<RoomEventFilter>,
/// The message and state update events to include for rooms.
#[serde(skip_serializing_if = "Option::is_none")]
pub timeline: Option<RoomEventFilter>,
/// The events that aren't recorded in the room history, e.g. typing and receipts, to include
/// for rooms.
#[serde(skip_serializing_if = "Option::is_none")]
pub ephemeral: Option<RoomEventFilter>,
/// The state events to include for rooms.
#[serde(skip_serializing_if = "Option::is_none")]
pub state: Option<RoomEventFilter>,
/// 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`.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub not_rooms: Vec<RoomId>,
/// 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`.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub rooms: Option<Vec<RoomId>>,
}
impl RoomFilter {
/// A filter that can be used to ignore all room events (of any type)
pub fn ignore_all() -> Self {
Self {
rooms: Some(vec![]),
..Default::default()
}
}
}
/// Filter for not-room data
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Filter {
/// 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.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub not_types: Vec<String>,
/// The maximum number of events to return.
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<UInt>,
/// A list of senders IDs to include.
///
/// If this list is absent then all senders are included.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub senders: Option<Vec<UserId>>,
/// 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.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub types: Option<Vec<String>>,
/// 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.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub not_senders: Vec<UserId>,
}
impl Filter {
/// A filter that can be used to ignore all events
pub fn ignore_all() -> Self {
Self {
types: Some(vec![]),
..Default::default()
}
}
}
/// A filter definition
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct FilterDefinition {
/// List of event fields to include.
///
/// If this list is absent then all fields are included. The entries may include '.' charaters
/// 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.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub event_fields: Option<Vec<String>>,
/// 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'.
#[serde(skip_serializing_if = "Option::is_none")]
pub event_format: Option<EventFormat>,
/// The presence updates to include.
#[serde(skip_serializing_if = "Option::is_none")]
pub presence: Option<Filter>,
/// The user account data that isn't associated with rooms to include.
#[serde(skip_serializing_if = "Option::is_none")]
pub account_data: Option<Filter>,
/// Filters to be applied to room data.
#[serde(skip_serializing_if = "Option::is_none")]
pub room: Option<RoomFilter>,
}
impl FilterDefinition {
/// A filter that can be used to ignore all events
pub fn ignore_all() -> Self {
Self {
account_data: Some(Filter::ignore_all()),
room: Some(RoomFilter::ignore_all()),
presence: Some(Filter::ignore_all()),
..Default::default()
}
}
}
/// Specifies options for [lazy-loading membership events][lazy-loading] on
/// supported endpoints
///
/// [lazy-loading]: https://matrix.org/docs/spec/client_server/r0.6.0#lazy-loading-room-members
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LazyLoadOptions {
/// Disables lazy-loading of membership events.
Disabled,
/// Enables lazy-loading of events.
Enabled {
/// If `true`, sends all membership events for all events, even if they have
/// already been sent to the client. Defaults to `false`.
include_redundant_members: bool,
},
}
impl Serialize for LazyLoadOptions {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state;
match *self {
Self::Enabled {
include_redundant_members: true,
} => {
state = serializer.serialize_struct("LazyLoad", 2)?;
state.serialize_field("lazy_load_members", &true)?;
state.serialize_field("include_redundant_members", &true)?;
}
Self::Enabled { .. } => {
state = serializer.serialize_struct("LazyLoad", 1)?;
state.serialize_field("lazy_load_members", &true)?;
}
_ => {
state = serializer.serialize_struct("LazyLoad", 0)?;
}
}
state.end()
}
}
impl Default for LazyLoadOptions {
fn default() -> Self {
Self::Disabled
}
}
struct LazyLoadOptionsVisitor;
impl<'de> Visitor<'de> for LazyLoadOptionsVisitor {
type Value = LazyLoadOptions;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("Lazy load options")
}
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut lazy_load_members = false;
let mut include_redundant_members = false;
while let Some((key, value)) = access.next_entry::<String, bool>()? {
match &*key {
"lazy_load_members" => lazy_load_members = value,
"include_redundant_members" => include_redundant_members = value,
_ => {}
};
}
Ok(if lazy_load_members {
LazyLoadOptions::Enabled {
include_redundant_members,
}
} else {
LazyLoadOptions::Disabled
})
}
}
impl<'de> Deserialize<'de> for LazyLoadOptions {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_map(LazyLoadOptionsVisitor)
}
}
#[cfg(test)]
mod tests {
use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
use super::LazyLoadOptions;
#[test]
fn test_serializing_disabled_lazy_load() {
let lazy_load_options = LazyLoadOptions::Disabled;
assert_eq!(to_json_value(lazy_load_options).unwrap(), json!({}));
}
#[test]
fn test_serializing_lazy_load_no_redundant() {
let lazy_load_options = LazyLoadOptions::Enabled {
include_redundant_members: false,
};
assert_eq!(
to_json_value(lazy_load_options).unwrap(),
json!({ "lazy_load_members": true })
);
}
#[test]
fn test_serializing_lazy_load_with_redundant() {
let lazy_load_options = LazyLoadOptions::Enabled {
include_redundant_members: true,
};
assert_eq!(
to_json_value(lazy_load_options).unwrap(),
json!({ "lazy_load_members": true, "include_redundant_members": true })
);
}
#[test]
fn test_deserializing_no_lazy_load() {
let json = json!({});
assert_eq!(
from_json_value::<LazyLoadOptions>(json).unwrap(),
LazyLoadOptions::Disabled,
);
}
#[test]
fn test_deserializing_ignore_redundant_members_when_no_lazy_load() {
let json = json!({ "include_redundant_members": true });
assert_eq!(
from_json_value::<LazyLoadOptions>(json).unwrap(),
LazyLoadOptions::Disabled,
);
}
}

View File

@ -0,0 +1,36 @@
//! [POST /_matrix/client/r0/user/{userId}/filter](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-user-userid-filter)
use ruma_api::ruma_api;
use ruma_identifiers::UserId;
use super::FilterDefinition;
ruma_api! {
metadata {
description: "Create a new filter for event retrieval.",
method: POST,
name: "create_filter",
path: "/_matrix/client/r0/user/:user_id/filter",
rate_limited: false,
requires_authentication: true,
}
request {
/// The ID of the user uploading the filter.
///
/// The access token must be authorized to make requests for this user ID.
#[ruma_api(path)]
pub user_id: UserId,
/// The filter definition.
#[ruma_api(body)]
pub filter: FilterDefinition,
}
response {
/// The ID of the filter that was created.
pub filter_id: String,
}
error: crate::Error
}

View File

@ -0,0 +1,35 @@
//! [GET /_matrix/client/r0/user/{userId}/filter/{filterId}](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-user-userid-filter-filterid)
use ruma_api::ruma_api;
use ruma_identifiers::UserId;
use super::FilterDefinition;
ruma_api! {
metadata {
description: "Retrieve a previously created filter.",
method: GET,
name: "get_filter",
path: "/_matrix/client/r0/user/:user_id/filter/:filter_id",
rate_limited: false,
requires_authentication: true,
}
request {
/// The user ID to download a filter for.
#[ruma_api(path)]
pub user_id: UserId,
/// The ID of the filter to download.
#[ruma_api(path)]
pub filter_id: String,
}
response {
/// The filter definition.
#[ruma_api(body)]
pub filter: FilterDefinition,
}
error: crate::Error
}

View File

@ -0,0 +1,164 @@
//! Endpoints for key management
use std::{
collections::BTreeMap,
convert::TryFrom,
fmt::{self, Debug, Display, Formatter},
};
use ruma_events::Algorithm;
use ruma_identifiers::{DeviceId, UserId};
use serde::{
de::{self, Unexpected},
Deserialize, Deserializer, Serialize, Serializer,
};
pub mod claim_keys;
pub mod get_key_changes;
pub mod get_keys;
pub mod upload_keys;
/// The basic key algorithms in the specification
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum KeyAlgorithm {
/// The Ed25519 signature algorithm.
#[serde(rename = "ed25519")]
Ed25519,
/// The Curve25519 ECDH algorithm.
#[serde(rename = "curve25519")]
Curve25519,
/// The Curve25519 ECDH algorithm, but the key also contains signatures
#[serde(rename = "signed_curve25519")]
SignedCurve25519,
}
impl Display for KeyAlgorithm {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let algorithm_str = match *self {
KeyAlgorithm::Ed25519 => "ed25519",
KeyAlgorithm::Curve25519 => "curve25519",
KeyAlgorithm::SignedCurve25519 => "signed_curve25519",
};
write!(f, "{}", algorithm_str)?;
Ok(())
}
}
impl TryFrom<&'_ str> for KeyAlgorithm {
type Error = &'static str;
fn try_from(s: &str) -> Result<Self, Self::Error> {
match s {
"ed25519" => Ok(KeyAlgorithm::Ed25519),
"curve25519" => Ok(KeyAlgorithm::Curve25519),
"signed_curve25519" => Ok(KeyAlgorithm::SignedCurve25519),
_ => Err("Unknown algorithm"),
}
}
}
/// A key algorithm and a device id, combined with a ':'
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct AlgorithmAndDeviceId(pub KeyAlgorithm, pub DeviceId);
impl Display for AlgorithmAndDeviceId {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", self.0, self.1)
}
}
impl Serialize for AlgorithmAndDeviceId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
impl<'de> Deserialize<'de> for AlgorithmAndDeviceId {
#[allow(clippy::comparison_chain)]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value = String::deserialize(deserializer)?;
let parts = value.split(':').collect::<Vec<_>>();
const EXPECTED: &str = "a string composed of an algorithm and a device id separated by ':'";
if parts.len() < 2 {
return Err(de::Error::invalid_type(
Unexpected::Other("string without a ':' separator"),
&EXPECTED,
));
} else if parts.len() > 2 {
return Err(de::Error::invalid_type(
Unexpected::Other("string with more than one ':' separator"),
&EXPECTED,
));
}
let algorithm_result = KeyAlgorithm::try_from(parts[0]);
match algorithm_result {
Ok(algorithm) => Ok(AlgorithmAndDeviceId(algorithm, parts[1].to_string())),
Err(_) => Err(de::Error::invalid_value(
Unexpected::Str(parts[0]),
&"valid key algorithm",
)),
}
}
}
/// Identity keys for a device.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeviceKeys {
/// The ID of the user the device belongs to. Must match the user ID used when logging in.
pub user_id: UserId,
/// The ID of the device these keys belong to. Must match the device ID used when logging in.
pub device_id: DeviceId,
/// The encryption algorithms supported by this device.
pub algorithms: Vec<Algorithm>,
/// Public identity keys.
pub keys: BTreeMap<AlgorithmAndDeviceId, String>,
/// Signatures for the device key object.
pub signatures: BTreeMap<UserId, BTreeMap<AlgorithmAndDeviceId, String>>,
/// Additional data added to the device key information by intermediate servers, and
/// not covered by the signatures.
#[serde(skip_serializing_if = "Option::is_none")]
pub unsigned: Option<UnsignedDeviceInfo>,
}
/// Additional data added to device key information by intermediate servers.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UnsignedDeviceInfo {
/// The display name which the user set on the device.
pub device_display_name: Option<String>,
}
/// A key for the SignedCurve25519 algorithm
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SignedKey {
/// Base64-encoded 32-byte Curve25519 public key.
pub key: String,
/// Signatures for the key object.
pub signatures: BTreeMap<UserId, BTreeMap<AlgorithmAndDeviceId, String>>,
}
/// A one-time public key for "pre-key" messages.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum OneTimeKey {
/// A key containing signatures, for the SignedCurve25519 algorithm.
SignedKey(SignedKey),
/// A string-valued key, for the Ed25519 and Curve25519 algorithms.
Key(String),
}

View File

@ -0,0 +1,47 @@
//! [POST /_matrix/client/r0/keys/claim](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-keys-claim)
use std::collections::BTreeMap;
use std::time::Duration;
use ruma_api::ruma_api;
use ruma_identifiers::{DeviceId, UserId};
use serde_json::Value as JsonValue;
use super::{AlgorithmAndDeviceId, KeyAlgorithm, OneTimeKey};
ruma_api! {
metadata {
description: "Claims one-time keys for use in pre-key messages.",
method: POST,
name: "claim_keys",
path: "/_matrix/client/r0/keys/claim",
rate_limited: false,
requires_authentication: true,
}
request {
/// The time (in milliseconds) to wait when downloading keys from remote servers.
/// 10 seconds is the recommended default.
#[serde(
with = "ruma_serde::duration::opt_ms",
default,
skip_serializing_if = "Option::is_none",
)]
pub timeout: Option<Duration>,
/// The keys to be claimed.
pub one_time_keys: BTreeMap<UserId, BTreeMap<DeviceId, KeyAlgorithm>>,
}
response {
/// If any remote homeservers could not be reached, they are recorded here.
/// The names of the properties are the names of the unreachable servers.
pub failures: BTreeMap<String, JsonValue>,
/// One-time keys for the queried devices.
pub one_time_keys: BTreeMap<UserId, BTreeMap<DeviceId, BTreeMap<AlgorithmAndDeviceId, OneTimeKey>>>,
}
error: crate::Error
}

View File

@ -0,0 +1,38 @@
//! [GET /_matrix/client/r0/keys/changes](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-keys-changes)
use ruma_api::ruma_api;
use ruma_identifiers::UserId;
ruma_api! {
metadata {
description: "Gets a list of users who have updated their device identity keys since a previous sync token.",
method: GET,
name: "get_key_changes",
path: "/_matrix/client/r0/keys/changes",
rate_limited: false,
requires_authentication: true,
}
request {
/// The desired start point of the list.
/// Should be the next_batch field from a response to an earlier call to /sync.
#[ruma_api(query)]
pub from: String,
/// The desired end point of the list.
/// Should be the next_batch field from a recent call to /sync - typically the most recent such call.
#[ruma_api(query)]
pub to: String,
}
response {
/// The Matrix User IDs of all users who updated their device identity keys.
pub changed: Vec<UserId>,
/// The Matrix User IDs of all users who may have left all the end-to-end
/// encrypted rooms they previously shared with the user.
pub left: Vec<UserId>
}
error: crate::Error
}

View File

@ -0,0 +1,55 @@
//! [POST /_matrix/client/r0/keys/query](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-keys-query)
use std::{collections::BTreeMap, time::Duration};
use ruma_api::ruma_api;
use ruma_identifiers::{DeviceId, UserId};
use serde_json::Value as JsonValue;
use super::DeviceKeys;
ruma_api! {
metadata {
description: "Returns the current devices and identity keys for the given users.",
method: POST,
name: "get_keys",
path: "/_matrix/client/r0/keys/query",
rate_limited: false,
requires_authentication: true,
}
request {
/// The time (in milliseconds) to wait when downloading keys from remote
/// servers. 10 seconds is the recommended default.
#[serde(
with = "ruma_serde::duration::opt_ms",
default,
skip_serializing_if = "Option::is_none",
)]
pub timeout: Option<Duration>,
/// The keys to be downloaded. An empty list indicates all devices for
/// the corresponding user.
pub device_keys: BTreeMap<UserId, Vec<DeviceId>>,
/// 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.
#[serde(skip_serializing_if = "Option::is_none")]
pub token: Option<String>,
}
response {
/// If any remote homeservers could not be reached, they are recorded
/// here. The names of the properties are the names of the unreachable
/// servers.
pub failures: BTreeMap<String, JsonValue>,
/// Information on the queried devices.
pub device_keys: BTreeMap<UserId, BTreeMap<DeviceId, DeviceKeys>>,
}
error: crate::Error
}

View File

@ -0,0 +1,37 @@
//! [POST /_matrix/client/r0/keys/upload](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-keys-upload)
use std::collections::BTreeMap;
use js_int::UInt;
use ruma_api::ruma_api;
use super::{AlgorithmAndDeviceId, DeviceKeys, KeyAlgorithm, OneTimeKey};
ruma_api! {
metadata {
description: "Publishes end-to-end encryption keys for the device.",
method: POST,
name: "upload_keys",
path: "/_matrix/client/r0/keys/upload",
rate_limited: false,
requires_authentication: true,
}
request {
/// Identity keys for the device. May be absent if no new identity keys are required.
#[serde(skip_serializing_if = "Option::is_none")]
pub device_keys: Option<DeviceKeys>,
/// One-time public keys for "pre-key" messages.
#[serde(skip_serializing_if = "Option::is_none")]
pub one_time_keys: Option<BTreeMap<AlgorithmAndDeviceId, OneTimeKey>>,
}
response {
/// For each key algorithm, the number of unclaimed one-time keys of that
/// type currently held on the server for this device.
pub one_time_key_counts: BTreeMap<KeyAlgorithm, UInt>
}
error: crate::Error
}

View File

@ -0,0 +1,8 @@
//! Endpoints for the media repository.
pub mod create_content;
pub mod get_content;
pub mod get_content_as_filename;
pub mod get_content_thumbnail;
pub mod get_media_config;
pub mod get_media_preview;

View File

@ -0,0 +1,37 @@
//! [POST /_matrix/media/r0/upload](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-media-r0-upload)
use ruma_api::ruma_api;
ruma_api! {
metadata {
description: "Upload content to the media store.",
method: POST,
name: "create_media_content",
path: "/_matrix/media/r0/upload",
rate_limited: true,
requires_authentication: true,
}
request {
/// The name of the file being uploaded.
#[ruma_api(query)]
#[serde(skip_serializing_if = "Option::is_none")]
pub filename: Option<String>,
/// The content type of the file being uploaded.
// TODO: This should be optional.
#[ruma_api(header = CONTENT_TYPE)]
pub content_type: String,
/// The file contents to upload.
#[ruma_api(raw_body)]
pub file: Vec<u8>,
}
response {
/// The MXC URI for the uploaded content.
pub content_uri: String,
}
error: crate::Error
}

View File

@ -0,0 +1,45 @@
//! [GET /_matrix/media/r0/download/{serverName}/{mediaId}](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-media-r0-download-servername-mediaid)
use ruma_api::ruma_api;
ruma_api! {
metadata {
description: "Retrieve content from the media store.",
method: GET,
name: "get_media_content",
path: "/_matrix/media/r0/download/:server_name/:media_id",
rate_limited: false,
requires_authentication: false,
}
request {
/// The media ID from the mxc:// URI (the path component).
#[ruma_api(path)]
pub media_id: String,
/// The server name from the mxc:// URI (the authoritory component).
#[ruma_api(path)]
pub server_name: String,
/// Whether to fetch media deemed remote.
/// Used to prevent routing loops. Defaults to `true`.
#[ruma_api(query)]
pub allow_remote: Option<bool>,
}
response {
/// The content that was previously uploaded.
#[ruma_api(raw_body)]
pub file: Vec<u8>,
/// The content type of the file that was previously uploaded.
#[ruma_api(header = CONTENT_TYPE)]
pub content_type: String,
/// The name of the file that was previously uploaded, if set.
#[ruma_api(header = CONTENT_DISPOSITION)]
pub content_disposition: String,
}
error: crate::Error
}

View File

@ -0,0 +1,49 @@
//! [GET /_matrix/media/r0/download/{serverName}/{mediaId}/{fileName}](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-media-r0-download-servername-mediaid-filename)
use ruma_api::ruma_api;
ruma_api! {
metadata {
description: "Retrieve content from the media store, specifying a filename to return.",
method: GET,
name: "get_media_content_as_filename",
path: "/_matrix/media/r0/download/:server_name/:media_id/:filename",
rate_limited: false,
requires_authentication: false,
}
request {
/// The media ID from the mxc:// URI (the path component).
#[ruma_api(path)]
pub media_id: String,
/// The server name from the mxc:// URI (the authoritory component).
#[ruma_api(path)]
pub server_name: String,
/// The filename to return in the `Content-Disposition` header.
#[ruma_api(path)]
pub filename: String,
/// Whether to fetch media deemed remote.
/// Used to prevent routing loops. Defaults to `true`.
#[ruma_api(query)]
pub allow_remote: Option<bool>,
}
response {
/// The content that was previously uploaded.
#[ruma_api(raw_body)]
pub file: Vec<u8>,
/// The content type of the file that was previously uploaded.
#[ruma_api(header = CONTENT_TYPE)]
pub content_type: String,
/// The name of the file that was previously uploaded, if set.
#[ruma_api(header = CONTENT_DISPOSITION)]
pub content_disposition: String,
}
error: crate::Error
}

View File

@ -0,0 +1,71 @@
//! [GET /_matrix/media/r0/thumbnail/{serverName}/{mediaId}](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-media-r0-thumbnail-servername-mediaid)
use js_int::UInt;
use ruma_api::ruma_api;
use serde::{Deserialize, Serialize};
/// The desired resizing method.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum Method {
/// Crop the original to produce the requested image dimensions.
Crop,
/// Maintain the original aspect ratio of the source image.
Scale,
}
ruma_api! {
metadata {
description: "Get a thumbnail of content from the media store.",
method: GET,
name: "get_content_thumbnail",
path: "/_matrix/media/r0/thumbnail/:server_name/:media_id",
rate_limited: true,
requires_authentication: false,
}
request {
/// Whether to fetch media deemed remote.
///
/// Used to prevent routing loops. Defaults to `true`.
#[ruma_api(query)]
#[serde(skip_serializing_if = "Option::is_none")]
pub allow_remote: Option<bool>,
/// The media ID from the mxc:// URI (the path component).
#[ruma_api(path)]
pub media_id: String,
/// The server name from the mxc:// URI (the authoritory component).
#[ruma_api(path)]
pub server_name: String,
/// The *desired* height of the thumbnail. The actual thumbnail may not match the size
/// specified.
#[ruma_api(query)]
pub height: UInt,
/// The desired resizing method.
#[ruma_api(query)]
#[serde(skip_serializing_if = "Option::is_none")]
pub method: Option<Method>,
/// The *desired* width of the thumbnail. The actual thumbnail may not match the size
/// specified.
#[ruma_api(query)]
pub width: UInt,
}
response {
/// The content type of the thumbnail.
#[ruma_api(header = CONTENT_TYPE)]
pub content_type: String,
/// A thumbnail of the requested content.
#[ruma_api(raw_body)]
pub file: Vec<u8>,
}
error: crate::Error
}

View File

@ -0,0 +1,25 @@
//! [GET /_matrix/media/r0/config](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-media-r0-config)
use js_int::UInt;
use ruma_api::ruma_api;
ruma_api! {
metadata {
description: "Gets the config for the media repository.",
method: GET,
path: "/_matrix/media/r0/config",
name: "get_media_config",
rate_limited: true,
requires_authentication: true,
}
request {}
response {
/// Maximum size of upload in bytes.
#[serde(rename = "m.upload.size")]
pub upload_size: UInt,
}
error: crate::Error
}

View File

@ -0,0 +1,73 @@
//! [GET /_matrix/media/r0/preview_url](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-media-r0-preview-url)
use std::time::SystemTime;
use ruma_api::ruma_api;
use serde_json::value::RawValue as RawJsonValue;
ruma_api! {
metadata {
description: "Get a preview for a URL.",
name: "get_media_preview",
method: GET,
path: "/_matrix/media/r0/preview_url",
rate_limited: true,
requires_authentication: true,
}
request {
/// URL to get a preview of.
#[ruma_api(query)]
pub url: String,
/// Preferred point in time (in milliseconds) to return a preview for.
#[ruma_api(query)]
#[serde(with = "ruma_serde::time::ms_since_unix_epoch")]
pub ts: SystemTime,
}
response {
/// OpenGraph-like data for the URL.
///
/// Differences from OpenGraph: the image size in bytes is added to the `matrix:image:size`
/// field, and `og:image` returns the MXC URI to the image, if any.
#[ruma_api(body)]
pub data: Option<Box<RawJsonValue>>,
}
error: crate::Error
}
#[cfg(test)]
mod tests {
use serde_json::{
from_value as from_json_value, json,
value::{to_raw_value as to_raw_json_value, RawValue as RawJsonValue},
};
// Since BTreeMap<String, Box<RawJsonValue>> deserialization doesn't seem to
// work, test that Option<RawJsonValue> works
#[test]
fn raw_json_deserialize() {
type OptRawJson = Option<Box<RawJsonValue>>;
assert!(from_json_value::<OptRawJson>(json!(null))
.unwrap()
.is_none());
assert!(from_json_value::<OptRawJson>(json!("test"))
.unwrap()
.is_some());
assert!(from_json_value::<OptRawJson>(json!({ "a": "b" }))
.unwrap()
.is_some());
}
// For completeness sake, make sure serialization works too
#[test]
fn raw_json_serialize() {
assert!(to_raw_json_value(&json!(null)).is_ok());
assert!(to_raw_json_value(&json!("string")).is_ok());
assert!(to_raw_json_value(&json!({})).is_ok());
assert!(to_raw_json_value(&json!({ "a": "b" })).is_ok());
}
}

View File

@ -0,0 +1,52 @@
//! Endpoints for room membership.
pub mod ban_user;
pub mod forget_room;
pub mod get_member_events;
pub mod invite_user;
pub mod join_room_by_id;
pub mod join_room_by_id_or_alias;
pub mod joined_members;
pub mod joined_rooms;
pub mod kick_user;
pub mod leave_room;
pub mod unban_user;
use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
use crate::r0::thirdparty::Medium;
/// 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.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ThirdPartySigned {
/// The Matrix ID of the user who issued the invite.
pub sender: String,
/// The Matrix ID of the invitee.
pub mxid: String,
/// The state key of the m.third_party_invite event.
pub token: String,
/// A signatures object containing a signature of the entire signed object.
pub signatures: BTreeMap<String, BTreeMap<String, String>>,
}
/// Represents third party IDs to invite to the room.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct Invite3pid {
/// Hostname and port of identity server to be used for account lookups.
pub id_server: String,
/// An access token registered with the identity server.
pub id_access_token: String,
/// Type of third party ID.
pub medium: Medium,
/// Third party identifier.
pub address: String,
}

View File

@ -0,0 +1,32 @@
//! [POST /_matrix/client/r0/rooms/{roomId}/ban](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-rooms-roomid-ban)
use ruma_api::ruma_api;
use ruma_identifiers::{RoomId, UserId};
ruma_api! {
metadata {
description: "Ban a user from a room.",
method: POST,
name: "ban_user",
path: "/_matrix/client/r0/rooms/:room_id/ban",
rate_limited: false,
requires_authentication: true,
}
request {
/// The room to kick the user from.
#[ruma_api(path)]
pub room_id: RoomId,
/// The user to ban.
pub user_id: UserId,
/// The reason for banning the user.
#[serde(skip_serializing_if = "Option::is_none")]
pub reason: Option<String>,
}
response {}
error: crate::Error
}

View File

@ -0,0 +1,25 @@
//! [POST /_matrix/client/r0/rooms/{roomId}/forget](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-rooms-roomid-forget)
use ruma_api::ruma_api;
use ruma_identifiers::RoomId;
ruma_api! {
metadata {
description: "Forget a room.",
method: POST,
name: "forget_room",
path: "/_matrix/client/r0/rooms/:room_id/forget",
rate_limited: true,
requires_authentication: true,
}
request {
/// The room to forget.
#[ruma_api(path)]
pub room_id: RoomId,
}
response {}
error: crate::Error
}

View File

@ -0,0 +1,66 @@
//! [GET /_matrix/client/r0/rooms/{roomId}/members](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-rooms-roomid-members)
use ruma_api::ruma_api;
use ruma_events::{room::member::MemberEvent, EventJson};
use ruma_identifiers::RoomId;
use serde::{Deserialize, Serialize};
ruma_api! {
metadata {
description: "Get membership events for a room.",
method: GET,
name: "get_member_events",
path: "/_matrix/client/r0/rooms/:room_id/members",
rate_limited: false,
requires_authentication: true,
}
request {
/// The room to get the member events for.
#[ruma_api(path)]
pub room_id: RoomId,
/// 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.
#[serde(skip_serializing_if = "Option::is_none")]
#[ruma_api(query)]
pub at: Option<String>,
/// The kind of memberships 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.
#[serde(skip_serializing_if = "Option::is_none")]
#[ruma_api(query)]
pub membership: Option<MembershipEventFilter>,
/// The kind of memberships to *exclude* from the results. Defaults to no filtering if
/// unspecified.
#[serde(skip_serializing_if = "Option::is_none")]
#[ruma_api(query)]
pub not_membership: Option<MembershipEventFilter>,
}
response {
/// A list of member events.
pub chunk: Vec<EventJson<MemberEvent>>
}
error: crate::Error
}
/// The kind of membership events to filter for.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum MembershipEventFilter {
/// The user has joined.
Join,
/// The user has been invited.
Invite,
/// The user has left.
Leave,
/// The user has been banned.
Ban,
}

View File

@ -0,0 +1,90 @@
//! [POST /_matrix/client/r0/rooms/{roomId}/invite][invite-by-user-id]
//!
//! This endpoint has two forms: one to invite a user
//! [by their Matrix identifier][invite-by-user-id], and one to invite a user
//! [by their third party identifier][invite-by-3pid].
//!
//! [invite-by-user-id]: https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-rooms-roomid-invite
//! [invite-by-3pid]: https://matrix.org/docs/spec/client_server/r0.6.0#id101
use ruma_api::ruma_api;
use ruma_identifiers::{RoomId, UserId};
use serde::{Deserialize, Serialize};
use super::Invite3pid;
ruma_api! {
metadata {
description: "Invite a user to a room.",
method: POST,
name: "invite_user",
path: "/_matrix/client/r0/rooms/:room_id/invite",
rate_limited: true,
requires_authentication: true,
}
request {
/// The room where the user should be invited.
#[ruma_api(path)]
pub room_id: RoomId,
/// The user to invite.
#[ruma_api(body)]
pub recipient: InvitationRecipient,
}
response {}
error: crate::Error
}
/// Distinguishes between invititations by Matrix or third party identifiers.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[serde(untagged)]
pub enum InvitationRecipient {
/// Used to invite user by their Matrix identifer.
UserId {
/// Matrix identifier of user.
user_id: UserId,
},
/// Used to invite user by a third party identifer.
ThirdPartyId(Invite3pid),
}
#[cfg(test)]
mod tests {
use std::convert::TryFrom;
use ruma_identifiers::UserId;
use serde_json::{from_value as from_json_value, json};
use super::InvitationRecipient;
use crate::r0::{membership::Invite3pid, thirdparty::Medium};
#[test]
fn deserialize_invite_by_user_id() {
let incoming =
from_json_value::<InvitationRecipient>(json!({ "user_id": "@carl:example.org" }))
.unwrap();
let user_id = UserId::try_from("@carl:example.org").unwrap();
let recipient = InvitationRecipient::UserId { user_id };
assert_eq!(incoming, recipient);
}
#[test]
fn deserialize_invite_by_3pid() {
let incoming = from_json_value::<InvitationRecipient>(json!({
"id_server": "example.org",
"id_access_token": "abcdefghijklmnop",
"medium": "email",
"address": "carl@example.org"
}))
.unwrap();
let recipient = InvitationRecipient::ThirdPartyId(Invite3pid {
id_server: "example.org".to_string(),
id_access_token: "abcdefghijklmnop".to_string(),
medium: Medium::Email,
address: "carl@example.org".to_string(),
});
assert_eq!(incoming, recipient);
}
}

View File

@ -0,0 +1,35 @@
//! [POST /_matrix/client/r0/rooms/{roomId}/join](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-rooms-roomid-join)
use ruma_api::ruma_api;
use ruma_identifiers::RoomId;
use super::ThirdPartySigned;
ruma_api! {
metadata {
description: "Join a room using its ID.",
method: POST,
name: "join_room_by_id",
path: "/_matrix/client/r0/rooms/:room_id/join",
rate_limited: true,
requires_authentication: true,
}
request {
/// The room where the user should be invited.
#[ruma_api(path)]
pub room_id: RoomId,
/// The signature of a `m.third_party_invite` token to prove that this user owns a third
/// party identity which has been invited to the room.
#[serde(skip_serializing_if = "Option::is_none")]
pub third_party_signed: Option<ThirdPartySigned>,
}
response {
/// The room that the user joined.
pub room_id: RoomId,
}
error: crate::Error
}

View File

@ -0,0 +1,41 @@
//! [POST /_matrix/client/r0/join/{roomIdOrAlias}](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-join-roomidoralias)
use ruma_api::ruma_api;
use ruma_identifiers::{RoomId, RoomIdOrAliasId};
use super::ThirdPartySigned;
ruma_api! {
metadata {
description: "Join a room using its ID or one of its aliases.",
method: POST,
name: "join_room_by_id_or_alias",
path: "/_matrix/client/r0/join/:room_id_or_alias",
rate_limited: true,
requires_authentication: true,
}
request {
/// The room where the user should be invited.
#[ruma_api(path)]
pub room_id_or_alias: RoomIdOrAliasId,
/// The servers to attempt to join the room through. One of the servers
/// must be participating in the room.
#[ruma_api(query)]
#[serde(default)]
pub server_name: Vec<String>,
/// The signature of a `m.third_party_invite` token to prove that this user owns a third
/// party identity which has been invited to the room.
#[serde(skip_serializing_if = "Option::is_none")]
pub third_party_signed: Option<ThirdPartySigned>,
}
response {
/// The room that the user joined.
pub room_id: RoomId,
}
error: crate::Error
}

View File

@ -0,0 +1,44 @@
//! [GET /_matrix/client/r0/rooms/{roomId}/joined_members](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-rooms-roomid-joined-members)
use std::collections::BTreeMap;
use ruma_api::ruma_api;
use ruma_identifiers::{RoomId, UserId};
use serde::{Deserialize, Serialize};
ruma_api! {
metadata {
description: "Get a map of user ids to member info objects for members of the room. Primarily for use in Application Services.",
method: GET,
name: "joined_members",
path: "/_matrix/client/r0/rooms/:room_id/joined_members",
rate_limited: false,
requires_authentication: true,
}
request {
/// The room to get the members of.
#[ruma_api(path)]
pub room_id: RoomId,
}
response {
/// A list of the rooms the user is in, i.e.
/// the ID of each room in which the user has joined membership.
pub joined: BTreeMap<UserId, RoomMember>,
}
error: crate::Error
}
/// Information about a room member.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RoomMember {
/// The display name of the user.
#[serde(skip_serializing_if = "Option::is_none")]
pub display_name: Option<String>,
/// The mxc avatar url of the user.
#[serde(skip_serializing_if = "Option::is_none")]
pub avatar_url: Option<String>,
}

View File

@ -0,0 +1,25 @@
//! [GET /_matrix/client/r0/joined_rooms](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-joined-rooms)
use ruma_api::ruma_api;
use ruma_identifiers::RoomId;
ruma_api! {
metadata {
description: "Get a list of the user's current rooms.",
method: GET,
name: "joined_rooms",
path: "/_matrix/client/r0/joined_rooms",
rate_limited: false,
requires_authentication: true,
}
request {}
response {
/// A list of the rooms the user is in, i.e. the ID of each room in
/// which the user has joined membership.
pub joined_rooms: Vec<RoomId>,
}
error: crate::Error
}

View File

@ -0,0 +1,32 @@
//! [POST /_matrix/client/r0/rooms/{roomId}/kick](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-rooms-roomid-kick)
use ruma_api::ruma_api;
use ruma_identifiers::{RoomId, UserId};
ruma_api! {
metadata {
description: "Kick a user from a room.",
method: POST,
name: "kick_user",
path: "/_matrix/client/r0/rooms/:room_id/kick",
rate_limited: false,
requires_authentication: true,
}
request {
/// The room to kick the user from.
#[ruma_api(path)]
pub room_id: RoomId,
/// The user to kick.
pub user_id: UserId,
/// The reason for kicking the user.
#[serde(skip_serializing_if = "Option::is_none")]
pub reason: Option<String>,
}
response {}
error: crate::Error
}

View File

@ -0,0 +1,25 @@
//! [POST /_matrix/client/r0/rooms/{roomId}/leave](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-rooms-roomid-leave)
use ruma_api::ruma_api;
use ruma_identifiers::RoomId;
ruma_api! {
metadata {
description: "Leave a room.",
method: POST,
name: "leave_room",
path: "/_matrix/client/r0/rooms/:room_id/leave",
rate_limited: true,
requires_authentication: true,
}
request {
/// The room to leave.
#[ruma_api(path)]
pub room_id: RoomId,
}
response {}
error: crate::Error
}

View File

@ -0,0 +1,28 @@
//! [POST /_matrix/client/r0/rooms/{roomId}/unban](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-rooms-roomid-unban)
use ruma_api::ruma_api;
use ruma_identifiers::{RoomId, UserId};
ruma_api! {
metadata {
description: "Unban a user from a room.",
method: POST,
name: "unban_user",
path: "/_matrix/client/r0/rooms/:room_id/unban",
rate_limited: false,
requires_authentication: true,
}
request {
/// The room to unban the user from.
#[ruma_api(path)]
pub room_id: RoomId,
/// The user to unban.
pub user_id: UserId,
}
response {}
error: crate::Error
}

View File

@ -0,0 +1,4 @@
//! Enpoints for sending and receiving messages
pub mod create_message_event;
pub mod get_message_events;

View File

@ -0,0 +1,50 @@
//! [PUT /_matrix/client/r0/rooms/{roomId}/send/{eventType}/{txnId}](https://matrix.org/docs/spec/client_server/r0.6.0#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid)
use ruma_api::ruma_api;
use ruma_events::EventType;
use ruma_identifiers::{EventId, RoomId};
use serde_json::value::RawValue as RawJsonValue;
ruma_api! {
metadata {
description: "Send a message event to a room.",
method: PUT,
name: "create_message_event",
path: "/_matrix/client/r0/rooms/:room_id/send/:event_type/:txn_id",
rate_limited: false,
requires_authentication: true,
}
request {
/// The room to send the event to.
#[ruma_api(path)]
pub room_id: RoomId,
/// The type of event to send.
#[ruma_api(path)]
pub event_type: EventType,
/// 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.
#[ruma_api(path)]
pub txn_id: String,
/// The event's content. The type for this field will be updated in a
/// future release, until then you can create a value using
/// `serde_json::value::to_raw_value`.
#[ruma_api(body)]
pub data: Box<RawJsonValue>,
}
response {
/// A unique identifier for the event.
// This is not declared required in r0.6.0, but that was a bug that has now been fixed:
// https://github.com/matrix-org/matrix-doc/pull/2525
pub event_id: EventId,
}
error: crate::Error
}

View File

@ -0,0 +1,176 @@
//! [GET /_matrix/client/r0/rooms/{roomId}/messages](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-rooms-roomid-messages)
use js_int::UInt;
use ruma_api::ruma_api;
use ruma_events::{
collections::all::{RoomEvent, StateEvent},
EventJson,
};
use ruma_identifiers::RoomId;
use serde::{Deserialize, Serialize};
use crate::r0::filter::RoomEventFilter;
ruma_api! {
metadata {
description: "Get message events for a room.",
method: GET,
name: "get_message_events",
path: "/_matrix/client/r0/rooms/:room_id/messages",
rate_limited: false,
requires_authentication: true,
}
request {
/// The room to get events from.
#[ruma_api(path)]
pub room_id: RoomId,
/// 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.
#[ruma_api(query)]
pub from: String,
/// 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.
#[serde(skip_serializing_if = "Option::is_none")]
#[ruma_api(query)]
pub to: Option<String>,
/// The direction to return events from.
#[ruma_api(query)]
pub dir: Direction,
/// The maximum number of events to return.
///
/// Default: 10.
#[serde(skip_serializing_if = "Option::is_none")]
#[ruma_api(query)]
pub limit: Option<UInt>,
/// A RoomEventFilter to filter returned events with.
#[ruma_api(query)]
#[serde(
with = "ruma_serde::json_string",
default,
skip_serializing_if = "Option::is_none"
)]
pub filter: Option<RoomEventFilter>,
}
response {
/// The token the pagination starts from.
#[serde(skip_serializing_if = "Option::is_none")]
pub start: Option<String>,
/// The token the pagination ends at.
#[serde(skip_serializing_if = "Option::is_none")]
pub end: Option<String>,
/// A list of room events.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub chunk: Vec<EventJson<RoomEvent>>,
/// A list of state events relevant to showing the `chunk`.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub state: Vec<EventJson<StateEvent>>,
}
error: crate::Error
}
/// The direction to return events from.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub enum Direction {
/// Return events backwards in time from the requested `from` token.
#[serde(rename = "b")]
Backward,
/// Return events forwards in time from the requested `from` token.
#[serde(rename = "f")]
Forward,
}
#[cfg(test)]
mod tests {
use super::{Direction, Request};
use std::convert::{TryFrom, TryInto};
use js_int::UInt;
use ruma_identifiers::RoomId;
use crate::r0::filter::{LazyLoadOptions, RoomEventFilter};
#[test]
fn test_serialize_some_room_event_filter() {
let room_id = RoomId::try_from("!roomid:example.org").unwrap();
let filter = RoomEventFilter {
lazy_load_options: LazyLoadOptions::Enabled {
include_redundant_members: true,
},
rooms: Some(vec![room_id.clone()]),
not_rooms: vec!["room".into(), "room2".into(), "room3".into()],
not_types: vec!["type".into()],
..Default::default()
};
let req = Request {
room_id,
from: "token".into(),
to: Some("token2".into()),
dir: Direction::Backward,
limit: Some(UInt::from(0u32)),
filter: Some(filter),
};
let request: http::Request<Vec<u8>> = req.try_into().unwrap();
assert_eq!(
"from=token&to=token2&dir=b&limit=0&filter=%7B%22not_types%22%3A%5B%22type%22%5D%2C%22not_rooms%22%3A%5B%22room%22%2C%22room2%22%2C%22room3%22%5D%2C%22rooms%22%3A%5B%22%21roomid%3Aexample.org%22%5D%2C%22lazy_load_members%22%3Atrue%2C%22include_redundant_members%22%3Atrue%7D",
request.uri().query().unwrap()
);
}
#[test]
fn test_serialize_none_room_event_filter() {
let room_id = RoomId::try_from("!roomid:example.org").unwrap();
let req = Request {
room_id,
from: "token".into(),
to: Some("token2".into()),
dir: Direction::Backward,
limit: Some(UInt::from(0u32)),
filter: None,
};
let request: http::Request<Vec<u8>> = req.try_into().unwrap();
assert_eq!(
"from=token&to=token2&dir=b&limit=0",
request.uri().query().unwrap(),
);
}
#[test]
fn test_serialize_default_room_event_filter() {
let room_id = RoomId::try_from("!roomid:example.org").unwrap();
let req = Request {
room_id,
from: "token".into(),
to: Some("token2".into()),
dir: Direction::Backward,
limit: Some(UInt::from(0u32)),
filter: Some(RoomEventFilter::default()),
};
let request: http::Request<Vec<u8>> = req.try_into().unwrap();
assert_eq!(
"from=token&to=token2&dir=b&limit=0&filter=%7B%7D",
request.uri().query().unwrap(),
);
}
}

View File

@ -0,0 +1,4 @@
//! Endpoints for user presence.
pub mod get_presence;
pub mod set_presence;

View File

@ -0,0 +1,47 @@
//! [GET /_matrix/client/r0/presence/{userId}/status](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-presence-userid-status)
use std::time::Duration;
use ruma_api::ruma_api;
use ruma_events::presence::PresenceState;
use ruma_identifiers::UserId;
ruma_api! {
metadata {
description: "Get presence status for this user.",
method: GET,
name: "get_presence",
path: "/_matrix/client/r0/presence/:user_id/status",
rate_limited: false,
requires_authentication: true,
}
request {
/// The user whose presence state will be retrieved.
#[ruma_api(path)]
pub user_id: UserId,
}
response {
/// The state message for this user if one was set.
#[serde(skip_serializing_if = "Option::is_none")]
pub status_msg: Option<String>,
/// Whether or not the user is currently active.
#[serde(skip_serializing_if = "Option::is_none")]
pub currently_active: Option<bool>,
/// The length of time in milliseconds since an action was performed by the user.
#[serde(
with = "ruma_serde::duration::opt_ms",
default,
skip_serializing_if = "Option::is_none",
)]
pub last_active_ago: Option<Duration>,
/// The user's presence state.
pub presence: PresenceState,
}
error: crate::Error
}

View File

@ -0,0 +1,33 @@
//! [PUT /_matrix/client/r0/presence/{userId}/status](https://matrix.org/docs/spec/client_server/r0.6.0#put-matrix-client-r0-presence-userid-status)
use ruma_api::ruma_api;
use ruma_events::presence::PresenceState;
use ruma_identifiers::UserId;
ruma_api! {
metadata {
description: "Set presence status for this user.",
method: PUT,
name: "set_presence",
path: "/_matrix/client/r0/presence/:user_id/status",
rate_limited: true,
requires_authentication: true,
}
request {
/// The user whose presence state will be updated.
#[ruma_api(path)]
pub user_id: UserId,
/// The new presence state.
pub presence: PresenceState,
/// The status message to attach to this state.
#[serde(skip_serializing_if = "Option::is_none")]
pub status_msg: Option<String>,
}
response {}
error: crate::Error
}

View File

@ -0,0 +1,7 @@
//! Endpoints for user profiles.
pub mod get_avatar_url;
pub mod get_display_name;
pub mod get_profile;
pub mod set_avatar_url;
pub mod set_display_name;

View File

@ -0,0 +1,29 @@
//! [GET /_matrix/client/r0/profile/{userId}/avatar_url](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-profile-userid-avatar-url)
use ruma_api::ruma_api;
use ruma_identifiers::UserId;
ruma_api! {
metadata {
description: "Get the avatar URL of a user.",
method: GET,
name: "get_avatar_url",
path: "/_matrix/client/r0/profile/:user_id/avatar_url",
rate_limited: false,
requires_authentication: false,
}
request {
/// The user whose avatar URL will be retrieved.
#[ruma_api(path)]
pub user_id: UserId
}
response {
/// The user's avatar URL, if set.
#[serde(skip_serializing_if = "Option::is_none")]
pub avatar_url: Option<String>
}
error: crate::Error
}

View File

@ -0,0 +1,29 @@
//! [GET /_matrix/client/r0/profile/{userId}/displayname](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-profile-userid-displayname)
use ruma_api::ruma_api;
use ruma_identifiers::UserId;
ruma_api! {
metadata {
description: "Get the display name of a user.",
method: GET,
name: "get_display_name",
path: "/_matrix/client/r0/profile/:user_id/displayname",
rate_limited: false,
requires_authentication: false,
}
request {
/// The user whose display name will be retrieved.
#[ruma_api(path)]
pub user_id: UserId
}
response {
/// The user's display name, if set.
#[serde(skip_serializing_if = "Option::is_none")]
pub displayname: Option<String>
}
error: crate::Error
}

View File

@ -0,0 +1,33 @@
//! [GET /_matrix/client/r0/profile/{userId}](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-profile-userid)
use ruma_api::ruma_api;
use ruma_identifiers::UserId;
ruma_api! {
metadata {
description: "Get all profile information of an user.",
method: GET,
name: "get_profile",
path: "/_matrix/client/r0/profile/:user_id",
rate_limited: false,
requires_authentication: false,
}
request {
/// The user whose profile will be retrieved.
#[ruma_api(path)]
pub user_id: UserId,
}
response {
/// The user's avatar URL, if set.
#[serde(skip_serializing_if = "Option::is_none")]
pub avatar_url: Option<String>,
/// The user's display name, if set.
#[serde(skip_serializing_if = "Option::is_none")]
pub displayname: Option<String>,
}
error: crate::Error
}

View File

@ -0,0 +1,30 @@
//! [PUT /_matrix/client/r0/profile/{userId}/avatar_url](https://matrix.org/docs/spec/client_server/r0.6.0#put-matrix-client-r0-profile-userid-avatar-url)
use ruma_api::ruma_api;
use ruma_identifiers::UserId;
ruma_api! {
metadata {
description: "Set the avatar URL of the user.",
method: PUT,
name: "set_avatar_url",
path: "/_matrix/client/r0/profile/:user_id/avatar_url",
rate_limited: true,
requires_authentication: true,
}
request {
/// The user whose avatar URL will be set.
#[ruma_api(path)]
pub user_id: UserId,
/// The new avatar URL for the user.
///
/// `None` is used to unset the avatar.
pub avatar_url: Option<String>,
}
response {}
error: crate::Error
}

View File

@ -0,0 +1,29 @@
//! [PUT /_matrix/client/r0/profile/{userId}/displayname](https://matrix.org/docs/spec/client_server/r0.6.0#put-matrix-client-r0-profile-userid-displayname)
use ruma_api::ruma_api;
use ruma_identifiers::UserId;
ruma_api! {
metadata {
description: "Set the display name of the user.",
method: PUT,
name: "set_display_name",
path: "/_matrix/client/r0/profile/:user_id/displayname",
rate_limited: true,
requires_authentication: true,
}
request {
/// The user whose display name will be set.
#[ruma_api(path)]
pub user_id: UserId,
/// The new display name for the user.
#[serde(skip_serializing_if = "Option::is_none")]
pub displayname: Option<String>,
}
response {}
error: crate::Error
}

View File

@ -0,0 +1,140 @@
//! Endpoints for push notifications.
use std::convert::TryFrom;
use serde::{Deserialize, Serialize};
use strum::{Display, EnumString};
pub mod delete_pushrule;
pub mod get_notifications;
pub mod get_pushers;
pub mod get_pushrule;
pub mod get_pushrule_actions;
pub mod get_pushrule_enabled;
pub mod get_pushrules_all;
pub mod get_pushrules_global_scope;
pub mod set_pusher;
pub mod set_pushrule;
pub mod set_pushrule_actions;
pub mod set_pushrule_enabled;
pub use ruma_common::push::Action;
pub use ruma_events::push_rules::PushCondition;
/// The kinds of push rules that are available
#[derive(
Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Display, EnumString,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum RuleKind {
/// User-configured rules that override all other kinds
Override,
/// Lowest priority user-defined rules
Underride,
/// Sender-specific rules
Sender,
/// Room-specific rules
Room,
/// Content-specific rules
Content,
}
impl TryFrom<&'_ str> for RuleKind {
type Error = strum::ParseError;
fn try_from(s: &str) -> Result<Self, Self::Error> {
s.parse()
}
}
/// A push rule
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PushRule {
/// The actions to perform when this rule is matched.
pub actions: Vec<Action>,
/// Whether this is a default rule, or has been set explicitly.
pub default: bool,
/// Whether the push rule is enabled or not.
pub enabled: bool,
/// The ID of this rule.
pub rule_id: String,
/// 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.
#[serde(skip_serializing_if = "Option::is_none")]
pub conditions: Option<Vec<PushCondition>>,
/// The glob-style pattern to match against. Only applicable to content rules.
#[serde(skip_serializing_if = "Option::is_none")]
pub pattern: Option<String>,
}
/// Defines a pusher
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Pusher {
/// This is a unique identifier for this pusher. Max length, 512 bytes.
pub pushkey: String,
/// The kind of the pusher. If set to None in a call to set_pusher, this
/// will delete the pusher
pub kind: Option<PusherKind>,
/// This is a reverse-DNS style identifier for the application. Max length, 64 chars.
pub app_id: String,
/// A string that will allow the user to identify what application owns this pusher.
pub app_display_name: String,
/// A string that will allow the user to identify what device owns this pusher.
pub device_display_name: String,
/// This string determines which set of device specific rules this pusher executes.
#[serde(skip_serializing_if = "Option::is_none")]
pub profile_tag: Option<String>,
/// The preferred language for receiving notifications (e.g. 'en' or 'en-US')
pub lang: String,
/// Information for the pusher implementation itself.
pub data: PusherData,
}
/// Which kind a pusher is
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PusherKind {
/// A pusher that sends HTTP pokes.
Http,
/// A pusher that emails the user with unread notifications.
Email,
}
/// Information for the pusher implementation itself.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PusherData {
/// Required if the pusher's kind is http. The URL to use to send notifications to.
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
/// The format to use when sending notifications to the Push Gateway.
#[serde(skip_serializing_if = "Option::is_none")]
pub format: Option<PushFormat>,
}
/// A special format that the homeserver should use when sending notifications to a Push Gateway.
/// Currently, only "event_id_only" is supported as of [Push Gateway API r0.1.1](https://matrix.org/docs/spec/push_gateway/r0.1.1#homeserver-behaviour)
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PushFormat {
/// Require the homeserver to only send a reduced set of fields in the push.
EventIdOnly,
}

View File

@ -0,0 +1,34 @@
//! [DELETE /_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}](https://matrix.org/docs/spec/client_server/r0.6.0#delete-matrix-client-r0-pushrules-scope-kind-ruleid)
use ruma_api::ruma_api;
use super::RuleKind;
ruma_api! {
metadata {
description: "This endpoint removes the push rule defined in the path.",
method: DELETE,
name: "delete_pushrule",
path: "/_matrix/client/r0/pushrules/:scope/:kind/:rule_id",
rate_limited: false,
requires_authentication: true,
}
request {
/// The scope to delete from. 'global' to specify global rules.
#[ruma_api(path)]
pub scope: String,
/// The kind of rule
#[ruma_api(path)]
pub kind: RuleKind,
/// The identifier for the rule.
#[ruma_api(path)]
pub rule_id: String,
}
response {}
error: crate::Error
}

Some files were not shown because too many files have changed in this diff Show More