cloudillo_action/native_hooks/
react.rs1use crate::hooks::{HookContext, HookResult};
11use crate::prelude::*;
12use cloudillo_core::app::App;
13use cloudillo_types::meta_adapter::UpdateActionDataOptions;
14use cloudillo_types::types::Patch;
15
16pub async fn on_create(app: App, context: HookContext) -> ClResult<HookResult> {
22 tracing::debug!("Native hook: REACT on_create for action {}", context.action_id);
23
24 let tn_id = TnId(context.tenant_id as u32);
25 let Some(subject_id) = &context.subject else {
26 tracing::warn!("REACT on_create: No subject specified");
27 return Ok(HookResult::default());
28 };
29
30 let subject_data = app.meta_adapter.get_action_data(tn_id, subject_id).await?;
32 let current_reactions = subject_data.as_ref().and_then(|d| d.reactions).unwrap_or(0);
33
34 let new_reactions = match context.subtype.as_deref() {
35 Some("DEL") => {
36 tracing::info!(
38 "REACT:DEL on_create: {} removing reaction from {}",
39 context.issuer,
40 subject_id
41 );
42 current_reactions.saturating_sub(1)
43 }
44 _ => {
45 tracing::info!(
47 "REACT:{:?} on_create: {} reacting to {}",
48 context.subtype,
49 context.issuer,
50 subject_id
51 );
52 current_reactions.saturating_add(1)
53 }
54 };
55
56 let update_opts =
58 UpdateActionDataOptions { reactions: Patch::Value(new_reactions), ..Default::default() };
59
60 if let Err(e) = app.meta_adapter.update_action_data(tn_id, subject_id, &update_opts).await {
61 tracing::warn!("REACT on_create: Failed to update subject {} reactions: {}", subject_id, e);
62 } else {
63 tracing::debug!(
64 "REACT on_create: Updated subject {} reactions: {} -> {}",
65 subject_id,
66 current_reactions,
67 new_reactions
68 );
69 }
70
71 Ok(HookResult::default())
72}
73
74pub async fn on_receive(app: App, context: HookContext) -> ClResult<HookResult> {
80 tracing::debug!("Native hook: REACT on_receive for action {}", context.action_id);
81
82 let tn_id = TnId(context.tenant_id as u32);
83 let Some(subject_id) = &context.subject else {
84 tracing::warn!("REACT on_receive: No subject specified");
85 return Ok(HookResult::default());
86 };
87
88 let Some(subject_action) = app.meta_adapter.get_action(tn_id, subject_id).await? else {
90 tracing::debug!("REACT on_receive: Subject action {} not found locally", subject_id);
91 return Ok(HookResult::default());
92 };
93
94 if subject_action.issuer.id_tag.as_ref() != context.tenant_tag {
96 tracing::debug!(
97 "REACT on_receive: Subject {} owned by {}, not us ({})",
98 subject_id,
99 subject_action.issuer.id_tag,
100 context.tenant_tag
101 );
102 return Ok(HookResult::default());
103 }
104
105 let subject_data = app.meta_adapter.get_action_data(tn_id, subject_id).await?;
107 let current_reactions = subject_data.as_ref().and_then(|d| d.reactions).unwrap_or(0);
108
109 let new_reactions = match context.subtype.as_deref() {
110 Some("DEL") => {
111 tracing::info!(
113 "REACT:DEL on_receive: {} removing reaction from our action {}",
114 context.issuer,
115 subject_id
116 );
117 current_reactions.saturating_sub(1)
118 }
119 _ => {
120 tracing::info!(
122 "REACT:{:?} on_receive: {} reacting to our action {}",
123 context.subtype,
124 context.issuer,
125 subject_id
126 );
127 current_reactions.saturating_add(1)
128 }
129 };
130
131 let update_opts =
133 UpdateActionDataOptions { reactions: Patch::Value(new_reactions), ..Default::default() };
134
135 if let Err(e) = app.meta_adapter.update_action_data(tn_id, subject_id, &update_opts).await {
136 tracing::warn!(
137 "REACT on_receive: Failed to update subject {} reactions: {}",
138 subject_id,
139 e
140 );
141 } else {
142 tracing::debug!(
143 "REACT on_receive: Updated subject {} reactions: {} -> {}",
144 subject_id,
145 current_reactions,
146 new_reactions
147 );
148 }
149
150 Ok(HookResult::default())
151}
152
153