1pub mod v3 {
6 use ruma_common::{
11 api::{auth_scheme::AccessToken, response},
12 metadata,
13 push::{Action, NewPushRule, PushCondition},
14 };
15
16 metadata! {
17 method: PUT,
18 rate_limited: true,
19 authentication: AccessToken,
20 history: {
21 1.0 => "/_matrix/client/r0/pushrules/global/{kind}/{rule_id}",
22 1.1 => "/_matrix/client/v3/pushrules/global/{kind}/{rule_id}",
23 }
24 }
25
26 #[derive(Clone, Debug)]
28 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
29 pub struct Request {
30 pub rule: NewPushRule,
32
33 pub before: Option<String>,
36
37 pub after: Option<String>,
40 }
41
42 #[response(error = crate::Error)]
44 #[derive(Default)]
45 pub struct Response {}
46
47 impl Request {
48 pub fn new(rule: NewPushRule) -> Self {
50 Self { rule, before: None, after: None }
51 }
52 }
53
54 impl Response {
55 pub fn new() -> Self {
57 Self {}
58 }
59 }
60
61 #[cfg(feature = "client")]
62 impl ruma_common::api::OutgoingRequest for Request {
63 type EndpointError = crate::Error;
64 type IncomingResponse = Response;
65
66 fn try_into_http_request<T: Default + bytes::BufMut + AsRef<[u8]>>(
67 self,
68 base_url: &str,
69 access_token: ruma_common::api::auth_scheme::SendAccessToken<'_>,
70 considering: std::borrow::Cow<'_, ruma_common::api::SupportedVersions>,
71 ) -> Result<http::Request<T>, ruma_common::api::error::IntoHttpError> {
72 use ruma_common::api::{Metadata, auth_scheme::AuthScheme};
73
74 fn serialize_rule<T: Default + bytes::BufMut>(
75 rule: NewPushRule,
76 ) -> serde_json::Result<T> {
77 match rule {
78 NewPushRule::Override(r) | NewPushRule::Underride(r) => {
79 let body =
80 ConditionalRequestBody { actions: r.actions, conditions: r.conditions };
81 ruma_common::serde::json_to_buf(&body)
82 }
83 NewPushRule::Content(r) => {
84 let body = PatternedRequestBody { actions: r.actions, pattern: r.pattern };
85 ruma_common::serde::json_to_buf(&body)
86 }
87 NewPushRule::Room(r) => {
88 let body = SimpleRequestBody { actions: r.actions };
89 ruma_common::serde::json_to_buf(&body)
90 }
91 NewPushRule::Sender(r) => {
92 let body = SimpleRequestBody { actions: r.actions };
93 ruma_common::serde::json_to_buf(&body)
94 }
95 #[cfg(not(ruma_unstable_exhaustive_types))]
96 _ => unreachable!(
97 "variant added to NewPushRule not serializable to request body"
98 ),
99 }
100 }
101
102 let query_string = serde_html_form::to_string(RequestQuery {
103 before: self.before,
104 after: self.after,
105 })?;
106
107 let url = Self::make_endpoint_url(
108 considering,
109 base_url,
110 &[&self.rule.kind(), &self.rule.rule_id()],
111 &query_string,
112 )?;
113
114 let mut http_request = http::Request::builder()
115 .method(Self::METHOD)
116 .uri(url)
117 .header(http::header::CONTENT_TYPE, ruma_common::http_headers::APPLICATION_JSON)
118 .body(serialize_rule(self.rule)?)?;
119
120 Self::Authentication::add_authentication(&mut http_request, access_token).map_err(
121 |error| ruma_common::api::error::IntoHttpError::Authentication(error.into()),
122 )?;
123
124 Ok(http_request)
125 }
126 }
127
128 #[cfg(feature = "server")]
129 impl ruma_common::api::IncomingRequest for Request {
130 type EndpointError = crate::Error;
131 type OutgoingResponse = Response;
132
133 fn try_from_http_request<B, S>(
134 request: http::Request<B>,
135 path_args: &[S],
136 ) -> Result<Self, ruma_common::api::error::FromHttpRequestError>
137 where
138 B: AsRef<[u8]>,
139 S: AsRef<str>,
140 {
141 use ruma_common::push::{
142 NewConditionalPushRule, NewPatternedPushRule, NewSimplePushRule,
143 };
144
145 #[derive(Debug, serde::Deserialize)]
147 #[serde(rename_all = "lowercase")]
148 enum RuleKind {
149 Override,
150 Underride,
151 Sender,
152 Room,
153 Content,
154 }
155
156 Self::check_request_method(request.method())?;
157
158 let (kind, rule_id): (RuleKind, String) =
159 serde::Deserialize::deserialize(serde::de::value::SeqDeserializer::<
160 _,
161 serde::de::value::Error,
162 >::new(
163 path_args.iter().map(::std::convert::AsRef::as_ref),
164 ))?;
165
166 let RequestQuery { before, after } =
167 serde_html_form::from_str(request.uri().query().unwrap_or(""))?;
168
169 let rule = match kind {
170 RuleKind::Override => {
171 let ConditionalRequestBody { actions, conditions } =
172 serde_json::from_slice(request.body().as_ref())?;
173 NewPushRule::Override(NewConditionalPushRule::new(rule_id, conditions, actions))
174 }
175 RuleKind::Underride => {
176 let ConditionalRequestBody { actions, conditions } =
177 serde_json::from_slice(request.body().as_ref())?;
178 NewPushRule::Underride(NewConditionalPushRule::new(
179 rule_id, conditions, actions,
180 ))
181 }
182 RuleKind::Sender => {
183 let SimpleRequestBody { actions } =
184 serde_json::from_slice(request.body().as_ref())?;
185 let rule_id = rule_id.try_into()?;
186 NewPushRule::Sender(NewSimplePushRule::new(rule_id, actions))
187 }
188 RuleKind::Room => {
189 let SimpleRequestBody { actions } =
190 serde_json::from_slice(request.body().as_ref())?;
191 let rule_id = rule_id.try_into()?;
192 NewPushRule::Room(NewSimplePushRule::new(rule_id, actions))
193 }
194 RuleKind::Content => {
195 let PatternedRequestBody { actions, pattern } =
196 serde_json::from_slice(request.body().as_ref())?;
197 NewPushRule::Content(NewPatternedPushRule::new(rule_id, pattern, actions))
198 }
199 };
200
201 Ok(Self { rule, before, after })
202 }
203 }
204
205 #[derive(Debug)]
206 #[cfg_attr(feature = "client", derive(serde::Serialize))]
207 #[cfg_attr(feature = "server", derive(serde::Deserialize))]
208 struct RequestQuery {
209 #[serde(skip_serializing_if = "Option::is_none")]
210 before: Option<String>,
211
212 #[serde(skip_serializing_if = "Option::is_none")]
213 after: Option<String>,
214 }
215
216 #[derive(Debug)]
217 #[cfg_attr(feature = "client", derive(serde::Serialize))]
218 #[cfg_attr(feature = "server", derive(serde::Deserialize))]
219 struct SimpleRequestBody {
220 actions: Vec<Action>,
221 }
222
223 #[derive(Debug)]
224 #[cfg_attr(feature = "client", derive(serde::Serialize))]
225 #[cfg_attr(feature = "server", derive(serde::Deserialize))]
226 struct PatternedRequestBody {
227 actions: Vec<Action>,
228
229 pattern: String,
230 }
231
232 #[derive(Debug)]
233 #[cfg_attr(feature = "client", derive(serde::Serialize))]
234 #[cfg_attr(feature = "server", derive(serde::Deserialize))]
235 struct ConditionalRequestBody {
236 actions: Vec<Action>,
237
238 conditions: Vec<PushCondition>,
239 }
240}