1pub mod v3 {
6 use ruma_common::{
11 api::{auth_scheme::AccessToken, error::Error, 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]
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 #[doc(hidden)]
62 #[cfg_attr(not(feature = "client"), expect(dead_code))]
64 pub struct RequestBody(NewPushRule);
65
66 #[cfg(feature = "client")]
67 impl ruma_common::api::OutgoingBody for RequestBody {
68 type Error = serde_json::Error;
69
70 fn try_into_buf<T: Default + bytes::BufMut + AsRef<[u8]>>(self) -> serde_json::Result<T> {
71 match self.0 {
72 NewPushRule::Override(r) | NewPushRule::Underride(r) => {
73 let body =
74 ConditionalRequestBody { actions: r.actions, conditions: r.conditions };
75 ruma_common::serde::json_to_buf(&body)
76 }
77 NewPushRule::Content(r) => {
78 let body = PatternedRequestBody { actions: r.actions, pattern: r.pattern };
79 ruma_common::serde::json_to_buf(&body)
80 }
81 NewPushRule::Room(r) => {
82 let body = SimpleRequestBody { actions: r.actions };
83 ruma_common::serde::json_to_buf(&body)
84 }
85 NewPushRule::Sender(r) => {
86 let body = SimpleRequestBody { actions: r.actions };
87 ruma_common::serde::json_to_buf(&body)
88 }
89 #[cfg(not(ruma_unstable_exhaustive_types))]
90 _ => unreachable!("variant added to NewPushRule not serializable to request body"),
91 }
92 }
93 }
94
95 #[cfg(feature = "client")]
96 impl ruma_common::api::OutgoingRequest for Request {
97 type Body = RequestBody;
98 type EndpointError = Error;
99 type IncomingResponse = Response;
100
101 fn try_into_http_request_inner(
102 self,
103 base_url: &str,
104 considering: std::borrow::Cow<'_, ruma_common::api::SupportedVersions>,
105 ) -> Result<http::Request<RequestBody>, ruma_common::api::error::IntoHttpError> {
106 use ruma_common::api::Metadata;
107
108 let query_string = serde_html_form::to_string(RequestQuery {
109 before: self.before,
110 after: self.after,
111 })?;
112
113 let url = Self::make_endpoint_url(
114 considering,
115 base_url,
116 &[&self.rule.kind(), &self.rule.rule_id()],
117 &query_string,
118 )?;
119
120 let http_request = http::Request::builder()
121 .method(Self::METHOD)
122 .uri(url)
123 .header(http::header::CONTENT_TYPE, ruma_common::http_headers::APPLICATION_JSON)
124 .body(RequestBody(self.rule))?;
125
126 Ok(http_request)
127 }
128 }
129
130 #[cfg(feature = "server")]
131 impl ruma_common::api::IncomingRequest for Request {
132 type EndpointError = Error;
133 type OutgoingResponse = Response;
134
135 fn try_from_http_request<B, S>(
136 request: http::Request<B>,
137 path_args: &[S],
138 ) -> Result<Self, ruma_common::api::error::FromHttpRequestError>
139 where
140 B: AsRef<[u8]>,
141 S: AsRef<str>,
142 {
143 use ruma_common::push::{
144 NewConditionalPushRule, NewPatternedPushRule, NewSimplePushRule,
145 };
146
147 #[derive(Debug, serde::Deserialize)]
149 #[serde(rename_all = "lowercase")]
150 enum RuleKind {
151 Override,
152 Underride,
153 Sender,
154 Room,
155 Content,
156 }
157
158 Self::check_request_method(request.method())?;
159
160 let (kind, rule_id): (RuleKind, String) =
161 serde::Deserialize::deserialize(serde::de::value::SeqDeserializer::<
162 _,
163 serde::de::value::Error,
164 >::new(
165 path_args.iter().map(::std::convert::AsRef::as_ref),
166 ))?;
167
168 let RequestQuery { before, after } =
169 serde_html_form::from_str(request.uri().query().unwrap_or(""))?;
170
171 let rule = match kind {
172 RuleKind::Override => {
173 let ConditionalRequestBody { actions, conditions } =
174 serde_json::from_slice(request.body().as_ref())?;
175 NewPushRule::Override(NewConditionalPushRule::new(rule_id, conditions, actions))
176 }
177 RuleKind::Underride => {
178 let ConditionalRequestBody { actions, conditions } =
179 serde_json::from_slice(request.body().as_ref())?;
180 NewPushRule::Underride(NewConditionalPushRule::new(
181 rule_id, conditions, actions,
182 ))
183 }
184 RuleKind::Sender => {
185 let SimpleRequestBody { actions } =
186 serde_json::from_slice(request.body().as_ref())?;
187 let rule_id = rule_id.try_into()?;
188 NewPushRule::Sender(NewSimplePushRule::new(rule_id, actions))
189 }
190 RuleKind::Room => {
191 let SimpleRequestBody { actions } =
192 serde_json::from_slice(request.body().as_ref())?;
193 let rule_id = rule_id.try_into()?;
194 NewPushRule::Room(NewSimplePushRule::new(rule_id, actions))
195 }
196 RuleKind::Content => {
197 let PatternedRequestBody { actions, pattern } =
198 serde_json::from_slice(request.body().as_ref())?;
199 NewPushRule::Content(NewPatternedPushRule::new(rule_id, pattern, actions))
200 }
201 };
202
203 Ok(Self { rule, before, after })
204 }
205 }
206
207 #[derive(Debug)]
208 #[cfg_attr(feature = "client", derive(serde::Serialize))]
209 #[cfg_attr(feature = "server", derive(serde::Deserialize))]
210 struct RequestQuery {
211 #[serde(skip_serializing_if = "Option::is_none")]
212 before: Option<String>,
213
214 #[serde(skip_serializing_if = "Option::is_none")]
215 after: Option<String>,
216 }
217
218 #[derive(Debug)]
219 #[cfg_attr(feature = "client", derive(serde::Serialize))]
220 #[cfg_attr(feature = "server", derive(serde::Deserialize))]
221 struct SimpleRequestBody {
222 actions: Vec<Action>,
223 }
224
225 #[derive(Debug)]
226 #[cfg_attr(feature = "client", derive(serde::Serialize))]
227 #[cfg_attr(feature = "server", derive(serde::Deserialize))]
228 struct PatternedRequestBody {
229 actions: Vec<Action>,
230
231 pattern: String,
232 }
233
234 #[derive(Debug)]
235 #[cfg_attr(feature = "client", derive(serde::Serialize))]
236 #[cfg_attr(feature = "server", derive(serde::Deserialize))]
237 struct ConditionalRequestBody {
238 actions: Vec<Action>,
239
240 conditions: Vec<PushCondition>,
241 }
242}