Compare commits

..

No commits in common. "af994da294d84e5e3a913e277ec2972d7c3ed2f5" and "34c01dd858f9ae052d70bfef73308ed44913711e" have entirely different histories.

7 changed files with 35 additions and 49 deletions

View file

@ -40,7 +40,7 @@ sea-orm = { version = "0.12", features = ["macros", "sqlx-sqlite", "runtime-toki
reqwest = { version = "0.12", features = ["json"] } reqwest = { version = "0.12", features = ["json"] }
axum = "0.7" axum = "0.7"
tower-http = { version = "0.5", features = ["cors", "trace"] } tower-http = { version = "0.5", features = ["cors", "trace"] }
apb = { path = "apb", features = ["unstructured", "orm", "activitypub-fe", "activitypub-counters", "litepub", "ostatus", "toot"] } apb = { path = "apb", features = ["unstructured", "orm", "activitypub-fe", "activitypub-counters", "litepub"] }
# nodeinfo = "0.0.2" # the version on crates.io doesn't re-export necessary types to build the struct!!! # nodeinfo = "0.0.2" # the version on crates.io doesn't re-export necessary types to build the struct!!!
nodeinfo = { git = "https://codeberg.org/thefederationinfo/nodeinfo-rs", rev = "e865094804" } nodeinfo = { git = "https://codeberg.org/thefederationinfo/nodeinfo-rs", rev = "e865094804" }
# migrations # migrations

View file

@ -67,9 +67,6 @@ pub struct SecurityConfig {
#[serde(default)] #[serde(default)]
pub allow_public_debugger: bool, pub allow_public_debugger: bool,
#[serde_inline_default(true)]
pub show_reply_ids: bool,
} }

View file

@ -69,7 +69,6 @@ impl Model {
.set_summary(self.summary.as_deref()) .set_summary(self.summary.as_deref())
.set_content(self.content.as_deref()) .set_content(self.content.as_deref())
.set_context(apb::Node::maybe_link(self.context.clone())) .set_context(apb::Node::maybe_link(self.context.clone()))
.set_conversation(apb::Node::maybe_link(self.context.clone())) // duplicate context for mastodon
.set_in_reply_to(apb::Node::maybe_link(self.in_reply_to.clone())) .set_in_reply_to(apb::Node::maybe_link(self.in_reply_to.clone()))
.set_published(Some(self.published)) .set_published(Some(self.published))
.set_updated(self.updated) .set_updated(self.updated)

View file

@ -33,8 +33,6 @@ impl LD for serde_json::Value {
Some(_) => { Some(_) => {
ctx.insert("fe".to_string(), serde_json::Value::String("https://ns.alemi.dev/as/fe/#".into())); ctx.insert("fe".to_string(), serde_json::Value::String("https://ns.alemi.dev/as/fe/#".into()));
ctx.insert("likedByMe".to_string(), serde_json::Value::String("fe:likedByMe".into())); ctx.insert("likedByMe".to_string(), serde_json::Value::String("fe:likedByMe".into()));
ctx.insert("ostatus".to_string(), serde_json::Value::String("http://ostatus.org#".into()));
ctx.insert("conversation".to_string(), serde_json::Value::String("ostatus:conversation".into()));
}, },
None => {}, None => {},
} }

View file

@ -2,7 +2,7 @@ pub mod replies;
use apb::{CollectionMut, ObjectMut}; use apb::{CollectionMut, ObjectMut};
use axum::extract::{Path, Query, State}; use axum::extract::{Path, Query, State};
use sea_orm::{ColumnTrait, EntityTrait, ModelTrait, QueryFilter, QuerySelect, SelectColumns}; use sea_orm::{ColumnTrait, ModelTrait, QueryFilter};
use crate::{errors::UpubError, model::{self, addressing::Event}, server::{auth::AuthIdentity, fetcher::Fetcher, Context}}; use crate::{errors::UpubError, model::{self, addressing::Event}, server::{auth::AuthIdentity, fetcher::Fetcher, Context}};
@ -31,11 +31,11 @@ pub async fn view(
.await? .await?
.ok_or_else(UpubError::not_found)?; .ok_or_else(UpubError::not_found)?;
let object = match item { let (object, liked) = match item {
Event::Tombstone => return Err(UpubError::not_found()), Event::Tombstone => return Err(UpubError::not_found()),
Event::Activity(_) => return Err(UpubError::not_found()), Event::Activity(_) => return Err(UpubError::not_found()),
Event::StrayObject { liked: _, object } => object, Event::StrayObject { object, liked } => (object, liked),
Event::DeepActivity { activity: _, liked: _, object } => object, Event::DeepActivity { activity: _, liked, object } => (object, liked),
}; };
let attachments = object.find_related(model::attachment::Entity) let attachments = object.find_related(model::attachment::Entity)
@ -45,32 +45,24 @@ pub async fn view(
.map(|x| x.ap()) .map(|x| x.ap())
.collect::<Vec<serde_json::Value>>(); .collect::<Vec<serde_json::Value>>();
let mut replies = apb::Node::Empty; // let replies =
// serde_json::Value::new_object()
// .set_id(Some(&crate::url!(ctx, "/objects/{id}/replies")))
// .set_collection_type(Some(apb::CollectionType::OrderedCollection))
// .set_first(apb::Node::link(crate::url!(ctx, "/objects/{id}/replies/page")))
// .set_total_items(Some(object.comments as u64));
if ctx.cfg().security.show_reply_ids { let likes_count = object.likes as u64;
let replies_ids = model::addressing::Entity::find_addressed(None) let mut obj = object.ap().set_attachment(apb::Node::array(attachments));
.filter(model::object::Column::InReplyTo.eq(oid))
.filter(auth.filter_condition())
.select_only()
.select_column(model::object::Column::Id)
.into_tuple::<String>()
.all(ctx.db())
.await?;
replies = apb::Node::object( if let Some(liked) = liked {
obj = obj.set_audience(apb::Node::object( // TODO setting this again ewww...
serde_json::Value::new_object() serde_json::Value::new_object()
// .set_id(Some(&crate::url!(ctx, "/objects/{id}/replies"))) .set_collection_type(Some(apb::CollectionType::OrderedCollection))
// .set_first(apb::Node::link(crate::url!(ctx, "/objects/{id}/replies/page"))) .set_total_items(Some(likes_count))
.set_collection_type(Some(apb::CollectionType::Collection)) .set_ordered_items(apb::Node::links(vec![liked]))
.set_total_items(Some(object.comments as u64)) ));
.set_items(apb::Node::links(replies_ids))
);
} }
Ok(JsonLD( Ok(JsonLD(obj.ld_context()))
object.ap()
.set_attachment(apb::Node::array(attachments))
.set_replies(replies)
.ld_context()
))
} }

View file

@ -307,6 +307,11 @@ async fn fetch_object_inner(ctx: &Context, id: &str, depth: usize) -> crate::Res
if let Some(reply) = object.in_reply_to().id() { if let Some(reply) = object.in_reply_to().id() {
if depth <= 16 { if depth <= 16 {
fetch_object_inner(ctx, &reply, depth + 1).await?; fetch_object_inner(ctx, &reply, depth + 1).await?;
model::object::Entity::update_many()
.filter(model::object::Column::Id.eq(reply))
.col_expr(model::object::Column::Comments, Expr::col(model::object::Column::Comments).add(1))
.exec(ctx.db())
.await?;
} else { } else {
tracing::warn!("thread deeper than 16, giving up fetching more replies"); tracing::warn!("thread deeper than 16, giving up fetching more replies");
} }

View file

@ -31,20 +31,15 @@ impl Normalizer for super::Context {
object_model.content = Some(mdhtml::safe_html(&content)); object_model.content = Some(mdhtml::safe_html(&content));
} }
// fix context for remote posts // fix context also for remote posts
// > note that this will effectively recursively try to fetch the parent object, in order to find // TODO this is not really appropriate because we're mirroring incorrectly remote objects, but
// > the context (which is id of topmost object). there's a recursion limit of 16 hidden inside // it makes it SOO MUCH EASIER for us to fetch threads and stuff, so we're filling it for them
// > btw! also if any link is broken or we get rate limited, the whole insertion fails which is match (&object_model.in_reply_to, &object_model.context) {
// > kind of dumb. there should be a job system so this can be done in waves. or maybe there's (Some(reply_id), None) => // get context from replied object
// > some whole other way to do this?? im thinking but misskey aaaa!! TODO object_model.context = self.fetch_object(reply_id).await?.context,
if let Some(ref reply) = object_model.in_reply_to { (None, None) => // generate a new context
if let Some(o) = model::object::Entity::find_by_id(reply).one(self.db()).await? { object_model.context = Some(object_model.id.clone()),
object_model.context = o.context; (_, Some(_)) => {}, // leave it as set by user
} else {
object_model.context = None; // TODO to be filled by some other task
}
} else {
object_model.context = Some(object_model.id.clone());
} }
model::object::Entity::insert(object_model.clone().into_active_model()).exec(self.db()).await?; model::object::Entity::insert(object_model.clone().into_active_model()).exec(self.db()).await?;