"lemmy_db_schema",
"log",
"serde 1.0.123",
+ "url",
]
[[package]]
Perform,
};
use actix_web::web::Data;
-use lemmy_apub::{ApubLikeableType, ApubObjectType};
+use lemmy_apub::{generate_apub_endpoint, ApubLikeableType, ApubObjectType, EndpointType};
use lemmy_db_queries::{
source::comment::Comment_,
Crud,
};
use lemmy_structs::{blocking, comment::*, send_local_notifs};
use lemmy_utils::{
- apub::{make_apub_endpoint, EndpointType},
utils::{remove_slurs, scrape_text_for_mentions},
APIError,
ConnectionId,
// Necessary to update the ap_id
let inserted_comment_id = inserted_comment.id;
- let updated_comment: Comment = match blocking(context.pool(), move |conn| {
- let apub_id =
- make_apub_endpoint(EndpointType::Comment, &inserted_comment_id.to_string()).to_string();
- Comment::update_ap_id(&conn, inserted_comment_id, apub_id)
- })
- .await?
- {
- Ok(comment) => comment,
- Err(_e) => return Err(APIError::err("couldnt_create_comment").into()),
- };
+ let updated_comment: Comment =
+ match blocking(context.pool(), move |conn| -> Result<Comment, LemmyError> {
+ let apub_id =
+ generate_apub_endpoint(EndpointType::Comment, &inserted_comment_id.to_string())?;
+ Ok(Comment::update_ap_id(&conn, inserted_comment_id, apub_id)?)
+ })
+ .await?
+ {
+ Ok(comment) => comment,
+ Err(_e) => return Err(APIError::err("couldnt_create_comment").into()),
+ };
updated_comment.send_create(&user, context).await?;
};
use actix_web::web::Data;
use anyhow::Context;
-use lemmy_apub::ActorType;
+use lemmy_apub::{
+ generate_apub_endpoint,
+ generate_followers_url,
+ generate_inbox_url,
+ generate_shared_inbox_url,
+ ActorType,
+ EndpointType,
+};
use lemmy_db_queries::{
diesel_option_overwrite,
source::{
};
use lemmy_structs::{blocking, community::*};
use lemmy_utils::{
- apub::{generate_actor_keypair, make_apub_endpoint, EndpointType},
+ apub::generate_actor_keypair,
location_info,
utils::{check_slurs, check_slurs_opt, is_valid_community_name, naive_from_unix},
APIError,
}
// Double check for duplicate community actor_ids
- let actor_id = make_apub_endpoint(EndpointType::Community, &data.name);
- let actor_id_cloned = actor_id.to_owned();
+ let community_actor_id = generate_apub_endpoint(EndpointType::Community, &data.name)?;
+ let actor_id_cloned = community_actor_id.to_owned();
let community_dupe = blocking(context.pool(), move |conn| {
- Community::read_from_apub_id(conn, &actor_id_cloned.into())
+ Community::read_from_apub_id(conn, &actor_id_cloned)
})
.await?;
if community_dupe.is_ok() {
deleted: None,
nsfw: data.nsfw,
updated: None,
- actor_id: Some(actor_id.into()),
+ actor_id: Some(community_actor_id.to_owned()),
local: true,
private_key: Some(keypair.private_key),
public_key: Some(keypair.public_key),
last_refreshed_at: None,
published: None,
+ followers_url: Some(generate_followers_url(&community_actor_id)?),
+ inbox_url: Some(generate_inbox_url(&community_actor_id)?),
+ shared_inbox_url: Some(Some(generate_shared_inbox_url(&community_actor_id)?)),
};
let inserted_community = match blocking(context.pool(), move |conn| {
public_key: read_community.public_key,
last_refreshed_at: None,
published: None,
+ followers_url: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let community_id = data.community_id;
Perform,
};
use actix_web::web::Data;
-use lemmy_apub::{ApubLikeableType, ApubObjectType};
+use lemmy_apub::{generate_apub_endpoint, ApubLikeableType, ApubObjectType, EndpointType};
use lemmy_db_queries::{
source::post::Post_,
Crud,
};
use lemmy_structs::{blocking, post::*};
use lemmy_utils::{
- apub::{make_apub_endpoint, EndpointType},
request::fetch_iframely_and_pictrs_data,
utils::{check_slurs, check_slurs_opt, is_valid_post_title},
APIError,
};
let inserted_post_id = inserted_post.id;
- let updated_post = match blocking(context.pool(), move |conn| {
- let apub_id =
- make_apub_endpoint(EndpointType::Post, &inserted_post_id.to_string()).to_string();
- Post::update_ap_id(conn, inserted_post_id, apub_id)
+ let updated_post = match blocking(context.pool(), move |conn| -> Result<Post, LemmyError> {
+ let apub_id = generate_apub_endpoint(EndpointType::Post, &inserted_post_id.to_string())?;
+ Ok(Post::update_ap_id(conn, inserted_post_id, apub_id)?)
})
.await?
{
use bcrypt::verify;
use captcha::{gen, Difficulty};
use chrono::Duration;
-use lemmy_apub::ApubObjectType;
+use lemmy_apub::{
+ generate_apub_endpoint,
+ generate_followers_url,
+ generate_inbox_url,
+ generate_shared_inbox_url,
+ ApubObjectType,
+ EndpointType,
+};
use lemmy_db_queries::{
diesel_option_overwrite,
source::{
};
use lemmy_structs::{blocking, send_email_to_user, user::*};
use lemmy_utils::{
- apub::{generate_actor_keypair, make_apub_endpoint, EndpointType},
+ apub::generate_actor_keypair,
email::send_email,
location_info,
settings::Settings,
if !is_valid_username(&data.username) {
return Err(APIError::err("invalid_username").into());
}
+ let user_actor_id = generate_apub_endpoint(EndpointType::User, &data.username)?;
// Register the new user
let user_form = UserForm {
lang: "browser".into(),
show_avatars: true,
send_notifications_to_email: false,
- actor_id: Some(make_apub_endpoint(EndpointType::User, &data.username).into()),
+ actor_id: Some(user_actor_id.clone()),
bio: None,
local: true,
private_key: Some(user_keypair.private_key),
public_key: Some(user_keypair.public_key),
last_refreshed_at: None,
+ inbox_url: Some(generate_inbox_url(&user_actor_id)?),
+ shared_inbox_url: Some(Some(generate_shared_inbox_url(&user_actor_id)?)),
};
// Create the user
Ok(c) => c,
Err(_e) => {
let default_community_name = "main";
+ let actor_id = generate_apub_endpoint(EndpointType::Community, default_community_name)?;
let community_form = CommunityForm {
name: default_community_name.to_string(),
title: "The Default Community".to_string(),
removed: None,
deleted: None,
updated: None,
- actor_id: Some(
- make_apub_endpoint(EndpointType::Community, default_community_name).into(),
- ),
+ actor_id: Some(actor_id.to_owned()),
local: true,
private_key: Some(main_community_keypair.private_key),
public_key: Some(main_community_keypair.public_key),
published: None,
icon: None,
banner: None,
+ followers_url: Some(generate_followers_url(&actor_id)?),
+ inbox_url: Some(generate_inbox_url(&actor_id)?),
+ shared_inbox_url: Some(Some(generate_shared_inbox_url(&actor_id)?)),
};
blocking(context.pool(), move |conn| {
Community::create(conn, &community_form)
matrix_user_id,
avatar,
banner,
+ inbox_url: None,
password_encrypted,
preferred_username,
published: Some(user.published),
private_key: user.private_key,
public_key: user.public_key,
last_refreshed_at: None,
+ shared_inbox_url: None,
};
let res = blocking(context.pool(), move |conn| {
};
let inserted_private_message_id = inserted_private_message.id;
- let updated_private_message = match blocking(context.pool(), move |conn| {
- let apub_id = make_apub_endpoint(
- EndpointType::PrivateMessage,
- &inserted_private_message_id.to_string(),
- )
- .to_string();
- PrivateMessage::update_ap_id(&conn, inserted_private_message_id, apub_id)
- })
+ let updated_private_message = match blocking(
+ context.pool(),
+ move |conn| -> Result<PrivateMessage, LemmyError> {
+ let apub_id = generate_apub_endpoint(
+ EndpointType::PrivateMessage,
+ &inserted_private_message_id.to_string(),
+ )?;
+ Ok(PrivateMessage::update_ap_id(
+ &conn,
+ inserted_private_message_id,
+ apub_id,
+ )?)
+ },
+ )
.await?
{
Ok(private_message) => private_message,
let parent_creator = get_comment_parent_creator(context.pool(), comment).await?;
let mut addressed_ccs = vec![community.actor_id(), parent_creator.actor_id()];
// Note: dont include community inbox here, as we send to it separately with `send_to_community()`
- let mut inboxes = vec![parent_creator.get_shared_inbox_url()?];
+ let mut inboxes = vec![parent_creator.get_shared_inbox_or_inbox_url()];
// Add the mention tag
let mut tags = Vec::new();
addressed_ccs.push(actor_id.to_owned().to_string().parse()?);
let mention_user = get_or_fetch_and_upsert_user(&actor_id, context, &mut 0).await?;
- inboxes.push(mention_user.get_shared_inbox_url()?);
+ inboxes.push(mention_user.get_shared_inbox_or_inbox_url());
let mut mention_tag = Mention::new();
mention_tag.set_href(actor_id).set_name(mention.full_name());
use lemmy_db_schema::source::community::Community;
use lemmy_db_views_actor::community_follower_view::CommunityFollowerView;
use lemmy_structs::blocking;
-use lemmy_utils::{location_info, settings::Settings, LemmyError};
+use lemmy_utils::{location_info, LemmyError};
use lemmy_websocket::LemmyContext;
use url::Url;
#[async_trait::async_trait(?Send)]
impl ActorType for Community {
+ fn is_local(&self) -> bool {
+ self.local
+ }
fn actor_id(&self) -> Url {
self.actor_id.to_owned().into_inner()
}
-
fn public_key(&self) -> Option<String> {
self.public_key.to_owned()
}
self.private_key.to_owned()
}
+ fn get_shared_inbox_or_inbox_url(&self) -> Url {
+ self
+ .shared_inbox_url
+ .clone()
+ .unwrap_or_else(|| self.inbox_url.to_owned())
+ .into()
+ }
+
async fn send_follow(
&self,
_follow_actor_id: &Url,
.set_id(generate_activity_id(AcceptType::Accept)?)
.set_to(user.actor_id());
- send_activity_single_dest(accept, self, user.get_inbox_url()?, context).await?;
+ send_activity_single_dest(accept, self, user.inbox_url.into(), context).await?;
Ok(())
}
.set_many_contexts(lemmy_context()?)
.set_id(generate_activity_id(DeleteType::Delete)?)
.set_to(public())
- .set_many_ccs(vec![self.get_followers_url()?]);
+ .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
send_to_community_followers(delete, self, context).await?;
Ok(())
.set_many_contexts(lemmy_context()?)
.set_id(generate_activity_id(DeleteType::Delete)?)
.set_to(public())
- .set_many_ccs(vec![self.get_followers_url()?]);
+ .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
let mut undo = Undo::new(self.actor_id(), delete.into_any_base()?);
undo
.set_many_contexts(lemmy_context()?)
.set_id(generate_activity_id(UndoType::Undo)?)
.set_to(public())
- .set_many_ccs(vec![self.get_followers_url()?]);
+ .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
send_to_community_followers(undo, self, context).await?;
Ok(())
.set_many_contexts(lemmy_context()?)
.set_id(generate_activity_id(RemoveType::Remove)?)
.set_to(public())
- .set_many_ccs(vec![self.get_followers_url()?]);
+ .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
send_to_community_followers(remove, self, context).await?;
Ok(())
.set_many_contexts(lemmy_context()?)
.set_id(generate_activity_id(RemoveType::Remove)?)
.set_to(public())
- .set_many_ccs(vec![self.get_followers_url()?]);
+ .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
// Undo that fake activity
let mut undo = Undo::new(self.actor_id(), remove.into_any_base()?);
.set_many_contexts(lemmy_context()?)
.set_id(generate_activity_id(LikeType::Like)?)
.set_to(public())
- .set_many_ccs(vec![self.get_followers_url()?]);
+ .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
send_to_community_followers(undo, self, context).await?;
Ok(())
.set_many_contexts(lemmy_context()?)
.set_id(generate_activity_id(AnnounceType::Announce)?)
.set_to(public())
- .set_many_ccs(vec![self.get_followers_url()?]);
+ .set_many_ccs(vec![self.followers_url.clone().into_inner()]);
send_to_community_followers(announce, self, context).await?;
}
/// For a given community, returns the inboxes of all followers.
- ///
- /// TODO: this function is very badly implemented, we should just store shared_inbox_url in
- /// CommunityFollowerView
async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError> {
let id = self.id;
- let inboxes = blocking(pool, move |conn| {
+ let follows = blocking(pool, move |conn| {
CommunityFollowerView::for_community(conn, id)
})
.await??;
- let inboxes = inboxes
+ let inboxes = follows
.into_iter()
- .filter(|i| !i.follower.local)
- .map(|u| -> Result<Url, LemmyError> {
- let url = u.follower.actor_id.into_inner();
- let domain = url.domain().context(location_info!())?;
- let port = if let Some(port) = url.port() {
- format!(":{}", port)
- } else {
- "".to_string()
- };
- Ok(Url::parse(&format!(
- "{}://{}{}/inbox",
- Settings::get().get_protocol_string(),
- domain,
- port,
- ))?)
- })
- .filter_map(Result::ok)
+ .filter(|f| !f.follower.local)
+ .map(|f| f.follower.shared_inbox_url.unwrap_or(f.follower.inbox_url))
+ .map(|i| i.into_inner())
+ .unique()
// Don't send to blocked instances
.filter(|inbox| check_is_apub_id_valid(inbox).is_ok())
- .unique()
.collect();
Ok(inboxes)
.set_id(generate_activity_id(CreateType::Create)?)
.set_to(recipient.actor_id());
- send_activity_single_dest(create, creator, recipient.get_inbox_url()?, context).await?;
+ send_activity_single_dest(create, creator, recipient.inbox_url.into(), context).await?;
Ok(())
}
.set_id(generate_activity_id(UpdateType::Update)?)
.set_to(recipient.actor_id());
- send_activity_single_dest(update, creator, recipient.get_inbox_url()?, context).await?;
+ send_activity_single_dest(update, creator, recipient.inbox_url.into(), context).await?;
Ok(())
}
.set_id(generate_activity_id(DeleteType::Delete)?)
.set_to(recipient.actor_id());
- send_activity_single_dest(delete, creator, recipient.get_inbox_url()?, context).await?;
+ send_activity_single_dest(delete, creator, recipient.inbox_url.into(), context).await?;
Ok(())
}
.set_id(generate_activity_id(UndoType::Undo)?)
.set_to(recipient.actor_id());
- send_activity_single_dest(undo, creator, recipient.get_inbox_url()?, context).await?;
+ send_activity_single_dest(undo, creator, recipient.inbox_url.into(), context).await?;
Ok(())
}
#[async_trait::async_trait(?Send)]
impl ActorType for User_ {
+ fn is_local(&self) -> bool {
+ self.local
+ }
fn actor_id(&self) -> Url {
self.actor_id.to_owned().into_inner()
}
self.private_key.to_owned()
}
+ fn get_shared_inbox_or_inbox_url(&self) -> Url {
+ self
+ .shared_inbox_url
+ .clone()
+ .unwrap_or_else(|| self.inbox_url.to_owned())
+ .into()
+ }
+
/// As a given local user, send out a follow request to a remote community.
async fn send_follow(
&self,
.set_id(generate_activity_id(FollowType::Follow)?)
.set_to(community.actor_id());
- send_activity_single_dest(follow, self, community.get_inbox_url()?, context).await?;
+ send_activity_single_dest(follow, self, community.inbox_url.into(), context).await?;
Ok(())
}
.set_id(generate_activity_id(UndoType::Undo)?)
.set_to(community.actor_id());
- send_activity_single_dest(undo, self, community.get_inbox_url()?, context).await?;
+ send_activity_single_dest(undo, self, community.inbox_url.into(), context).await?;
Ok(())
}
.collect();
debug!(
"Sending activity {:?} to followers of {}",
- &activity.id_unchecked(),
+ &activity.id_unchecked().map(|i| i.to_string()),
&community.actor_id
);
.send_announce(activity.into_any_base()?, context)
.await?;
} else {
- let inbox = community.get_shared_inbox_url()?;
+ let inbox = community.get_shared_inbox_or_inbox_url();
check_is_apub_id_valid(&inbox)?;
debug!(
"Sending activity {:?} to community {}",
},
inbox::user_inbox::receive_announce,
objects::FromApub,
- ActorType,
GroupExt,
};
use activitystreams::{
+ actor::ApActorExt,
collection::{CollectionExt, OrderedCollection},
object::ObjectExt,
};
// only fetch outbox for new communities, otherwise this can create an infinite loop
if old_community.is_none() {
- fetch_community_outbox(context, &community, recursion_counter).await?
+ let outbox = group.inner.outbox()?.context(location_info!())?;
+ fetch_community_outbox(context, outbox, &community, recursion_counter).await?
}
Ok(community)
async fn fetch_community_outbox(
context: &LemmyContext,
+ outbox: &Url,
community: &Community,
recursion_counter: &mut i32,
) -> Result<(), LemmyError> {
- let outbox = fetch_remote_object::<OrderedCollection>(
- context.client(),
- &community.get_outbox_url()?,
- recursion_counter,
- )
- .await?;
+ let outbox =
+ fetch_remote_object::<OrderedCollection>(context.client(), outbox, recursion_counter).await?;
let outbox_activities = outbox.items().context(location_info!())?.clone();
let mut outbox_activities = outbox_activities.many().context(location_info!())?;
if outbox_activities.len() > 20 {
let mut collection = UnorderedCollection::new();
collection
.set_many_contexts(lemmy_context()?)
- .set_id(community.get_followers_url()?)
+ .set_id(community.followers_url.into())
.set_total_items(community_followers.len() as u64);
Ok(create_apub_response(&collection))
}
};
use actix_web::HttpRequest;
use anyhow::{anyhow, Context};
-use lemmy_db_queries::{source::activity::Activity_, ApubObject, DbPool};
+use lemmy_db_queries::{
+ source::{activity::Activity_, community::Community_},
+ ApubObject,
+ DbPool,
+};
use lemmy_db_schema::source::{activity::Activity, community::Community, user::User_};
use lemmy_structs::blocking;
use lemmy_utils::{location_info, settings::Settings, LemmyError};
pool: &DbPool,
) -> Result<Option<Community>, LemmyError> {
for url in to_and_cc {
- let url = url.to_string();
- // TODO: extremely hacky, we should just store the followers url for each community in the db
- if url.ends_with("/followers") {
- let community_url = Url::parse(&url.replace("/followers", ""))?;
- let community = blocking(&pool, move |conn| {
- Community::read_from_apub_id(&conn, &community_url.into())
- })
- .await??;
- if !community.local {
- return Ok(Some(community));
+ let url = url.to_owned().into();
+ let community = blocking(&pool, move |conn| {
+ // ignore errors here, because the current url might not actually be a followers url
+ Community::read_from_followers_url(&conn, &url).ok()
+ })
+ .await?;
+ if let Some(c) = community {
+ if !c.local {
+ return Ok(Some(c));
}
}
}
/// implemented by all actors.
#[async_trait::async_trait(?Send)]
pub trait ActorType {
+ fn is_local(&self) -> bool;
fn actor_id(&self) -> Url;
// TODO: every actor should have a public key, so this shouldnt be an option (needs to be fixed in db)
/// For a given community, returns the inboxes of all followers.
async fn get_follower_inboxes(&self, pool: &DbPool) -> Result<Vec<Url>, LemmyError>;
- // TODO move these to the db rows
- fn get_inbox_url(&self) -> Result<Url, ParseError> {
- Url::parse(&format!("{}/inbox", &self.actor_id()))
- }
-
- fn get_shared_inbox_url(&self) -> Result<Url, LemmyError> {
- let actor_id = self.actor_id();
- let url = format!(
- "{}://{}{}/inbox",
- &actor_id.scheme(),
- &actor_id.host_str().context(location_info!())?,
- if let Some(port) = actor_id.port() {
- format!(":{}", port)
- } else {
- "".to_string()
- },
- );
- Ok(Url::parse(&url)?)
- }
-
- fn get_outbox_url(&self) -> Result<Url, ParseError> {
- Url::parse(&format!("{}/outbox", &self.actor_id()))
- }
+ fn get_shared_inbox_or_inbox_url(&self) -> Url;
- fn get_followers_url(&self) -> Result<Url, ParseError> {
- Url::parse(&format!("{}/followers", &self.actor_id()))
+ /// Outbox URL is not generally used by Lemmy, so it can be generated on the fly (but only for
+ /// local actors).
+ fn get_outbox_url(&self) -> Result<Url, LemmyError> {
+ if !self.is_local() {
+ return Err(anyhow!("get_outbox_url() called for remote actor").into());
+ }
+ Ok(Url::parse(&format!("{}/outbox", &self.actor_id()))?)
}
fn get_public_key_ext(&self) -> Result<PublicKeyExtension, LemmyError> {
}
}
+pub enum EndpointType {
+ Community,
+ User,
+ Post,
+ Comment,
+ PrivateMessage,
+}
+
+/// Generates the ActivityPub ID for a given object type and ID.
+pub fn generate_apub_endpoint(
+ endpoint_type: EndpointType,
+ name: &str,
+) -> Result<lemmy_db_schema::Url, ParseError> {
+ let point = match endpoint_type {
+ EndpointType::Community => "c",
+ EndpointType::User => "u",
+ EndpointType::Post => "post",
+ EndpointType::Comment => "comment",
+ EndpointType::PrivateMessage => "private_message",
+ };
+
+ Ok(
+ Url::parse(&format!(
+ "{}/{}/{}",
+ Settings::get().get_protocol_and_hostname(),
+ point,
+ name
+ ))?
+ .into(),
+ )
+}
+
+pub fn generate_followers_url(
+ actor_id: &lemmy_db_schema::Url,
+) -> Result<lemmy_db_schema::Url, ParseError> {
+ Ok(Url::parse(&format!("{}/followers", actor_id))?.into())
+}
+
+pub fn generate_inbox_url(
+ actor_id: &lemmy_db_schema::Url,
+) -> Result<lemmy_db_schema::Url, ParseError> {
+ Ok(Url::parse(&format!("{}/inbox", actor_id))?.into())
+}
+
+pub fn generate_shared_inbox_url(
+ actor_id: &lemmy_db_schema::Url,
+) -> Result<lemmy_db_schema::Url, LemmyError> {
+ let actor_id = actor_id.clone().into_inner();
+ let url = format!(
+ "{}://{}{}/inbox",
+ &actor_id.scheme(),
+ &actor_id.host_str().context(location_info!())?,
+ if let Some(port) = actor_id.port() {
+ format!(":{}", port)
+ } else {
+ "".to_string()
+ },
+ );
+ Ok(Url::parse(&url)?.into())
+}
+
/// Store a sent or received activity in the database, for logging purposes. These records are not
/// persistent.
pub(crate) async fn insert_activity<T>(
group.set_image(image.into_any_base()?);
}
- let mut ap_actor = ApActor::new(self.get_inbox_url()?, group);
+ let mut ap_actor = ApActor::new(self.inbox_url.clone().into(), group);
ap_actor
.set_preferred_username(self.name.to_owned())
.set_outbox(self.get_outbox_url()?)
- .set_followers(self.get_followers_url()?)
+ .set_followers(self.followers_url.clone().into())
.set_endpoints(Endpoints {
- shared_inbox: Some(self.get_shared_inbox_url()?),
+ shared_inbox: Some(self.get_shared_inbox_or_inbox_url()),
..Default::default()
});
),
None => None,
};
-
let banner = match group.image() {
Some(any_image) => Some(
Image::from_any_base(any_image.as_one().context(location_info!())?.clone())
),
None => None,
};
+ let shared_inbox = group
+ .inner
+ .endpoints()?
+ .map(|e| e.shared_inbox)
+ .flatten()
+ .map(|s| s.to_owned().into());
Ok(CommunityForm {
name,
last_refreshed_at: Some(naive_now()),
icon,
banner,
+ followers_url: Some(
+ group
+ .inner
+ .followers()?
+ .context(location_info!())?
+ .to_owned()
+ .into(),
+ ),
+ inbox_url: Some(group.inner.inbox()?.to_owned().into()),
+ shared_inbox_url: Some(shared_inbox),
})
}
}
person.set_name(i);
}
- let mut ap_actor = ApActor::new(self.get_inbox_url()?, person);
+ let mut ap_actor = ApActor::new(self.inbox_url.clone().into(), person);
ap_actor
.set_preferred_username(self.name.to_owned())
.set_outbox(self.get_outbox_url()?)
.set_endpoints(Endpoints {
- shared_inbox: Some(self.get_shared_inbox_url()?),
+ shared_inbox: Some(self.get_shared_inbox_or_inbox_url()),
..Default::default()
});
.flatten()
.map(|n| n.to_owned().xsd_string())
.flatten();
-
let bio = get_source_markdown_value(person)?;
+ let shared_inbox = person
+ .inner
+ .endpoints()?
+ .map(|e| e.shared_inbox)
+ .flatten()
+ .map(|s| s.to_owned().into());
check_slurs(&name)?;
check_slurs_opt(&preferred_username)?;
private_key: None,
public_key: Some(person.ext_one.public_key.to_owned().public_key_pem),
last_refreshed_at: Some(naive_now()),
+ inbox_url: Some(person.inner.inbox()?.to_owned().into()),
+ shared_inbox_url: Some(shared_inbox),
})
}
}
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let another_inserted_user = User_::create(&conn, &another_user).unwrap();
published: None,
icon: None,
banner: None,
+ followers_url: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let another_inserted_user = User_::create(&conn, &another_user).unwrap();
published: None,
icon: None,
banner: None,
+ followers_url: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
published: None,
icon: None,
banner: None,
+ followers_url: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let another_inserted_community = Community::create(&conn, &another_community).unwrap();
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let another_inserted_user = User_::create(&conn, &another_user).unwrap();
published: None,
icon: None,
banner: None,
+ followers_url: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
published: None,
icon: None,
banner: None,
+ followers_url: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let another_inserted_user = User_::create(&conn, &another_user).unwrap();
published: None,
icon: None,
banner: None,
+ followers_url: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_creator = User_::create(&conn, &creator_form).unwrap();
};
pub trait Comment_ {
- fn update_ap_id(conn: &PgConnection, comment_id: i32, apub_id: String) -> Result<Comment, Error>;
+ fn update_ap_id(conn: &PgConnection, comment_id: i32, apub_id: Url) -> Result<Comment, Error>;
fn permadelete_for_creator(
conn: &PgConnection,
for_creator_id: i32,
}
impl Comment_ for Comment {
- fn update_ap_id(conn: &PgConnection, comment_id: i32, apub_id: String) -> Result<Self, Error> {
+ fn update_ap_id(conn: &PgConnection, comment_id: i32, apub_id: Url) -> Result<Self, Error> {
use lemmy_db_schema::schema::comment::dsl::*;
diesel::update(comment.find(comment_id))
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
published: None,
banner: None,
icon: None,
+ inbox_url: None,
+ shared_inbox_url: None,
+ followers_url: None,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
new_creator_id: i32,
) -> Result<Community, Error>;
fn distinct_federated_communities(conn: &PgConnection) -> Result<Vec<String>, Error>;
+ fn read_from_followers_url(conn: &PgConnection, followers_url: &Url) -> Result<Community, Error>;
}
impl Community_ for Community {
use lemmy_db_schema::schema::community::dsl::*;
community.select(actor_id).distinct().load::<String>(conn)
}
+
+ fn read_from_followers_url(
+ conn: &PgConnection,
+ followers_url_: &Url,
+ ) -> Result<Community, Error> {
+ use lemmy_db_schema::schema::community::dsl::*;
+ community
+ .filter(followers_url.eq(followers_url_))
+ .first::<Self>(conn)
+ }
}
impl Joinable<CommunityModeratorForm> for CommunityModerator {
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
published: None,
icon: None,
banner: None,
+ followers_url: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
last_refreshed_at: inserted_community.published,
icon: None,
banner: None,
+ followers_url: inserted_community.followers_url.to_owned(),
+ inbox_url: inserted_community.inbox_url.to_owned(),
+ shared_inbox_url: None,
};
let community_follower_form = CommunityFollowerForm {
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_mod = User_::create(&conn, &new_mod).unwrap();
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
published: None,
icon: None,
banner: None,
+ followers_url: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
pub trait Post_ {
//fn read(conn: &PgConnection, post_id: i32) -> Result<Post, Error>;
fn list_for_community(conn: &PgConnection, the_community_id: i32) -> Result<Vec<Post>, Error>;
- fn update_ap_id(conn: &PgConnection, post_id: i32, apub_id: String) -> Result<Post, Error>;
+ fn update_ap_id(conn: &PgConnection, post_id: i32, apub_id: Url) -> Result<Post, Error>;
fn permadelete_for_creator(conn: &PgConnection, for_creator_id: i32) -> Result<Vec<Post>, Error>;
fn update_deleted(conn: &PgConnection, post_id: i32, new_deleted: bool) -> Result<Post, Error>;
fn update_removed(conn: &PgConnection, post_id: i32, new_removed: bool) -> Result<Post, Error>;
.load::<Self>(conn)
}
- fn update_ap_id(conn: &PgConnection, post_id: i32, apub_id: String) -> Result<Self, Error> {
+ fn update_ap_id(conn: &PgConnection, post_id: i32, apub_id: Url) -> Result<Self, Error> {
use lemmy_db_schema::schema::post::dsl::*;
diesel::update(post.find(post_id))
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
published: None,
icon: None,
banner: None,
+ followers_url: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
fn update_ap_id(
conn: &PgConnection,
private_message_id: i32,
- apub_id: String,
+ apub_id: Url,
) -> Result<PrivateMessage, Error>;
fn update_content(
conn: &PgConnection,
fn update_ap_id(
conn: &PgConnection,
private_message_id: i32,
- apub_id: String,
+ apub_id: Url,
) -> Result<PrivateMessage, Error> {
use lemmy_db_schema::schema::private_message::dsl::*;
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_creator = User_::create(&conn, &creator_form).unwrap();
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_recipient = User_::create(&conn, &recipient_form).unwrap();
local,
banner,
deleted,
+ inbox_url,
+ shared_inbox_url,
);
impl ToSafe for User_ {
local,
banner,
deleted,
+ inbox_url,
+ shared_inbox_url,
)
}
}
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
public_key: None,
last_refreshed_at: inserted_user.published,
deleted: false,
+ inbox_url: inserted_user.inbox_url.to_owned(),
+ shared_inbox_url: None,
};
let read_user = User_::read(&conn, inserted_user.id).unwrap();
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_recipient = User_::create(&conn, &recipient_form).unwrap();
published: None,
icon: None,
banner: None,
+ followers_url: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
last_refreshed_at -> Timestamp,
icon -> Nullable<Text>,
banner -> Nullable<Text>,
+ followers_url -> Text,
+ inbox_url -> Text,
+ shared_inbox_url -> Nullable<Text>,
}
}
last_refreshed_at -> Timestamp,
banner -> Nullable<Text>,
deleted -> Bool,
+ inbox_url -> Text,
+ shared_inbox_url -> Nullable<Text>,
}
}
pub last_refreshed_at: chrono::NaiveDateTime,
pub icon: Option<String>,
pub banner: Option<String>,
+ pub followers_url: Url,
+ pub inbox_url: Url,
+ pub shared_inbox_url: Option<Url>,
}
/// A safe representation of community, without the sensitive info
pub last_refreshed_at: Option<chrono::NaiveDateTime>,
pub icon: Option<Option<String>>,
pub banner: Option<Option<String>>,
+ pub followers_url: Option<Url>,
+ pub inbox_url: Option<Url>,
+ pub shared_inbox_url: Option<Option<Url>>,
}
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
pub last_refreshed_at: chrono::NaiveDateTime,
pub banner: Option<String>,
pub deleted: bool,
+ pub inbox_url: Url,
+ pub shared_inbox_url: Option<Url>,
}
/// A safe representation of user, without the sensitive info
pub local: bool,
pub banner: Option<String>,
pub deleted: bool,
+ pub inbox_url: Url,
+ pub shared_inbox_url: Option<Url>,
}
/// A safe user view with only settings
pub public_key: Option<String>,
pub last_refreshed_at: Option<chrono::NaiveDateTime>,
pub banner: Option<Option<String>>,
+ pub inbox_url: Option<Url>,
+ pub shared_inbox_url: Option<Option<Url>>,
}
diesel = { version = "1.4.5", features = ["postgres","chrono","r2d2","serde_json"] }
serde = { version = "1.0.123", features = ["derive"] }
log = "0.4.14"
+url = "2.2.0"
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
published: None,
icon: None,
banner: None,
+ followers_url: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
admin: false,
updated: None,
matrix_user_id: None,
+ inbox_url: inserted_user.inbox_url.to_owned(),
+ shared_inbox_url: None,
},
recipient: None,
post: Post {
private_key: None,
public_key: None,
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_user = User_::create(&conn, &new_user).unwrap();
published: None,
icon: None,
banner: None,
+ followers_url: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
let inserted_community = Community::create(&conn, &new_community).unwrap();
admin: false,
updated: None,
matrix_user_id: None,
+ inbox_url: inserted_user.inbox_url.to_owned(),
+ shared_inbox_url: None,
},
creator_banned_from_community: false,
community: CommunitySafe {
-use crate::settings::Settings;
use openssl::{pkey::PKey, rsa::Rsa};
use std::io::{Error, ErrorKind};
-use url::Url;
pub struct Keypair {
pub private_key: String,
public_key: key_to_string(public_key)?,
})
}
-
-pub enum EndpointType {
- Community,
- User,
- Post,
- Comment,
- PrivateMessage,
-}
-
-/// Generates the ActivityPub ID for a given object type and ID.
-pub fn make_apub_endpoint(endpoint_type: EndpointType, name: &str) -> Url {
- let point = match endpoint_type {
- EndpointType::Community => "c",
- EndpointType::User => "u",
- EndpointType::Post => "post",
- EndpointType::Comment => "comment",
- EndpointType::PrivateMessage => "private_message",
- };
-
- Url::parse(&format!(
- "{}/{}/{}",
- Settings::get().get_protocol_and_hostname(),
- point,
- name
- ))
- .unwrap()
-}
--- /dev/null
+table! {
+ activity (id) {
+ id -> Int4,
+ data -> Jsonb,
+ local -> Bool,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ ap_id -> Nullable<Text>,
+ sensitive -> Nullable<Bool>,
+ }
+}
+
+table! {
+ category (id) {
+ id -> Int4,
+ name -> Varchar,
+ }
+}
+
+table! {
+ comment (id) {
+ id -> Int4,
+ creator_id -> Int4,
+ post_id -> Int4,
+ parent_id -> Nullable<Int4>,
+ content -> Text,
+ removed -> Bool,
+ read -> Bool,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ deleted -> Bool,
+ ap_id -> Varchar,
+ local -> Bool,
+ }
+}
+
+table! {
+ comment_aggregates (id) {
+ id -> Int4,
+ comment_id -> Int4,
+ score -> Int8,
+ upvotes -> Int8,
+ downvotes -> Int8,
+ published -> Timestamp,
+ }
+}
+
+table! {
+ comment_like (id) {
+ id -> Int4,
+ user_id -> Int4,
+ comment_id -> Int4,
+ post_id -> Int4,
+ score -> Int2,
+ published -> Timestamp,
+ }
+}
+
+table! {
+ comment_report (id) {
+ id -> Int4,
+ creator_id -> Int4,
+ comment_id -> Int4,
+ original_comment_text -> Text,
+ reason -> Text,
+ resolved -> Bool,
+ resolver_id -> Nullable<Int4>,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ }
+}
+
+table! {
+ comment_saved (id) {
+ id -> Int4,
+ comment_id -> Int4,
+ user_id -> Int4,
+ published -> Timestamp,
+ }
+}
+
+table! {
+ community (id) {
+ id -> Int4,
+ name -> Varchar,
+ title -> Varchar,
+ description -> Nullable<Text>,
+ category_id -> Int4,
+ creator_id -> Int4,
+ removed -> Bool,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ deleted -> Bool,
+ nsfw -> Bool,
+ actor_id -> Varchar,
+ local -> Bool,
+ private_key -> Nullable<Text>,
+ public_key -> Nullable<Text>,
+ last_refreshed_at -> Timestamp,
+ icon -> Nullable<Text>,
+ banner -> Nullable<Text>,
+ followers_url -> Text,
+ inbox_url -> Text,
+ shared_inbox_url -> Nullable<Text>,
+ }
+}
+
+table! {
+ community_aggregates (id) {
+ id -> Int4,
+ community_id -> Int4,
+ subscribers -> Int8,
+ posts -> Int8,
+ comments -> Int8,
+ published -> Timestamp,
+ }
+}
+
+table! {
+ community_follower (id) {
+ id -> Int4,
+ community_id -> Int4,
+ user_id -> Int4,
+ published -> Timestamp,
+ pending -> Nullable<Bool>,
+ }
+}
+
+table! {
+ community_moderator (id) {
+ id -> Int4,
+ community_id -> Int4,
+ user_id -> Int4,
+ published -> Timestamp,
+ }
+}
+
+table! {
+ community_user_ban (id) {
+ id -> Int4,
+ community_id -> Int4,
+ user_id -> Int4,
+ published -> Timestamp,
+ }
+}
+
+table! {
+ mod_add (id) {
+ id -> Int4,
+ mod_user_id -> Int4,
+ other_user_id -> Int4,
+ removed -> Nullable<Bool>,
+ when_ -> Timestamp,
+ }
+}
+
+table! {
+ mod_add_community (id) {
+ id -> Int4,
+ mod_user_id -> Int4,
+ other_user_id -> Int4,
+ community_id -> Int4,
+ removed -> Nullable<Bool>,
+ when_ -> Timestamp,
+ }
+}
+
+table! {
+ mod_ban (id) {
+ id -> Int4,
+ mod_user_id -> Int4,
+ other_user_id -> Int4,
+ reason -> Nullable<Text>,
+ banned -> Nullable<Bool>,
+ expires -> Nullable<Timestamp>,
+ when_ -> Timestamp,
+ }
+}
+
+table! {
+ mod_ban_from_community (id) {
+ id -> Int4,
+ mod_user_id -> Int4,
+ other_user_id -> Int4,
+ community_id -> Int4,
+ reason -> Nullable<Text>,
+ banned -> Nullable<Bool>,
+ expires -> Nullable<Timestamp>,
+ when_ -> Timestamp,
+ }
+}
+
+table! {
+ mod_lock_post (id) {
+ id -> Int4,
+ mod_user_id -> Int4,
+ post_id -> Int4,
+ locked -> Nullable<Bool>,
+ when_ -> Timestamp,
+ }
+}
+
+table! {
+ mod_remove_comment (id) {
+ id -> Int4,
+ mod_user_id -> Int4,
+ comment_id -> Int4,
+ reason -> Nullable<Text>,
+ removed -> Nullable<Bool>,
+ when_ -> Timestamp,
+ }
+}
+
+table! {
+ mod_remove_community (id) {
+ id -> Int4,
+ mod_user_id -> Int4,
+ community_id -> Int4,
+ reason -> Nullable<Text>,
+ removed -> Nullable<Bool>,
+ expires -> Nullable<Timestamp>,
+ when_ -> Timestamp,
+ }
+}
+
+table! {
+ mod_remove_post (id) {
+ id -> Int4,
+ mod_user_id -> Int4,
+ post_id -> Int4,
+ reason -> Nullable<Text>,
+ removed -> Nullable<Bool>,
+ when_ -> Timestamp,
+ }
+}
+
+table! {
+ mod_sticky_post (id) {
+ id -> Int4,
+ mod_user_id -> Int4,
+ post_id -> Int4,
+ stickied -> Nullable<Bool>,
+ when_ -> Timestamp,
+ }
+}
+
+table! {
+ password_reset_request (id) {
+ id -> Int4,
+ user_id -> Int4,
+ token_encrypted -> Text,
+ published -> Timestamp,
+ }
+}
+
+table! {
+ post (id) {
+ id -> Int4,
+ name -> Varchar,
+ url -> Nullable<Text>,
+ body -> Nullable<Text>,
+ creator_id -> Int4,
+ community_id -> Int4,
+ removed -> Bool,
+ locked -> Bool,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ deleted -> Bool,
+ nsfw -> Bool,
+ stickied -> Bool,
+ embed_title -> Nullable<Text>,
+ embed_description -> Nullable<Text>,
+ embed_html -> Nullable<Text>,
+ thumbnail_url -> Nullable<Text>,
+ ap_id -> Varchar,
+ local -> Bool,
+ }
+}
+
+table! {
+ post_aggregates (id) {
+ id -> Int4,
+ post_id -> Int4,
+ comments -> Int8,
+ score -> Int8,
+ upvotes -> Int8,
+ downvotes -> Int8,
+ stickied -> Bool,
+ published -> Timestamp,
+ newest_comment_time -> Timestamp,
+ }
+}
+
+table! {
+ post_like (id) {
+ id -> Int4,
+ post_id -> Int4,
+ user_id -> Int4,
+ score -> Int2,
+ published -> Timestamp,
+ }
+}
+
+table! {
+ post_read (id) {
+ id -> Int4,
+ post_id -> Int4,
+ user_id -> Int4,
+ published -> Timestamp,
+ }
+}
+
+table! {
+ post_report (id) {
+ id -> Int4,
+ creator_id -> Int4,
+ post_id -> Int4,
+ original_post_name -> Varchar,
+ original_post_url -> Nullable<Text>,
+ original_post_body -> Nullable<Text>,
+ reason -> Text,
+ resolved -> Bool,
+ resolver_id -> Nullable<Int4>,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ }
+}
+
+table! {
+ post_saved (id) {
+ id -> Int4,
+ post_id -> Int4,
+ user_id -> Int4,
+ published -> Timestamp,
+ }
+}
+
+table! {
+ private_message (id) {
+ id -> Int4,
+ creator_id -> Int4,
+ recipient_id -> Int4,
+ content -> Text,
+ deleted -> Bool,
+ read -> Bool,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ ap_id -> Varchar,
+ local -> Bool,
+ }
+}
+
+table! {
+ site (id) {
+ id -> Int4,
+ name -> Varchar,
+ description -> Nullable<Text>,
+ creator_id -> Int4,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ enable_downvotes -> Bool,
+ open_registration -> Bool,
+ enable_nsfw -> Bool,
+ icon -> Nullable<Text>,
+ banner -> Nullable<Text>,
+ }
+}
+
+table! {
+ site_aggregates (id) {
+ id -> Int4,
+ site_id -> Int4,
+ users -> Int8,
+ posts -> Int8,
+ comments -> Int8,
+ communities -> Int8,
+ }
+}
+
+table! {
+ user_ (id) {
+ id -> Int4,
+ name -> Varchar,
+ preferred_username -> Nullable<Varchar>,
+ password_encrypted -> Text,
+ email -> Nullable<Text>,
+ avatar -> Nullable<Text>,
+ admin -> Bool,
+ banned -> Bool,
+ published -> Timestamp,
+ updated -> Nullable<Timestamp>,
+ show_nsfw -> Bool,
+ theme -> Varchar,
+ default_sort_type -> Int2,
+ default_listing_type -> Int2,
+ lang -> Varchar,
+ show_avatars -> Bool,
+ send_notifications_to_email -> Bool,
+ matrix_user_id -> Nullable<Text>,
+ actor_id -> Varchar,
+ bio -> Nullable<Text>,
+ local -> Bool,
+ private_key -> Nullable<Text>,
+ public_key -> Nullable<Text>,
+ last_refreshed_at -> Timestamp,
+ banner -> Nullable<Text>,
+ deleted -> Bool,
+ inbox_url -> Text,
+ shared_inbox_url -> Nullable<Text>,
+ }
+}
+
+table! {
+ user_aggregates (id) {
+ id -> Int4,
+ user_id -> Int4,
+ post_count -> Int8,
+ post_score -> Int8,
+ comment_count -> Int8,
+ comment_score -> Int8,
+ }
+}
+
+table! {
+ user_ban (id) {
+ id -> Int4,
+ user_id -> Int4,
+ published -> Timestamp,
+ }
+}
+
+table! {
+ user_mention (id) {
+ id -> Int4,
+ recipient_id -> Int4,
+ comment_id -> Int4,
+ read -> Bool,
+ published -> Timestamp,
+ }
+}
+
+joinable!(comment -> post (post_id));
+joinable!(comment -> user_ (creator_id));
+joinable!(comment_aggregates -> comment (comment_id));
+joinable!(comment_like -> comment (comment_id));
+joinable!(comment_like -> post (post_id));
+joinable!(comment_like -> user_ (user_id));
+joinable!(comment_report -> comment (comment_id));
+joinable!(comment_saved -> comment (comment_id));
+joinable!(comment_saved -> user_ (user_id));
+joinable!(community -> category (category_id));
+joinable!(community -> user_ (creator_id));
+joinable!(community_aggregates -> community (community_id));
+joinable!(community_follower -> community (community_id));
+joinable!(community_follower -> user_ (user_id));
+joinable!(community_moderator -> community (community_id));
+joinable!(community_moderator -> user_ (user_id));
+joinable!(community_user_ban -> community (community_id));
+joinable!(community_user_ban -> user_ (user_id));
+joinable!(mod_add_community -> community (community_id));
+joinable!(mod_ban_from_community -> community (community_id));
+joinable!(mod_lock_post -> post (post_id));
+joinable!(mod_lock_post -> user_ (mod_user_id));
+joinable!(mod_remove_comment -> comment (comment_id));
+joinable!(mod_remove_comment -> user_ (mod_user_id));
+joinable!(mod_remove_community -> community (community_id));
+joinable!(mod_remove_community -> user_ (mod_user_id));
+joinable!(mod_remove_post -> post (post_id));
+joinable!(mod_remove_post -> user_ (mod_user_id));
+joinable!(mod_sticky_post -> post (post_id));
+joinable!(mod_sticky_post -> user_ (mod_user_id));
+joinable!(password_reset_request -> user_ (user_id));
+joinable!(post -> community (community_id));
+joinable!(post -> user_ (creator_id));
+joinable!(post_aggregates -> post (post_id));
+joinable!(post_like -> post (post_id));
+joinable!(post_like -> user_ (user_id));
+joinable!(post_read -> post (post_id));
+joinable!(post_read -> user_ (user_id));
+joinable!(post_report -> post (post_id));
+joinable!(post_saved -> post (post_id));
+joinable!(post_saved -> user_ (user_id));
+joinable!(site -> user_ (creator_id));
+joinable!(site_aggregates -> site (site_id));
+joinable!(user_aggregates -> user_ (user_id));
+joinable!(user_ban -> user_ (user_id));
+joinable!(user_mention -> comment (comment_id));
+joinable!(user_mention -> user_ (recipient_id));
+
+allow_tables_to_appear_in_same_query!(
+ activity,
+ category,
+ comment,
+ comment_aggregates,
+ comment_like,
+ comment_report,
+ comment_saved,
+ community,
+ community_aggregates,
+ community_follower,
+ community_moderator,
+ community_user_ban,
+ mod_add,
+ mod_add_community,
+ mod_ban,
+ mod_ban_from_community,
+ mod_lock_post,
+ mod_remove_comment,
+ mod_remove_community,
+ mod_remove_post,
+ mod_sticky_post,
+ password_reset_request,
+ post,
+ post_aggregates,
+ post_like,
+ post_read,
+ post_report,
+ post_saved,
+ private_message,
+ site,
+ site_aggregates,
+ user_,
+ user_aggregates,
+ user_ban,
+ user_mention,
+);
--- /dev/null
+ALTER TABLE community DROP COLUMN followers_url;
+ALTER TABLE community DROP COLUMN inbox_url;
+ALTER TABLE community DROP COLUMN shared_inbox_url;
+
+ALTER TABLE user_ DROP COLUMN inbox_url;
+ALTER TABLE user_ DROP COLUMN shared_inbox_url;
\ No newline at end of file
--- /dev/null
+ALTER TABLE community ADD COLUMN followers_url varchar(255) NOT NULL DEFAULT generate_unique_changeme();
+ALTER TABLE community ADD COLUMN inbox_url varchar(255) NOT NULL DEFAULT generate_unique_changeme();
+ALTER TABLE community ADD COLUMN shared_inbox_url varchar(255);
+
+ALTER TABLE user_ ADD COLUMN inbox_url varchar(255) NOT NULL DEFAULT generate_unique_changeme();
+ALTER TABLE user_ ADD COLUMN shared_inbox_url varchar(255);
+
+ALTER TABLE community ADD CONSTRAINT idx_community_followers_url UNIQUE (followers_url);
+ALTER TABLE community ADD CONSTRAINT idx_community_inbox_url UNIQUE (inbox_url);
+ALTER TABLE user_ ADD CONSTRAINT idx_user_inbox_url UNIQUE (inbox_url);
#!/bin/sh
set -e
+psql -U lemmy -d postgres -c "DROP DATABASE lemmy;"
+psql -U lemmy -d postgres -c "CREATE DATABASE lemmy;"
+
export LEMMY_DATABASE_URL=postgres://lemmy:password@localhost:5432/lemmy
# Commenting since this will overwrite schema.rs, which will break things now
# diesel migration run
sql_types::{Nullable, Text},
*,
};
+use lemmy_apub::{
+ generate_apub_endpoint,
+ generate_followers_url,
+ generate_inbox_url,
+ generate_shared_inbox_url,
+ EndpointType,
+};
use lemmy_db_queries::{
source::{comment::Comment_, post::Post_, private_message::PrivateMessage_},
Crud,
user::{UserForm, User_},
},
};
-use lemmy_utils::{
- apub::{generate_actor_keypair, make_apub_endpoint, EndpointType},
- settings::Settings,
- LemmyError,
-};
+use lemmy_utils::{apub::generate_actor_keypair, settings::Settings, LemmyError};
use log::info;
pub fn run_advanced_migrations(conn: &PgConnection) -> Result<(), LemmyError> {
comment_updates_2020_04_03(&conn)?;
private_message_updates_2020_05_05(&conn)?;
post_thumbnail_url_updates_2020_07_27(&conn)?;
+ apub_columns_2021_02_02(&conn)?;
Ok(())
}
lang: cuser.lang.to_owned(),
show_avatars: cuser.show_avatars,
send_notifications_to_email: cuser.send_notifications_to_email,
- actor_id: Some(make_apub_endpoint(EndpointType::User, &cuser.name).into()),
+ actor_id: Some(generate_apub_endpoint(EndpointType::User, &cuser.name)?),
bio: Some(cuser.bio.to_owned()),
local: cuser.local,
private_key: Some(keypair.private_key),
public_key: Some(keypair.public_key),
last_refreshed_at: Some(naive_now()),
+ inbox_url: None,
+ shared_inbox_url: None,
};
User_::update(&conn, cuser.id, &form)?;
for ccommunity in &incorrect_communities {
let keypair = generate_actor_keypair()?;
+ let community_actor_id = generate_apub_endpoint(EndpointType::Community, &ccommunity.name)?;
let form = CommunityForm {
name: ccommunity.name.to_owned(),
deleted: None,
nsfw: ccommunity.nsfw,
updated: None,
- actor_id: Some(make_apub_endpoint(EndpointType::Community, &ccommunity.name).into()),
+ actor_id: Some(community_actor_id.to_owned()),
local: ccommunity.local,
private_key: Some(keypair.private_key),
public_key: Some(keypair.public_key),
published: None,
icon: Some(ccommunity.icon.to_owned()),
banner: Some(ccommunity.banner.to_owned()),
+ followers_url: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
Community::update(&conn, ccommunity.id, &form)?;
.load::<Post>(conn)?;
for cpost in &incorrect_posts {
- let apub_id = make_apub_endpoint(EndpointType::Post, &cpost.id.to_string()).to_string();
+ let apub_id = generate_apub_endpoint(EndpointType::Post, &cpost.id.to_string())?;
Post::update_ap_id(&conn, cpost.id, apub_id)?;
}
.load::<Comment>(conn)?;
for ccomment in &incorrect_comments {
- let apub_id = make_apub_endpoint(EndpointType::Comment, &ccomment.id.to_string()).to_string();
+ let apub_id = generate_apub_endpoint(EndpointType::Comment, &ccomment.id.to_string())?;
Comment::update_ap_id(&conn, ccomment.id, apub_id)?;
}
.load::<PrivateMessage>(conn)?;
for cpm in &incorrect_pms {
- let apub_id = make_apub_endpoint(EndpointType::PrivateMessage, &cpm.id.to_string()).to_string();
+ let apub_id = generate_apub_endpoint(EndpointType::PrivateMessage, &cpm.id.to_string())?;
PrivateMessage::update_ap_id(&conn, cpm.id, apub_id)?;
}
Ok(())
}
+
+/// We are setting inbox and follower URLs for local and remote actors alike, because for now
+/// all federated instances are also Lemmy and use the same URL scheme.
+fn apub_columns_2021_02_02(conn: &PgConnection) -> Result<(), LemmyError> {
+ info!("Running apub_columns_2021_02_02");
+ {
+ use lemmy_db_schema::schema::user_::dsl::*;
+ let users = user_
+ .filter(inbox_url.eq("http://changeme_%"))
+ .load::<User_>(conn)?;
+
+ for u in &users {
+ let inbox_url_ = generate_inbox_url(&u.actor_id)?;
+ let shared_inbox_url_ = generate_shared_inbox_url(&u.actor_id)?;
+ diesel::update(user_.find(u.id))
+ .set((
+ inbox_url.eq(inbox_url_),
+ shared_inbox_url.eq(shared_inbox_url_),
+ ))
+ .get_result::<User_>(conn)?;
+ }
+ }
+
+ {
+ use lemmy_db_schema::schema::community::dsl::*;
+ let communities = community
+ .filter(inbox_url.eq("http://changeme_%"))
+ .load::<Community>(conn)?;
+
+ for c in &communities {
+ let followers_url_ = generate_followers_url(&c.actor_id)?;
+ let inbox_url_ = generate_inbox_url(&c.actor_id)?;
+ let shared_inbox_url_ = generate_shared_inbox_url(&c.actor_id)?;
+ diesel::update(community.find(c.id))
+ .set((
+ followers_url.eq(followers_url_),
+ inbox_url.eq(inbox_url_),
+ shared_inbox_url.eq(shared_inbox_url_),
+ ))
+ .get_result::<Community>(conn)?;
+ }
+ }
+
+ Ok(())
+}
private_key: Some(user_keypair.private_key),
public_key: Some(user_keypair.public_key),
last_refreshed_at: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
User_::create(&conn, &new_user).unwrap()
published: None,
icon: None,
banner: None,
+ followers_url: None,
+ inbox_url: None,
+ shared_inbox_url: None,
};
Community::create(&conn, &new_community).unwrap()
}