Skip to main content

cloudillo_action/native_hooks/
conv.rs

1//! CONV (Conversation) action native hooks
2//!
3//! Handles conversation lifecycle:
4//! - on_create: Auto-creates SUBS with admin role for the creator
5//! - on_receive: Handles receiving federated conversation
6//! - Subtypes:
7//!   - UPD: Update conversation settings (requires admin role)
8//!   - DEL: Archive/delete conversation (requires admin role)
9
10use crate::hooks::{HookContext, HookResult};
11use crate::prelude::*;
12use crate::task::{create_action, CreateAction};
13use cloudillo_core::app::App;
14
15/// CONV on_create hook - Auto-subscribe creator as admin
16///
17/// Logic:
18/// - Creator creates their own SUBS with subject=action_id
19/// - Role is stored in x.role (extensible metadata), not in content JWT
20/// - If CONV has an audience (community), SUBS federates to the community
21/// - SUBS issuer is the creator (self-issued) ensuring proper ownership
22pub async fn on_create(app: App, context: HookContext) -> ClResult<HookResult> {
23	let tn_id = TnId(context.tenant_id as u32);
24
25	tracing::info!(
26		"CONV: Creating conversation {} by {}, audience={:?}",
27		context.action_id,
28		context.issuer,
29		context.audience
30	);
31
32	// Auto-create admin subscription for the creator
33	// Role is stored in x.role (server-side metadata, not in JWT)
34	let subs_action = CreateAction {
35		typ: "SUBS".into(),
36		// If CONV has audience (e.g., community), use that for federation
37		// Otherwise, use self as audience (personal conversation)
38		audience_tag: context
39			.audience
40			.clone()
41			.map(|a| a.into_boxed_str())
42			.or_else(|| Some(context.issuer.clone().into_boxed_str())),
43		subject: Some(context.action_id.clone().into()),
44		// x.role stores the subscription role (server-side, not in JWT)
45		x: Some(serde_json::json!({ "role": "admin" })),
46		..Default::default()
47	};
48
49	match create_action(&app, tn_id, &context.issuer, subs_action).await {
50		Ok(subs_id) => {
51			tracing::info!(
52				"CONV: Auto-created admin SUBS {} for conversation {}",
53				subs_id,
54				context.action_id
55			);
56		}
57		Err(e) => {
58			tracing::error!(
59				"CONV: Failed to create admin SUBS for conversation {}: {}",
60				context.action_id,
61				e
62			);
63			// Don't fail the CONV creation - log and continue
64		}
65	}
66
67	Ok(HookResult::default())
68}
69
70/// CONV on_receive hook - Handle receiving shared conversation
71///
72/// Logic:
73/// - When a CONV is received (federated), we store it for reference
74/// - No special action needed as SUBS handles membership
75pub async fn on_receive(_app: App, context: HookContext) -> ClResult<HookResult> {
76	tracing::debug!("CONV: Received conversation {} from {}", context.action_id, context.issuer);
77
78	// CONV actions from remote are informational - the SUBS system handles access
79	Ok(HookResult::default())
80}
81
82// vim: ts=4