summaryrefslogtreecommitdiffstats
path: root/server/src/apub/activities.rs
blob: 204a380d39b387e66abb7a334e4ff6d94d9215f7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use crate::{
  apub::{
    community::do_announce,
    extensions::signatures::sign,
    insert_activity,
    is_apub_id_valid,
    ActorType,
  },
  request::retry_custom,
  DbPool,
  LemmyError,
};
use activitystreams::{context, object::properties::ObjectProperties, public, Activity, Base};
use actix_web::client::Client;
use lemmy_db::{community::Community, user::User_};
use log::debug;
use serde::Serialize;
use std::fmt::Debug;
use url::Url;

pub fn populate_object_props(
  props: &mut ObjectProperties,
  addressed_ccs: Vec<String>,
  object_id: &str,
) -> Result<(), LemmyError> {
  props
    .set_context_xsd_any_uri(context())?
    // TODO: the activity needs a seperate id from the object
    .set_id(object_id)?
    // TODO: should to/cc go on the Create, or on the Post? or on both?
    // TODO: handle privacy on the receiving side (at least ignore anything thats not public)
    .set_to_xsd_any_uri(public())?
    .set_many_cc_xsd_any_uris(addressed_ccs)?;
  Ok(())
}

pub async fn send_activity_to_community<A>(
  creator: &User_,
  community: &Community,
  to: Vec<String>,
  activity: A,
  client: &Client,
  pool: &DbPool,
) -> Result<(), LemmyError>
where
  A: Activity + Base + Serialize + Debug + Clone + Send + 'static,
{
  insert_activity(creator.id, activity.clone(), true, pool).await?;

  // if this is a local community, we need to do an announce from the community instead
  if community.local {
    do_announce(activity, &community, creator, client, pool).await?;
  } else {
    send_activity(client, &activity, creator, to).await?;
  }

  Ok(())
}

/// Send an activity to a list of recipients, using the correct headers etc.
pub async fn send_activity<A>(
  client: &Client,
  activity: &A,
  actor: &dyn ActorType,
  to: Vec<String>,
) -> Result<(), LemmyError>
where
  A: Serialize,
{
  let activity = serde_json::to_string(&activity)?;
  debug!("Sending activitypub activity {} to {:?}", activity, to);

  for t in to {
    let to_url = Url::parse(&t)?;
    if !is_apub_id_valid(&to_url) {
      debug!("Not sending activity to {} (invalid or blocklisted)", t);
      continue;
    }

    let res = retry_custom(|| async {
      let request = client.post(&t).header("Content-Type", "application/json");

      match sign(request, actor, activity.clone()).await {
        Ok(signed) => Ok(signed.send().await),
        Err(e) => Err(e),
      }
    })
    .await?;

    debug!("Result for activity send: {:?}", res);
  }

  Ok(())
}