rewrite person to use inbox_id

This commit is contained in:
Felix Ableitner 2024-10-17 14:13:33 +02:00
parent e6f219aa1a
commit 60f837c605
10 changed files with 73 additions and 23 deletions

View file

@ -18,6 +18,7 @@ use lemmy_db_schema::{
community_block::CommunityBlock, community_block::CommunityBlock,
email_verification::{EmailVerification, EmailVerificationForm}, email_verification::{EmailVerification, EmailVerificationForm},
images::{ImageDetails, RemoteImage}, images::{ImageDetails, RemoteImage},
inbox::Inbox,
instance::Instance, instance::Instance,
instance_block::InstanceBlock, instance_block::InstanceBlock,
local_site::LocalSite, local_site::LocalSite,
@ -973,6 +974,12 @@ pub fn generate_followers_url(actor_id: &DbUrl) -> Result<DbUrl, ParseError> {
Ok(Url::parse(&format!("{actor_id}/followers"))?.into()) Ok(Url::parse(&format!("{actor_id}/followers"))?.into())
} }
pub async fn generate_inbox(context: &LemmyContext) -> Result<Inbox, LemmyError> {
let url = format!("{}/inbox", context.settings().get_protocol_and_hostname());
let parsed = Url::parse(&url)?.into();
Ok(Inbox::read_or_create(&mut context.pool(), &parsed).await?)
}
pub fn generate_inbox_url(actor_id: &DbUrl) -> Result<DbUrl, ParseError> { pub fn generate_inbox_url(actor_id: &DbUrl) -> Result<DbUrl, ParseError> {
Ok(Url::parse(&format!("{actor_id}/inbox"))?.into()) Ok(Url::parse(&format!("{actor_id}/inbox"))?.into())
} }

View file

