Add read-outbox command
This commit is contained in:
parent
c022e0d320
commit
7f6ebb89c0
5 changed files with 77 additions and 4 deletions
|
@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Added `create-user` command.
|
- Added `create-user` command.
|
||||||
|
- Added `read-outbox` command.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ use uuid::Uuid;
|
||||||
use mitra::activitypub::{
|
use mitra::activitypub::{
|
||||||
actors::helpers::update_remote_profile, builders::delete_note::prepare_delete_note,
|
actors::helpers::update_remote_profile, builders::delete_note::prepare_delete_note,
|
||||||
builders::delete_person::prepare_delete_person, fetcher::fetchers::fetch_actor,
|
builders::delete_person::prepare_delete_person, fetcher::fetchers::fetch_actor,
|
||||||
|
fetcher::helpers::import_from_outbox,
|
||||||
};
|
};
|
||||||
use mitra::admin::roles::{role_from_str, ALLOWED_ROLES};
|
use mitra::admin::roles::{role_from_str, ALLOWED_ROLES};
|
||||||
use mitra::media::{remove_files, remove_media, MediaStorage};
|
use mitra::media::{remove_files, remove_media, MediaStorage};
|
||||||
|
@ -55,6 +56,7 @@ pub enum SubCommand {
|
||||||
SetPassword(SetPassword),
|
SetPassword(SetPassword),
|
||||||
SetRole(SetRole),
|
SetRole(SetRole),
|
||||||
RefetchActor(RefetchActor),
|
RefetchActor(RefetchActor),
|
||||||
|
ReadOutbox(ReadOutbox),
|
||||||
DeleteProfile(DeleteProfile),
|
DeleteProfile(DeleteProfile),
|
||||||
DeletePost(DeletePost),
|
DeletePost(DeletePost),
|
||||||
DeleteEmoji(DeleteEmoji),
|
DeleteEmoji(DeleteEmoji),
|
||||||
|
@ -221,6 +223,23 @@ impl RefetchActor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pull activities from actor's outbox
|
||||||
|
#[derive(Parser)]
|
||||||
|
pub struct ReadOutbox {
|
||||||
|
actor_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReadOutbox {
|
||||||
|
pub async fn execute(
|
||||||
|
&self,
|
||||||
|
config: &Config,
|
||||||
|
db_client: &mut impl DatabaseClient,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
import_from_outbox(config, db_client, &self.actor_id).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Delete profile
|
/// Delete profile
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
pub struct DeleteProfile {
|
pub struct DeleteProfile {
|
||||||
|
|
|
@ -35,6 +35,7 @@ async fn main() {
|
||||||
SubCommand::SetPassword(cmd) => cmd.execute(db_client).await.unwrap(),
|
SubCommand::SetPassword(cmd) => cmd.execute(db_client).await.unwrap(),
|
||||||
SubCommand::SetRole(cmd) => cmd.execute(db_client).await.unwrap(),
|
SubCommand::SetRole(cmd) => cmd.execute(db_client).await.unwrap(),
|
||||||
SubCommand::RefetchActor(cmd) => cmd.execute(&config, db_client).await.unwrap(),
|
SubCommand::RefetchActor(cmd) => cmd.execute(&config, db_client).await.unwrap(),
|
||||||
|
SubCommand::ReadOutbox(cmd) => cmd.execute(&config, db_client).await.unwrap(),
|
||||||
SubCommand::DeleteProfile(cmd) => cmd.execute(&config, db_client).await.unwrap(),
|
SubCommand::DeleteProfile(cmd) => cmd.execute(&config, db_client).await.unwrap(),
|
||||||
SubCommand::DeletePost(cmd) => cmd.execute(&config, db_client).await.unwrap(),
|
SubCommand::DeletePost(cmd) => cmd.execute(&config, db_client).await.unwrap(),
|
||||||
SubCommand::DeleteEmoji(cmd) => cmd.execute(&config, db_client).await.unwrap(),
|
SubCommand::DeleteEmoji(cmd) => cmd.execute(&config, db_client).await.unwrap(),
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use reqwest::{Client, Method, RequestBuilder};
|
use reqwest::{Client, Method, RequestBuilder};
|
||||||
use serde_json::Value;
|
use serde::Deserialize;
|
||||||
|
use serde_json::{Value as JsonValue};
|
||||||
|
|
||||||
use mitra_config::Instance;
|
use mitra_config::Instance;
|
||||||
use mitra_utils::{
|
use mitra_utils::{
|
||||||
|
@ -222,7 +223,31 @@ pub async fn fetch_object(
|
||||||
object_url: &str,
|
object_url: &str,
|
||||||
) -> Result<Object, FetchError> {
|
) -> Result<Object, FetchError> {
|
||||||
let object_json = send_request(instance, object_url).await?;
|
let object_json = send_request(instance, object_url).await?;
|
||||||
let object_value: Value = serde_json::from_str(&object_json)?;
|
let object_value: JsonValue = serde_json::from_str(&object_json)?;
|
||||||
let object: Object = serde_json::from_value(object_value)?;
|
let object: Object = serde_json::from_value(object_value)?;
|
||||||
Ok(object)
|
Ok(object)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const OUTBOX_PAGE_SIZE_LIMIT: usize = 5;
|
||||||
|
|
||||||
|
pub async fn fetch_outbox(
|
||||||
|
instance: &Instance,
|
||||||
|
outbox_url: &str,
|
||||||
|
) -> Result<Vec<JsonValue>, FetchError> {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Collection {
|
||||||
|
first: String,
|
||||||
|
}
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct CollectionPage {
|
||||||
|
ordered_items: Vec<JsonValue>,
|
||||||
|
}
|
||||||
|
let collection_json = send_request(instance, outbox_url).await?;
|
||||||
|
let collection: Collection = serde_json::from_str(&collection_json)?;
|
||||||
|
let page_json = send_request(instance, &collection.first).await?;
|
||||||
|
let page: CollectionPage = serde_json::from_str(&page_json)?;
|
||||||
|
let activities = page.ordered_items.into_iter()
|
||||||
|
.take(OUTBOX_PAGE_SIZE_LIMIT).collect();
|
||||||
|
Ok(activities)
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use mitra_config::Instance;
|
use mitra_config::{Config, Instance};
|
||||||
use mitra_models::{
|
use mitra_models::{
|
||||||
database::{DatabaseClient, DatabaseError},
|
database::{DatabaseClient, DatabaseError},
|
||||||
posts::helpers::get_local_post_by_id,
|
posts::helpers::get_local_post_by_id,
|
||||||
|
@ -17,7 +17,7 @@ use crate::activitypub::{
|
||||||
actors::helpers::{create_remote_profile, update_remote_profile},
|
actors::helpers::{create_remote_profile, update_remote_profile},
|
||||||
handlers::create::{get_object_links, handle_note},
|
handlers::create::{get_object_links, handle_note},
|
||||||
identifiers::parse_local_object_id,
|
identifiers::parse_local_object_id,
|
||||||
receiver::HandlerError,
|
receiver::{handle_activity, HandlerError},
|
||||||
types::Object,
|
types::Object,
|
||||||
};
|
};
|
||||||
use crate::errors::ValidationError;
|
use crate::errors::ValidationError;
|
||||||
|
@ -26,6 +26,7 @@ use crate::webfinger::types::ActorAddress;
|
||||||
use super::fetchers::{
|
use super::fetchers::{
|
||||||
fetch_actor,
|
fetch_actor,
|
||||||
fetch_object,
|
fetch_object,
|
||||||
|
fetch_outbox,
|
||||||
perform_webfinger_query,
|
perform_webfinger_query,
|
||||||
FetchError,
|
FetchError,
|
||||||
};
|
};
|
||||||
|
@ -301,3 +302,29 @@ pub async fn import_post(
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Ok(initial_post)
|
Ok(initial_post)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn import_from_outbox(
|
||||||
|
config: &Config,
|
||||||
|
db_client: &mut impl DatabaseClient,
|
||||||
|
actor_id: &str,
|
||||||
|
) -> Result<(), HandlerError> {
|
||||||
|
let instance = config.instance();
|
||||||
|
let actor = fetch_actor(&instance, actor_id).await?;
|
||||||
|
let activities = fetch_outbox(&instance, &actor.outbox).await?;
|
||||||
|
log::info!("fetched {} activities", activities.len());
|
||||||
|
for activity in activities {
|
||||||
|
let activity_actor = activity["actor"].as_str()
|
||||||
|
.ok_or(ValidationError("actor property is missing"))?;
|
||||||
|
if activity_actor != actor.id {
|
||||||
|
log::warn!("activity doesn't belong to outbox owner");
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
handle_activity(
|
||||||
|
config,
|
||||||
|
db_client,
|
||||||
|
&activity,
|
||||||
|
true, // is authenticated
|
||||||
|
).await?;
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue