Skip to content
Clone
main
89 lines 3.1 KB Rust
use models::users::{user, users};
use sea_orm::{ConnectionTrait, DbErr, EntityTrait};
use serde::Serialize;
use serde_json::Value;
use uuid::Uuid;
use crate::{EventKind, Labels, label};
pub async fn emit(
tx: &impl ConnectionTrait,
kind: EventKind,
mut labels: Labels,
payload: impl Serialize,
) -> Result<Uuid, DbErr> {
let request_id = labels
.get(label::REQUEST_ID)
.map(str::to_owned)
.or_else(envelope::context::request_id)
.unwrap_or_default();
if !request_id.is_empty() {
labels.insert(label::REQUEST_ID, &request_id);
}
let mut payload = serde_json::to_value(payload)
.map_err(|error| DbErr::Custom(format!("event serialization failed: {error}")))?;
let actor_id = labels
.get(label::ACTOR_USER_ID)
.and_then(|value| value.parse::<i64>().ok())
.or_else(|| {
payload
.get("notification")
.and_then(|notification| notification.get("actor_id"))
.and_then(Value::as_i64)
})
.or_else(|| {
payload
.get("message")
.and_then(|message| message.get("author_id"))
.and_then(Value::as_i64)
})
.or_else(|| {
if labels.get(label::RECIPIENT_USER_ID).is_none() {
labels
.get(label::USER_ID)
.and_then(|value| value.parse::<i64>().ok())
} else {
None
}
});
if let Some(uid) = actor_id
&& let Some(snapshot) = actor_snapshot(tx, uid).await
{
if payload.is_object() && payload.get("actor").is_none_or(Value::is_null) {
payload["actor"] = snapshot.clone();
}
if let Some(notification) = payload.get_mut("notification")
&& notification.is_object()
&& notification.get("actor").is_none_or(Value::is_null)
{
notification["actor"] = snapshot;
}
}
if let Some(message) = payload.get_mut("message")
&& message.get("author").is_none_or(Value::is_null)
&& let Some(uid) = message.get("author_id").and_then(Value::as_i64)
&& let Some(snapshot) = actor_snapshot(tx, uid).await
{
message["author"] = snapshot;
}
crate::outbox::enqueue_now(tx, kind, labels, payload, &request_id, Some(&request_id)).await
}
pub async fn actor_snapshot(tx: &impl ConnectionTrait, uid: i64) -> Option<Value> {
let identity = users::Entity::find_by_id(uid).one(tx).await.ok()??;
let local = user::Entity::find_by_id(uid).one(tx).await.ok().flatten();
let avatar = local.map(|user| user.local_avatar_url).unwrap_or_default();
let avatar = if avatar.is_empty() {
String::new()
} else if avatar.starts_with("http://") || avatar.starts_with("https://") {
avatar
} else {
format!("/api/v1/users/{uid}/avatar")
};
Some(serde_json::json!({
"id": identity.id,
"username": identity.username,
"display_name": identity.displayname,
"avatar_url": avatar,
}))
}