Create DbActor type and use it to represent actor_profile.actor_json column value

This commit is contained in:
silverpill 2023-03-16 20:09:13 +00:00
parent 4f9a99e6f2
commit 462da87e9b
22 changed files with 125 additions and 79 deletions

View file

@ -175,7 +175,7 @@ pub async fn create_remote_profile(
extra_fields,
aliases,
emojis,
actor_json: Some(actor),
actor_json: Some(actor.into_db_actor()),
};
clean_profile_create_data(&mut profile_data)?;
let profile = create_profile(db_client, profile_data).await?;
@ -233,7 +233,7 @@ pub async fn update_remote_profile(
extra_fields,
aliases,
emojis,
actor_json: Some(actor),
actor_json: Some(actor.into_db_actor()),
};
clean_profile_update_data(&mut profile_data)?;
let profile = update_profile(db_client, &profile.id, profile_data).await?;

View file

@ -36,6 +36,8 @@ use crate::errors::ValidationError;
use crate::media::get_file_url;
use crate::models::{
profiles::types::{
DbActor,
DbActorPublicKey,
ExtraField,
IdentityProof,
PaymentOption,
@ -52,7 +54,7 @@ use super::attachments::{
parse_payment_option,
};
#[derive(Clone, Debug, Deserialize, Serialize)]
#[derive(Deserialize, Serialize)]
#[cfg_attr(test, derive(Default))]
#[serde(rename_all = "camelCase")]
pub struct PublicKey {
@ -61,7 +63,7 @@ pub struct PublicKey {
pub public_key_pem: String,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[derive(Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ActorImage {
#[serde(rename = "type")]
@ -70,7 +72,7 @@ pub struct ActorImage {
pub media_type: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[derive(Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ActorAttachment {
pub name: String,
@ -130,8 +132,7 @@ fn deserialize_attachments<'de, D>(
Ok(attachments)
}
// Clone and Debug traits are required by FromSql
#[derive(Clone, Debug, Deserialize, Serialize)]
#[derive(Deserialize, Serialize)]
#[cfg_attr(test, derive(Default))]
#[serde(rename_all = "camelCase")]
pub struct Actor {
@ -210,6 +211,23 @@ impl Actor {
Ok(actor_address)
}
pub fn into_db_actor(self) -> DbActor {
DbActor {
object_type: self.object_type,
id: self.id,
inbox: self.inbox,
outbox: self.outbox,
followers: self.followers,
subscribers: self.subscribers,
url: self.url,
public_key: DbActorPublicKey {
id: self.public_key.id,
owner: self.public_key.owner,
public_key_pem: self.public_key.public_key_pem,
},
}
}
pub fn parse_attachments(&self) -> (
Vec<IdentityProof>,
Vec<PaymentOption>,

View file

@ -4,14 +4,13 @@ use mitra_config::Instance;
use mitra_utils::id::generate_ulid;
use crate::activitypub::{
actors::types::Actor,
deliverer::OutgoingActivity,
identifiers::{local_actor_id, local_object_id},
types::{build_default_context, Context},
vocabulary::ACCEPT,
};
use crate::models::{
profiles::types::DbActorProfile,
profiles::types::{DbActor, DbActorProfile},
users::types::User,
};
@ -52,7 +51,7 @@ fn build_accept_follow(
pub fn prepare_accept_follow(
instance: &Instance,
sender: &User,
source_actor: &Actor,
source_actor: &DbActor,
follow_activity_id: &str,
) -> OutgoingActivity {
let activity = build_accept_follow(

View file

@ -4,13 +4,15 @@ use mitra_config::Instance;
use mitra_utils::id::generate_ulid;
use crate::activitypub::{
actors::types::Actor,
deliverer::OutgoingActivity,
identifiers::{local_actor_id, local_object_id, LocalActorCollection},
types::{build_default_context, Context},
vocabulary::{ADD, REMOVE},
};
use crate::models::users::types::User;
use crate::models::{
profiles::types::DbActor,
users::types::User,
};
#[derive(Serialize)]
struct AddOrRemovePerson {
@ -53,7 +55,7 @@ fn build_update_collection(
pub fn prepare_update_collection(
instance: &Instance,
sender: &User,
person: &Actor,
person: &DbActor,
collection: LocalActorCollection,
remove: bool,
) -> OutgoingActivity {
@ -76,7 +78,7 @@ pub fn prepare_update_collection(
pub fn prepare_add_person(
instance: &Instance,
sender: &User,
person: &Actor,
person: &DbActor,
collection: LocalActorCollection,
) -> OutgoingActivity {
prepare_update_collection(instance, sender, person, collection, false)

View file

@ -4,7 +4,6 @@ use serde::Serialize;
use mitra_config::Instance;
use crate::activitypub::{
actors::types::Actor,
constants::AP_PUBLIC,
deliverer::OutgoingActivity,
identifiers::{
@ -20,6 +19,7 @@ use crate::activitypub::{
use crate::database::{DatabaseClient, DatabaseError};
use crate::models::{
posts::types::Post,
profiles::types::DbActor,
relationships::queries::get_followers,
users::types::User,
};
@ -70,9 +70,9 @@ pub async fn get_announce_recipients(
instance_url: &str,
current_user: &User,
post: &Post,
) -> Result<(Vec<Actor>, String), DatabaseError> {
) -> Result<(Vec<DbActor>, String), DatabaseError> {
let followers = get_followers(db_client, &current_user.id).await?;
let mut recipients: Vec<Actor> = Vec::new();
let mut recipients = vec![];
for profile in followers {
if let Some(remote_actor) = profile.actor_json {
recipients.push(remote_actor);
@ -113,7 +113,6 @@ pub async fn prepare_announce(
#[cfg(test)]
mod tests {
use crate::activitypub::actors::types::Actor;
use crate::models::profiles::types::DbActorProfile;
use super::*;
@ -123,7 +122,7 @@ mod tests {
fn test_build_announce() {
let post_author_id = "https://test.net/user/test";
let post_author = DbActorProfile {
actor_json: Some(Actor {
actor_json: Some(DbActor {
id: post_author_id.to_string(),
..Default::default()
}),

View file

@ -4,7 +4,6 @@ use serde::Serialize;
use mitra_config::Instance;
use crate::activitypub::{
actors::types::Actor,
constants::{AP_MEDIA_TYPE, AP_PUBLIC},
deliverer::OutgoingActivity,
identifiers::{
@ -34,6 +33,7 @@ use crate::models::{
emojis::types::DbEmoji,
posts::queries::get_post_author,
posts::types::{Post, Visibility},
profiles::types::DbActor,
relationships::queries::{get_followers, get_subscribers},
users::types::User,
};
@ -256,7 +256,7 @@ pub async fn get_note_recipients(
db_client: &impl DatabaseClient,
current_user: &User,
post: &Post,
) -> Result<Vec<Actor>, DatabaseError> {
) -> Result<Vec<DbActor>, DatabaseError> {
let mut audience = vec![];
match post.visibility {
Visibility::Public | Visibility::Followers => {
@ -276,7 +276,7 @@ pub async fn get_note_recipients(
};
audience.extend(post.mentions.clone());
let mut recipients: Vec<Actor> = Vec::new();
let mut recipients = vec![];
for profile in audience {
if let Some(remote_actor) = profile.actor_json {
recipients.push(remote_actor);
@ -399,7 +399,7 @@ mod tests {
let subscriber = DbActorProfile {
username: "subscriber".to_string(),
hostname: Some("test.com".to_string()),
actor_json: Some(Actor {
actor_json: Some(DbActor {
id: subscriber_id.to_string(),
..Default::default()
}),
@ -426,7 +426,7 @@ mod tests {
let mentioned = DbActorProfile {
username: "mention".to_string(),
hostname: Some("test.com".to_string()),
actor_json: Some(Actor {
actor_json: Some(DbActor {
id: mentioned_id.to_string(),
..Default::default()
}),
@ -473,7 +473,7 @@ mod tests {
username: "test".to_string(),
hostname: Some("test.net".to_string()),
acct: parent_author_acct.to_string(),
actor_json: Some(Actor {
actor_json: Some(DbActor {
id: parent_author_actor_id.to_string(),
url: Some(parent_author_actor_url.to_string()),
..Default::default()

View file

@ -4,7 +4,6 @@ use uuid::Uuid;
use mitra_config::Instance;
use crate::activitypub::{
actors::types::Actor,
constants::AP_PUBLIC,
deliverer::OutgoingActivity,
identifiers::local_actor_id,
@ -13,6 +12,7 @@ use crate::activitypub::{
};
use crate::database::{DatabaseClient, DatabaseError};
use crate::models::{
profiles::types::DbActor,
relationships::queries::{get_followers, get_following},
users::types::User,
};
@ -51,7 +51,7 @@ fn build_delete_person(
async fn get_delete_person_recipients(
db_client: &impl DatabaseClient,
user_id: &Uuid,
) -> Result<Vec<Actor>, DatabaseError> {
) -> Result<Vec<DbActor>, DatabaseError> {
let followers = get_followers(db_client, user_id).await?;
let following = get_following(db_client, user_id).await?;
let mut recipients = vec![];

View file

@ -4,14 +4,13 @@ use uuid::Uuid;
use mitra_config::Instance;
use crate::activitypub::{
actors::types::Actor,
deliverer::OutgoingActivity,
identifiers::{local_actor_id, local_object_id},
types::{build_default_context, Context},
vocabulary::FOLLOW,
};
use crate::models::{
profiles::types::DbActorProfile,
profiles::types::{DbActor, DbActorProfile},
users::types::User,
};
@ -51,7 +50,7 @@ fn build_follow(
pub fn prepare_follow(
instance: &Instance,
sender: &User,
target_actor: &Actor,
target_actor: &DbActor,
follow_request_id: &Uuid,
) -> OutgoingActivity {
let activity = build_follow(

View file

@ -4,7 +4,6 @@ use uuid::Uuid;
use mitra_config::Instance;
use crate::activitypub::{
actors::types::Actor,
constants::AP_PUBLIC,
deliverer::OutgoingActivity,
identifiers::{
@ -19,7 +18,7 @@ use crate::activitypub::{
use crate::database::{DatabaseClient, DatabaseError};
use crate::models::{
posts::types::{Post, Visibility},
profiles::types::DbActorProfile,
profiles::types::{DbActor, DbActorProfile},
users::types::User,
};
@ -78,8 +77,8 @@ pub async fn get_like_recipients(
_db_client: &impl DatabaseClient,
_instance_url: &str,
post: &Post,
) -> Result<Vec<Actor>, DatabaseError> {
let mut recipients: Vec<Actor> = Vec::new();
) -> Result<Vec<DbActor>, DatabaseError> {
let mut recipients = vec![];
if let Some(remote_actor) = post.author.actor_json.as_ref() {
recipients.push(remote_actor.clone());
};

View file

@ -5,13 +5,15 @@ use mitra_config::Instance;
use mitra_utils::id::generate_ulid;
use crate::activitypub::{
actors::types::Actor,
deliverer::OutgoingActivity,
identifiers::{local_actor_id, local_object_id},
types::{build_default_context, Context},
vocabulary::MOVE,
};
use crate::models::users::types::User;
use crate::models::{
profiles::types::DbActor,
users::types::User,
};
#[derive(Serialize)]
pub struct MovePerson {
@ -55,7 +57,7 @@ pub fn prepare_move_person(
instance: &Instance,
sender: &User,
from_actor_id: &str,
followers: Vec<Actor>,
followers: Vec<DbActor>,
maybe_internal_activity_id: Option<&Uuid>,
) -> OutgoingActivity {
let followers_ids: Vec<String> = followers.iter()

View file

@ -1,17 +1,19 @@
use mitra_config::Instance;
use crate::activitypub::{
actors::types::Actor,
deliverer::OutgoingActivity,
identifiers::LocalActorCollection,
};
use crate::models::users::types::User;
use crate::models::{
profiles::types::DbActor,
users::types::User,
};
use super::add_person::prepare_update_collection;
pub fn prepare_remove_person(
instance: &Instance,
sender: &User,
person: &Actor,
person: &DbActor,
collection: LocalActorCollection,
) -> OutgoingActivity {
prepare_update_collection(instance, sender, person, collection, true)

View file

@ -4,14 +4,13 @@ use uuid::Uuid;
use mitra_config::Instance;
use crate::activitypub::{
actors::types::Actor,
deliverer::OutgoingActivity,
identifiers::{local_actor_id, local_object_id},
types::{build_default_context, Context},
vocabulary::{FOLLOW, UNDO},
};
use crate::models::{
profiles::types::DbActorProfile,
profiles::types::{DbActor, DbActorProfile},
users::types::User,
};
use super::follow::Follow;
@ -68,7 +67,7 @@ fn build_undo_follow(
pub fn prepare_undo_follow(
instance: &Instance,
sender: &User,
target_actor: &Actor,
target_actor: &DbActor,
follow_request_id: &Uuid,
) -> OutgoingActivity {
let activity = build_undo_follow(

View file

@ -14,6 +14,7 @@ use crate::activitypub::{
};
use crate::database::{DatabaseClient, DatabaseError, DatabaseTypeError};
use crate::models::{
profiles::types::DbActor,
relationships::queries::get_followers,
users::types::User,
};
@ -60,9 +61,9 @@ pub fn build_update_person(
async fn get_update_person_recipients(
db_client: &impl DatabaseClient,
user_id: &Uuid,
) -> Result<Vec<Actor>, DatabaseError> {
) -> Result<Vec<DbActor>, DatabaseError> {
let followers = get_followers(db_client, user_id).await?;
let mut recipients: Vec<Actor> = Vec::new();
let mut recipients = vec![];
for profile in followers {
if let Some(remote_actor) = profile.actor_json {
recipients.push(remote_actor);

View file

@ -25,9 +25,11 @@ use crate::json_signatures::create::{
sign_object,
JsonSignatureError,
};
use crate::models::users::types::User;
use crate::models::{
profiles::types::DbActor,
users::types::User,
};
use super::{
actors::types::Actor,
constants::AP_MEDIA_TYPE,
http_client::build_federation_client,
identifiers::{local_actor_id, local_actor_key_id},
@ -186,7 +188,7 @@ impl OutgoingActivity {
instance: &Instance,
sender: &User,
activity: impl Serialize,
recipients: Vec<Actor>,
recipients: Vec<DbActor>,
) -> Self {
// Sort and de-duplicate recipients
let mut recipient_map = BTreeMap::new();

View file

@ -667,10 +667,10 @@ pub async fn handle_create(
mod tests {
use serde_json::json;
use crate::activitypub::{
actors::types::Actor,
types::Object,
vocabulary::NOTE,
};
use crate::models::profiles::types::DbActor;
use super::*;
#[test]
@ -742,7 +742,7 @@ mod tests {
fn test_get_object_visibility_followers() {
let author_followers = "https://example.com/users/author/followers";
let author = DbActorProfile {
actor_json: Some(Actor {
actor_json: Some(DbActor {
followers: Some(author_followers.to_string()),
..Default::default()
}),
@ -763,7 +763,7 @@ mod tests {
let author_followers = "https://example.com/users/author/followers";
let author_subscribers = "https://example.com/users/author/subscribers";
let author = DbActorProfile {
actor_json: Some(Actor {
actor_json: Some(DbActor {
followers: Some(author_followers.to_string()),
subscribers: Some(author_subscribers.to_string()),
..Default::default()
@ -783,7 +783,7 @@ mod tests {
#[test]
fn test_get_object_visibility_direct() {
let author = DbActorProfile {
actor_json: Some(Actor::default()),
actor_json: Some(DbActor::default()),
..Default::default()
};
let primary_audience = vec!["https://example.com/users/1".to_string()];

View file

@ -199,7 +199,7 @@ pub async fn move_followers_task(
#[cfg(test)]
mod tests {
use crate::activitypub::actors::types::Actor;
use crate::models::profiles::types::DbActor;
use super::*;
#[test]
@ -211,7 +211,7 @@ mod tests {
let profile_2 = DbActorProfile {
username: "user2".to_string(),
hostname: Some("test.net".to_string()),
actor_json: Some(Actor::default()),
actor_json: Some(DbActor::default()),
..Default::default()
};
let csv = export_profiles_to_csv(

View file

@ -105,7 +105,7 @@ pub fn replace_mentions(
#[cfg(test)]
mod tests {
use crate::activitypub::actors::types::Actor;
use crate::models::profiles::types::DbActor;
use super::*;
const INSTANCE_HOSTNAME: &str = "server1.com";
@ -147,7 +147,7 @@ mod tests {
// Remote actors
let profile_3 = DbActorProfile {
username: "user2".to_string(),
actor_json: Some(Actor {
actor_json: Some(DbActor {
id: "https://server2.com/actors/user2".to_string(),
url: Some("https://server2.com/@user2".to_string()),
..Default::default()
@ -156,7 +156,7 @@ mod tests {
};
let profile_4 = DbActorProfile {
username: "user3".to_string(),
actor_json: Some(Actor {
actor_json: Some(DbActor {
id: "https://server2.com/actors/user3".to_string(),
url: Some("https://server2.com/@user3".to_string()),
..Default::default()

View file

@ -828,13 +828,13 @@ pub async fn find_empty_profiles(
#[cfg(test)]
mod tests {
use serial_test::serial;
use crate::activitypub::actors::types::Actor;
use crate::database::test_utils::create_test_database;
use crate::models::{
emojis::queries::create_emoji,
emojis::types::EmojiImage,
profiles::queries::create_profile,
profiles::types::{
DbActor,
ExtraField,
IdentityProof,
IdentityProofType,
@ -845,8 +845,8 @@ mod tests {
};
use super::*;
fn create_test_actor(actor_id: &str) -> Actor {
Actor { id: actor_id.to_string(), ..Default::default() }
fn create_test_actor(actor_id: &str) -> DbActor {
DbActor { id: actor_id.to_string(), ..Default::default() }
}
#[tokio::test]

View file

@ -13,9 +13,6 @@ use mitra_utils::{
did::Did,
};
use crate::activitypub::{
actors::types::Actor,
};
use crate::database::{
json_macro::{json_from_sql, json_to_sql},
DatabaseTypeError,
@ -336,8 +333,34 @@ impl ProfileEmojis {
json_from_sql!(ProfileEmojis);
json_from_sql!(Actor);
json_to_sql!(Actor);
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(test, derive(Default))]
#[serde(rename_all = "camelCase")]
pub struct DbActorPublicKey {
pub id: String,
pub owner: String,
pub public_key_pem: String,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(test, derive(Default))]
#[serde(rename_all = "camelCase")]
pub struct DbActor {
#[serde(rename = "type")]
pub object_type: String,
pub id: String,
pub inbox: String,
pub outbox: String,
pub followers: Option<String>,
pub subscribers: Option<String>,
pub url: Option<String>,
pub public_key: DbActorPublicKey,
}
json_from_sql!(DbActor);
json_to_sql!(DbActor);
#[derive(Clone, FromSql)]
#[postgres(name = "actor_profile")]
@ -360,7 +383,7 @@ pub struct DbActorProfile {
pub subscriber_count: i32,
pub post_count: i32,
pub emojis: ProfileEmojis,
pub actor_json: Option<Actor>,
pub actor_json: Option<DbActor>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub unreachable_since: Option<DateTime<Utc>>,
@ -446,7 +469,7 @@ pub struct ProfileCreateData {
pub extra_fields: Vec<ExtraField>,
pub aliases: Vec<String>,
pub emojis: Vec<Uuid>,
pub actor_json: Option<Actor>,
pub actor_json: Option<DbActor>,
}
pub struct ProfileUpdateData {
@ -461,7 +484,7 @@ pub struct ProfileUpdateData {
pub extra_fields: Vec<ExtraField>,
pub aliases: Vec<String>,
pub emojis: Vec<Uuid>,
pub actor_json: Option<Actor>,
pub actor_json: Option<DbActor>,
}
impl ProfileUpdateData {

View file

@ -557,15 +557,16 @@ pub async fn show_replies(
#[cfg(test)]
mod tests {
use serial_test::serial;
use crate::activitypub::actors::types::Actor;
use crate::database::{
test_utils::create_test_database,
DatabaseError,
};
use crate::models::profiles::queries::create_profile;
use crate::models::profiles::types::ProfileCreateData;
use crate::models::users::queries::create_user;
use crate::models::users::types::UserCreateData;
use crate::models::{
profiles::queries::create_profile,
profiles::types::{DbActor, ProfileCreateData},
users::queries::create_user,
users::types::UserCreateData,
};
use super::*;
#[tokio::test]
@ -580,7 +581,7 @@ mod tests {
let target_data = ProfileCreateData {
username: "followed".to_string(),
hostname: Some("example.org".to_string()),
actor_json: Some(Actor::default()),
actor_json: Some(DbActor::default()),
..Default::default()
};
let target = create_profile(db_client, target_data).await.unwrap();
@ -621,7 +622,7 @@ mod tests {
let source_data = ProfileCreateData {
username: "follower".to_string(),
hostname: Some("example.org".to_string()),
actor_json: Some(Actor::default()),
actor_json: Some(DbActor::default()),
..Default::default()
};
let source = create_profile(db_client, source_data).await.unwrap();

View file

@ -129,7 +129,7 @@ pub fn clean_profile_update_data(
#[cfg(test)]
mod tests {
use crate::activitypub::actors::types::Actor;
use crate::models::profiles::types::DbActor;
use super::*;
#[test]
@ -185,7 +185,7 @@ mod tests {
username: "test".to_string(),
hostname: Some("example.org".to_string()),
display_name: Some("Test Test".to_string()),
actor_json: Some(Actor {
actor_json: Some(DbActor {
id: "https://example.org/test".to_string(),
..Default::default()
}),

View file

@ -104,7 +104,7 @@ pub struct JsonResourceDescriptor {
#[cfg(test)]
mod tests {
use crate::activitypub::actors::types::Actor;
use crate::models::profiles::types::DbActor;
use super::*;
#[test]
@ -138,7 +138,7 @@ mod tests {
username: "test".to_string(),
hostname: Some("remote.com".to_string()),
acct: "test@remote.com".to_string(),
actor_json: Some(Actor {
actor_json: Some(DbActor {
id: "https://test".to_string(),
..Default::default()
}),