@ -9,9 +9,8 @@ use lemmy_api_common::{
check_email_verified, check_email_verified,
check_registration_application, check_registration_application,
check_user_valid, check_user_valid,
generate_inbox_url, generate_inbox,
generate_local_apub_endpoint, generate_local_apub_endpoint,
generate_shared_inbox_url,
honeypot_check, honeypot_check,
local_site_to_slur_regex, local_site_to_slur_regex,
password_length_check, password_length_check,
@ -418,8 +417,7 @@ async fn create_person(
// Register the new person // Register the new person
let person_form = PersonInsertForm { let person_form = PersonInsertForm {
actor_id: Some(actor_id.clone()), actor_id: Some(actor_id.clone()),
inbox_url: Some(generate_inbox_url(&actor_id)?), inbox_id: Some(generate_inbox(&context).await?.id),
shared_inbox_url: Some(generate_shared_inbox_url(context.settings())?),
private_key: Some(actor_keypair.private_key), private_key: Some(actor_keypair.private_key),
..PersonInsertForm::new(username.clone(), actor_keypair.public_key, instance_id) ..PersonInsertForm::new(username.clone(), actor_keypair.public_key, instance_id)
}; };

View file

@ -6,10 +6,7 @@ use crate::{
local_site_data_cached, local_site_data_cached,
objects::{instance::fetch_instance_actor_for_object, read_from_string_or_source_opt}, objects::{instance::fetch_instance_actor_for_object, read_from_string_or_source_opt},
protocol::{ protocol::{
objects::{ objects::person::{Person, UserTypes},
person::{Person, UserTypes},
Endpoints,
},
ImageObject, ImageObject,
Source, Source,
}, },
@ -34,6 +31,7 @@ use lemmy_db_schema::{
sensitive::SensitiveString, sensitive::SensitiveString,
source::{ source::{
activity::ActorType, activity::ActorType,
inbox::Inbox,
local_site::LocalSite, local_site::LocalSite,
person::{Person as DbPerson, PersonInsertForm, PersonUpdateForm}, person::{Person as DbPerson, PersonInsertForm, PersonUpdateForm},
}, },
@ -99,7 +97,7 @@ impl Object for ApubPerson {
} }
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
async fn into_json(self, _context: &Data<Self::DataType>) -> LemmyResult<Person> { async fn into_json(self, context: &Data<Self::DataType>) -> LemmyResult<Person> {
let kind = if self.bot_account { let kind = if self.bot_account {
UserTypes::Service UserTypes::Service
} else { } else {
@ -118,12 +116,13 @@ impl Object for ApubPerson {
matrix_user_id: self.matrix_user_id.clone(), matrix_user_id: self.matrix_user_id.clone(),
published: Some(self.published), published: Some(self.published),
outbox: generate_outbox_url(&self.actor_id)?.into(), outbox: generate_outbox_url(&self.actor_id)?.into(),
endpoints: self.shared_inbox_url.clone().map(|s| Endpoints { endpoints: None,
shared_inbox: s.into(),
}),
public_key: self.public_key(), public_key: self.public_key(),
updated: self.updated, updated: self.updated,
inbox: self.inbox_url.clone().into(), inbox: Inbox::read(&mut context.pool(), self.inbox_id)
.await?
.url
.into(),
}; };
Ok(person) Ok(person)
} }
@ -160,6 +159,7 @@ impl Object for ApubPerson {
let bio = markdown_rewrite_remote_links_opt(bio, context).await; let bio = markdown_rewrite_remote_links_opt(bio, context).await;
let avatar = proxy_image_link_opt_apub(person.icon.map(|i| i.url), context).await?; let avatar = proxy_image_link_opt_apub(person.icon.map(|i| i.url), context).await?;
let banner = proxy_image_link_opt_apub(person.image.map(|i| i.url), context).await?; let banner = proxy_image_link_opt_apub(person.image.map(|i| i.url), context).await?;
let inbox = Inbox::read_or_create(&mut context.pool(), &person.inbox.into()).await?;
// Some Mastodon users have `name: ""` (empty string), need to convert that to `None` // Some Mastodon users have `name: ""` (empty string), need to convert that to `None`
// https://github.com/mastodon/mastodon/issues/25233 // https://github.com/mastodon/mastodon/issues/25233
@ -182,8 +182,7 @@ impl Object for ApubPerson {
private_key: None, private_key: None,
public_key: person.public_key.public_key_pem, public_key: person.public_key.public_key_pem,
last_refreshed_at: Some(naive_now()), last_refreshed_at: Some(naive_now()),
inbox_url: Some(person.inbox.into()), inbox_id: Some(inbox.id),
shared_inbox_url: person.endpoints.map(|e| e.shared_inbox.into()),
matrix_user_id: person.matrix_user_id, matrix_user_id: person.matrix_user_id,
instance_id, instance_id,
}; };
@ -209,10 +208,6 @@ impl Actor for ApubPerson {
fn inbox(&self) -> Url { fn inbox(&self) -> Url {
self.inbox_url.clone().into() self.inbox_url.clone().into()
} }
fn shared_inbox(&self) -> Option<Url> {
self.shared_inbox_url.clone().map(Into::into)
}
} }
impl GetActorType for ApubPerson { impl GetActorType for ApubPerson {

View file

@ -0,0 +1,25 @@
use crate::{
newtypes::{DbUrl, InboxId},
schema::inbox,
source::inbox::Inbox,
utils::{get_conn, DbPool},
};
use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl};
use diesel_async::RunQueryDsl;
impl Inbox {
pub async fn read_or_create(pool: &mut DbPool<'_>, inbox: &DbUrl) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?;
insert_into(inbox::table)
.values(inbox::url.eq(inbox))
.on_conflict_do_nothing()
.get_result::<Self>(conn)
.await
}
pub async fn read(pool: &mut DbPool<'_>, id: InboxId) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?;
inbox::table.find(id).first(conn).await
}
}

View file

@ -12,6 +12,7 @@ pub mod federation_allowlist;
pub mod federation_blocklist; pub mod federation_blocklist;
pub mod federation_queue_state; pub mod federation_queue_state;
pub mod images; pub mod images;
pub mod inbox;
pub mod instance; pub mod instance;
pub mod instance_block; pub mod instance_block;
pub mod language; pub mod language;

View file

@ -166,6 +166,11 @@ pub struct RegistrationApplicationId(i32);
/// The oauth provider id. /// The oauth provider id.
pub struct OAuthProviderId(pub i32); pub struct OAuthProviderId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct InboxId(pub i32);
#[cfg(feature = "full")] #[cfg(feature = "full")]
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(remote = "Ltree")] #[serde(remote = "Ltree")]

View file

@ -0,0 +1,18 @@
use crate::newtypes::{DbUrl, InboxId};
#[cfg(feature = "full")]
use crate::schema::inbox;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
#[cfg(feature = "full")]
use ts_rs::TS;
#[skip_serializing_none]
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "full", derive(Queryable, Selectable, Identifiable, TS))]
#[cfg_attr(feature = "full", diesel(table_name = inbox))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))]
pub struct Inbox {
pub id: InboxId,
pub url: DbUrl,
}

View file

@ -17,6 +17,7 @@ pub mod federation_allowlist;
pub mod federation_blocklist; pub mod federation_blocklist;
pub mod federation_queue_state; pub mod federation_queue_state;
pub mod images; pub mod images;
pub mod inbox;
pub mod instance; pub mod instance;
pub mod instance_block; pub mod instance_block;
pub mod language; pub mod language;

View file

@ -1,7 +1,7 @@
#[cfg(feature = "full")] #[cfg(feature = "full")]
use crate::schema::{person, person_follower}; use crate::schema::{person, person_follower};
use crate::{ use crate::{
newtypes::{DbUrl, InstanceId, PersonId}, newtypes::{DbUrl, InboxId, InstanceId, PersonId},
sensitive::SensitiveString, sensitive::SensitiveString,
}; };
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
@ -53,7 +53,7 @@ pub struct Person {
pub instance_id: InstanceId, pub instance_id: InstanceId,
#[cfg_attr(feature = "full", ts(skip))] #[cfg_attr(feature = "full", ts(skip))]
#[serde(skip, default)] #[serde(skip, default)]
pub inbox_id: i32, pub inbox_id: InboxId,
} }
#[derive(Clone, derive_new::new)] #[derive(Clone, derive_new::new)]
@ -88,7 +88,7 @@ pub struct PersonInsertForm {
#[new(default)] #[new(default)]
pub deleted: Option<bool>, pub deleted: Option<bool>,
#[new(default)] #[new(default)]
pub inbox_id: Option<i32>, pub inbox_id: Option<InboxId>,
#[new(default)] #[new(default)]
pub matrix_user_id: Option<String>, pub matrix_user_id: Option<String>,
#[new(default)] #[new(default)]

View file

@ -4,7 +4,7 @@
-- TODO: add trigger which removes unused inbox items -- TODO: add trigger which removes unused inbox items
CREATE TABLE inbox ( CREATE TABLE inbox (
id serial PRIMARY KEY, id serial PRIMARY KEY,
url varchar(255) NOT NULL url varchar(255) NOT NULL UNIQUE
); );
-- Move existing inbox values to inbox table, and replace with foreign key -- Move existing inbox values to inbox table, and replace with foreign key