client-api: Use an enum to construct set_pushrule's Request
This commit is contained in:
parent
f31530e02c
commit
aa2e905ce3
@ -12,6 +12,7 @@ Breaking changes:
|
|||||||
* Remove `push::set_pusher::v3::Pusher` and use the common type instead
|
* Remove `push::set_pusher::v3::Pusher` and use the common type instead
|
||||||
* Make `push::PusherKind` contain the pusher's `data`
|
* Make `push::PusherKind` contain the pusher's `data`
|
||||||
* Use an enum for the `scope` of the `push` endpoints
|
* Use an enum for the `scope` of the `push` endpoints
|
||||||
|
* Use `NewPushRule` to construct a `push::set_pushrule::v3::Request`
|
||||||
|
|
||||||
Improvements:
|
Improvements:
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ rustdoc-args = ["--cfg", "docsrs"]
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
compat = []
|
compat = []
|
||||||
unstable-exhaustive-types = []
|
unstable-exhaustive-types = ["ruma-common/unstable-exhaustive-types"]
|
||||||
unstable-msc2246 = []
|
unstable-msc2246 = []
|
||||||
unstable-msc2666 = []
|
unstable-msc2666 = []
|
||||||
unstable-msc2448 = []
|
unstable-msc2448 = []
|
||||||
|
@ -7,14 +7,19 @@ pub mod v3 {
|
|||||||
|
|
||||||
use ruma_common::{
|
use ruma_common::{
|
||||||
api::ruma_api,
|
api::ruma_api,
|
||||||
push::{Action, PushCondition},
|
push::{
|
||||||
|
Action, NewConditionalPushRule, NewPatternedPushRule, NewPushRule, NewSimplePushRule,
|
||||||
|
PushCondition,
|
||||||
|
},
|
||||||
|
serde::Incoming,
|
||||||
};
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::push::{RuleKind, RuleScope};
|
use crate::push::RuleScope;
|
||||||
|
|
||||||
ruma_api! {
|
ruma_api! {
|
||||||
metadata: {
|
metadata: {
|
||||||
description: "This endpoint allows the creation, modification and deletion of pushers for this user ID.",
|
description: "This endpoint allows the creation and modification of push rules for this user ID.",
|
||||||
method: PUT,
|
method: PUT,
|
||||||
name: "set_pushrule",
|
name: "set_pushrule",
|
||||||
r0_path: "/_matrix/client/r0/pushrules/:scope/:kind/:rule_id",
|
r0_path: "/_matrix/client/r0/pushrules/:scope/:kind/:rule_id",
|
||||||
@ -24,71 +29,38 @@ pub mod v3 {
|
|||||||
added: 1.0,
|
added: 1.0,
|
||||||
}
|
}
|
||||||
|
|
||||||
request: {
|
|
||||||
/// The scope to set the rule in.
|
|
||||||
#[ruma_api(path)]
|
|
||||||
pub scope: RuleScope,
|
|
||||||
|
|
||||||
/// The kind of rule
|
|
||||||
#[ruma_api(path)]
|
|
||||||
pub kind: RuleKind,
|
|
||||||
|
|
||||||
/// The identifier for the rule.
|
|
||||||
#[ruma_api(path)]
|
|
||||||
pub rule_id: &'a str,
|
|
||||||
|
|
||||||
/// Use 'before' with a rule_id as its value to make the new rule the next-most important
|
|
||||||
/// rule with respect to the given user defined rule.
|
|
||||||
#[ruma_api(query)]
|
|
||||||
pub before: Option<&'a str>,
|
|
||||||
|
|
||||||
/// This makes the new rule the next-less important rule relative to the given user defined
|
|
||||||
/// rule.
|
|
||||||
#[ruma_api(query)]
|
|
||||||
pub after: Option<&'a str>,
|
|
||||||
|
|
||||||
/// The actions to perform when this rule is matched.
|
|
||||||
pub actions: &'a [Action],
|
|
||||||
|
|
||||||
/// 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, empty Vec otherwise.
|
|
||||||
#[serde(default, skip_serializing_if = "<[_]>::is_empty")]
|
|
||||||
pub conditions: &'a [PushCondition],
|
|
||||||
|
|
||||||
/// The glob-style pattern to match against.
|
|
||||||
///
|
|
||||||
/// Only applicable to content rules.
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub pattern: Option<&'a str>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
response: {}
|
response: {}
|
||||||
|
|
||||||
error: crate::Error
|
error: crate::Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Data for a request to the `set_pushrule` API endpoint.
|
||||||
|
///
|
||||||
|
/// Create or update a push rule.
|
||||||
|
#[derive(Clone, Debug, Incoming)]
|
||||||
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||||
|
#[incoming_derive(!Deserialize)]
|
||||||
|
pub struct Request<'a> {
|
||||||
|
/// The scope to set the rule in.
|
||||||
|
pub scope: RuleScope,
|
||||||
|
|
||||||
|
/// The rule.
|
||||||
|
pub rule: NewPushRule,
|
||||||
|
|
||||||
|
/// Use 'before' with a rule_id as its value to make the new rule the next-most important
|
||||||
|
/// rule with respect to the given user defined rule.
|
||||||
|
pub before: Option<&'a str>,
|
||||||
|
|
||||||
|
/// This makes the new rule the next-less important rule relative to the given user defined
|
||||||
|
/// rule.
|
||||||
|
pub after: Option<&'a str>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Request<'a> {
|
impl<'a> Request<'a> {
|
||||||
/// Creates a new `Request` with the given scope, rule kind, rule ID and actions.
|
/// Creates a new `Request` with the given scope and rule.
|
||||||
pub fn new(
|
pub fn new(scope: RuleScope, rule: NewPushRule) -> Self {
|
||||||
scope: RuleScope,
|
Self { scope, rule, before: None, after: None }
|
||||||
kind: RuleKind,
|
|
||||||
rule_id: &'a str,
|
|
||||||
actions: &'a [Action],
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
scope,
|
|
||||||
kind,
|
|
||||||
rule_id,
|
|
||||||
before: None,
|
|
||||||
after: None,
|
|
||||||
actions,
|
|
||||||
conditions: &[],
|
|
||||||
pattern: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,4 +70,193 @@ pub mod v3 {
|
|||||||
Self {}
|
Self {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "client")]
|
||||||
|
impl<'a> ruma_common::api::OutgoingRequest for Request<'a> {
|
||||||
|
type EndpointError = crate::Error;
|
||||||
|
type IncomingResponse = Response;
|
||||||
|
|
||||||
|
const METADATA: ruma_common::api::Metadata = METADATA;
|
||||||
|
|
||||||
|
fn try_into_http_request<T: Default + bytes::BufMut>(
|
||||||
|
self,
|
||||||
|
base_url: &str,
|
||||||
|
access_token: ruma_common::api::SendAccessToken<'_>,
|
||||||
|
considering_versions: &[ruma_common::api::MatrixVersion],
|
||||||
|
) -> Result<http::Request<T>, ruma_common::api::error::IntoHttpError> {
|
||||||
|
use http::header;
|
||||||
|
use ruma_common::serde::urlencoded;
|
||||||
|
|
||||||
|
let query_string =
|
||||||
|
urlencoded::to_string(RequestQuery { before: self.before, after: self.after })?;
|
||||||
|
|
||||||
|
let url = METADATA.make_endpoint_url(
|
||||||
|
considering_versions,
|
||||||
|
base_url,
|
||||||
|
&[&self.scope, &self.rule.kind(), &self.rule.rule_id()],
|
||||||
|
Some(&query_string),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let body: RequestBody = self.rule.into();
|
||||||
|
|
||||||
|
http::Request::builder()
|
||||||
|
.method(http::Method::GET)
|
||||||
|
.uri(url)
|
||||||
|
.header(header::CONTENT_TYPE, "application/json")
|
||||||
|
.header(
|
||||||
|
header::AUTHORIZATION,
|
||||||
|
format!(
|
||||||
|
"Bearer {}",
|
||||||
|
access_token
|
||||||
|
.get_required_for_endpoint()
|
||||||
|
.ok_or(ruma_common::api::error::IntoHttpError::NeedsAuthentication)?,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.body(ruma_common::serde::json_to_buf(&body)?)
|
||||||
|
.map_err(Into::into)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
impl ruma_common::api::IncomingRequest for IncomingRequest {
|
||||||
|
type EndpointError = crate::Error;
|
||||||
|
type OutgoingResponse = Response;
|
||||||
|
|
||||||
|
const METADATA: ruma_common::api::Metadata = METADATA;
|
||||||
|
|
||||||
|
fn try_from_http_request<B, S>(
|
||||||
|
request: http::Request<B>,
|
||||||
|
path_args: &[S],
|
||||||
|
) -> Result<Self, ruma_common::api::error::FromHttpRequestError>
|
||||||
|
where
|
||||||
|
B: AsRef<[u8]>,
|
||||||
|
S: AsRef<str>,
|
||||||
|
{
|
||||||
|
// Exhaustive enum to fail deserialization on unknown variants.
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
enum RuleKind {
|
||||||
|
Override,
|
||||||
|
Underride,
|
||||||
|
Sender,
|
||||||
|
Room,
|
||||||
|
Content,
|
||||||
|
}
|
||||||
|
|
||||||
|
let (scope, kind, rule_id): (RuleScope, RuleKind, String) =
|
||||||
|
serde::Deserialize::deserialize(serde::de::value::SeqDeserializer::<
|
||||||
|
_,
|
||||||
|
serde::de::value::Error,
|
||||||
|
>::new(
|
||||||
|
path_args.iter().map(::std::convert::AsRef::as_ref),
|
||||||
|
))?;
|
||||||
|
|
||||||
|
let IncomingRequestQuery { before, after } =
|
||||||
|
ruma_common::serde::urlencoded::from_str(request.uri().query().unwrap_or(""))?;
|
||||||
|
|
||||||
|
let rule = match kind {
|
||||||
|
RuleKind::Override => {
|
||||||
|
let ConditionalRequestBody { actions, conditions } =
|
||||||
|
serde_json::from_slice(request.body().as_ref())?;
|
||||||
|
NewPushRule::Override(NewConditionalPushRule::new(rule_id, conditions, actions))
|
||||||
|
}
|
||||||
|
RuleKind::Underride => {
|
||||||
|
let ConditionalRequestBody { actions, conditions } =
|
||||||
|
serde_json::from_slice(request.body().as_ref())?;
|
||||||
|
NewPushRule::Underride(NewConditionalPushRule::new(
|
||||||
|
rule_id, conditions, actions,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
RuleKind::Sender => {
|
||||||
|
let SimpleRequestBody { actions } =
|
||||||
|
serde_json::from_slice(request.body().as_ref())?;
|
||||||
|
NewPushRule::Sender(NewSimplePushRule::new(rule_id, actions))
|
||||||
|
}
|
||||||
|
RuleKind::Room => {
|
||||||
|
let SimpleRequestBody { actions } =
|
||||||
|
serde_json::from_slice(request.body().as_ref())?;
|
||||||
|
NewPushRule::Room(NewSimplePushRule::new(rule_id, actions))
|
||||||
|
}
|
||||||
|
RuleKind::Content => {
|
||||||
|
let PatternedRequestBody { actions, pattern } =
|
||||||
|
serde_json::from_slice(request.body().as_ref())?;
|
||||||
|
NewPushRule::Content(NewPatternedPushRule::new(rule_id, pattern, actions))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self { scope, rule, before, after })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
struct RequestQuery<'a> {
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
before: Option<&'a str>,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
after: Option<&'a str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct IncomingRequestQuery {
|
||||||
|
before: Option<String>,
|
||||||
|
|
||||||
|
after: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum RequestBody {
|
||||||
|
Simple(SimpleRequestBody),
|
||||||
|
|
||||||
|
Patterned(PatternedRequestBody),
|
||||||
|
|
||||||
|
Conditional(ConditionalRequestBody),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
struct SimpleRequestBody {
|
||||||
|
actions: Vec<Action>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
struct PatternedRequestBody {
|
||||||
|
actions: Vec<Action>,
|
||||||
|
|
||||||
|
pattern: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
struct ConditionalRequestBody {
|
||||||
|
actions: Vec<Action>,
|
||||||
|
|
||||||
|
conditions: Vec<PushCondition>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<NewPushRule> for RequestBody {
|
||||||
|
fn from(rule: NewPushRule) -> Self {
|
||||||
|
match rule {
|
||||||
|
NewPushRule::Override(r) => RequestBody::Conditional(ConditionalRequestBody {
|
||||||
|
actions: r.actions,
|
||||||
|
conditions: r.conditions,
|
||||||
|
}),
|
||||||
|
NewPushRule::Content(r) => RequestBody::Patterned(PatternedRequestBody {
|
||||||
|
actions: r.actions,
|
||||||
|
pattern: r.pattern,
|
||||||
|
}),
|
||||||
|
NewPushRule::Room(r) => {
|
||||||
|
RequestBody::Simple(SimpleRequestBody { actions: r.actions })
|
||||||
|
}
|
||||||
|
NewPushRule::Sender(r) => {
|
||||||
|
RequestBody::Simple(SimpleRequestBody { actions: r.actions })
|
||||||
|
}
|
||||||
|
NewPushRule::Underride(r) => RequestBody::Conditional(ConditionalRequestBody {
|
||||||
|
actions: r.actions,
|
||||||
|
conditions: r.conditions,
|
||||||
|
}),
|
||||||
|
#[cfg(not(feature = "unstable-exhaustive-types"))]
|
||||||
|
_ => unreachable!("variant added to NewPushRule not covered by RequestBody"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -468,6 +468,116 @@ pub enum RuleKind {
|
|||||||
_Custom(PrivOwnedStr),
|
_Custom(PrivOwnedStr),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A push rule to update or create.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||||
|
pub enum NewPushRule {
|
||||||
|
/// Rules that override all other kinds.
|
||||||
|
Override(NewConditionalPushRule),
|
||||||
|
|
||||||
|
/// Content-specific rules.
|
||||||
|
Content(NewPatternedPushRule),
|
||||||
|
|
||||||
|
/// Room-specific rules.
|
||||||
|
Room(NewSimplePushRule),
|
||||||
|
|
||||||
|
/// Sender-specific rules.
|
||||||
|
Sender(NewSimplePushRule),
|
||||||
|
|
||||||
|
/// Lowest priority rules.
|
||||||
|
Underride(NewConditionalPushRule),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NewPushRule {
|
||||||
|
/// The kind of this `NewPushRule`.
|
||||||
|
pub fn kind(&self) -> RuleKind {
|
||||||
|
match self {
|
||||||
|
NewPushRule::Override(_) => RuleKind::Override,
|
||||||
|
NewPushRule::Content(_) => RuleKind::Content,
|
||||||
|
NewPushRule::Room(_) => RuleKind::Room,
|
||||||
|
NewPushRule::Sender(_) => RuleKind::Sender,
|
||||||
|
NewPushRule::Underride(_) => RuleKind::Underride,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The ID of this `NewPushRule`.
|
||||||
|
pub fn rule_id(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
NewPushRule::Override(r) => &r.rule_id,
|
||||||
|
NewPushRule::Content(r) => &r.rule_id,
|
||||||
|
NewPushRule::Room(r) => &r.rule_id,
|
||||||
|
NewPushRule::Sender(r) => &r.rule_id,
|
||||||
|
NewPushRule::Underride(r) => &r.rule_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A simple push rule to update or create.
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||||
|
pub struct NewSimplePushRule {
|
||||||
|
/// The ID of this rule.
|
||||||
|
pub rule_id: String,
|
||||||
|
|
||||||
|
/// Actions to determine if and how a notification is delivered for events matching this
|
||||||
|
/// rule.
|
||||||
|
pub actions: Vec<Action>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NewSimplePushRule {
|
||||||
|
/// Creates a `NewSimplePushRule` with the given ID and actions.
|
||||||
|
pub fn new(rule_id: String, actions: Vec<Action>) -> Self {
|
||||||
|
Self { rule_id, actions }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A patterned push rule to update or create.
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||||
|
pub struct NewPatternedPushRule {
|
||||||
|
/// The ID of this rule.
|
||||||
|
pub rule_id: String,
|
||||||
|
|
||||||
|
/// The glob-style pattern to match against.
|
||||||
|
pub pattern: String,
|
||||||
|
|
||||||
|
/// Actions to determine if and how a notification is delivered for events matching this
|
||||||
|
/// rule.
|
||||||
|
pub actions: Vec<Action>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NewPatternedPushRule {
|
||||||
|
/// Creates a `NewPatternedPushRule` with the given ID, pattern and actions.
|
||||||
|
pub fn new(rule_id: String, pattern: String, actions: Vec<Action>) -> Self {
|
||||||
|
Self { rule_id, pattern, actions }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A conditional push rule to update or create.
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||||
|
pub struct NewConditionalPushRule {
|
||||||
|
/// 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.
|
||||||
|
pub conditions: Vec<PushCondition>,
|
||||||
|
|
||||||
|
/// Actions to determine if and how a notification is delivered for events matching this
|
||||||
|
/// rule.
|
||||||
|
pub actions: Vec<Action>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NewConditionalPushRule {
|
||||||
|
/// Creates a `NewConditionalPushRule` with the given ID, conditions and actions.
|
||||||
|
pub fn new(rule_id: String, conditions: Vec<PushCondition>, actions: Vec<Action>) -> Self {
|
||||||
|
Self { rule_id, conditions, actions }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user