Skip to main content

tuwunel_api/client/push/
pushrules_global.rs

1use axum::extract::State;
2use ruma::{
3	CanonicalJsonObject, CanonicalJsonValue,
4	api::client::push::get_pushrules_global_scope,
5	events::{
6		GlobalAccountDataEventType,
7		push_rules::{PushRulesEvent, PushRulesEventContent},
8	},
9	push::{PredefinedContentRuleId, PredefinedOverrideRuleId, Ruleset},
10};
11use tuwunel_core::{Result, err};
12
13use crate::Ruma;
14
15/// # `GET /_matrix/client/r0/pushrules/global/`
16///
17/// Retrieves the push rules event for this user.
18///
19/// This appears to be the exact same as `GET /_matrix/client/r0/pushrules/`.
20pub(crate) async fn get_pushrules_global_route(
21	State(services): State<crate::State>,
22	body: Ruma<get_pushrules_global_scope::v3::Request>,
23) -> Result<get_pushrules_global_scope::v3::Response> {
24	let sender_user = body.sender_user();
25
26	let Some(content_value) = services
27		.account_data
28		.get_global::<CanonicalJsonObject>(sender_user, GlobalAccountDataEventType::PushRules)
29		.await
30		.ok()
31		.and_then(|event| event.get("content").cloned())
32		.filter(CanonicalJsonValue::is_object)
33	else {
34		// user somehow has non-existent push rule event. recreate it and return server
35		// default silently
36
37		let ty = GlobalAccountDataEventType::PushRules;
38		let event = PushRulesEvent {
39			content: PushRulesEventContent {
40				global: Ruleset::server_default(sender_user),
41			},
42		};
43
44		services
45			.account_data
46			.update(None, sender_user, ty.to_string().into(), &serde_json::to_value(event)?)
47			.await?;
48
49		return Ok(get_pushrules_global_scope::v3::Response {
50			global: Ruleset::server_default(sender_user),
51		});
52	};
53
54	let account_data_content =
55		serde_json::from_value::<PushRulesEventContent>(content_value.into()).map_err(|e| {
56			err!(Database(warn!("Invalid push rules account data event in database: {e}")))
57		})?;
58
59	let mut global_ruleset = account_data_content.global;
60
61	// remove old deprecated mentions push rules as per MSC4210
62	// and update the stored server default push rules
63	#[expect(deprecated)]
64	{
65		use ruma::push::RuleKind::*;
66		if global_ruleset
67			.get(Override, PredefinedOverrideRuleId::ContainsDisplayName.as_str())
68			.is_some()
69			|| global_ruleset
70				.get(Override, PredefinedOverrideRuleId::RoomNotif.as_str())
71				.is_some()
72			|| global_ruleset
73				.get(Content, PredefinedContentRuleId::ContainsUserName.as_str())
74				.is_some()
75			|| global_ruleset
76				.get(Override, PredefinedOverrideRuleId::Reply.as_str())
77				.is_none()
78		{
79			global_ruleset
80				.remove(Override, PredefinedOverrideRuleId::ContainsDisplayName)
81				.ok();
82			global_ruleset
83				.remove(Override, PredefinedOverrideRuleId::RoomNotif)
84				.ok();
85			global_ruleset
86				.remove(Content, PredefinedContentRuleId::ContainsUserName)
87				.ok();
88
89			global_ruleset.update_with_server_default(Ruleset::server_default(sender_user));
90
91			services
92				.account_data
93				.update(
94					None,
95					sender_user,
96					GlobalAccountDataEventType::PushRules
97						.to_string()
98						.into(),
99					&serde_json::to_value(PushRulesEvent {
100						content: PushRulesEventContent { global: global_ruleset.clone() },
101					})
102					.expect("to json always works"),
103				)
104				.await?;
105		}
106	};
107
108	Ok(get_pushrules_global_scope::v3::Response { global: global_ruleset })
109}