Compare commits
4 commits
34c01dd858
...
af994da294
Author | SHA1 | Date | |
---|---|---|---|
af994da294 | |||
08ec2da814 | |||
d939d3d90e | |||
79236699cc |
7 changed files with 49 additions and 35 deletions
|
@ -40,7 +40,7 @@ sea-orm = { version = "0.12", features = ["macros", "sqlx-sqlite", "runtime-toki
|
|||
reqwest = { version = "0.12", features = ["json"] }
|
||||
axum = "0.7"
|
||||
tower-http = { version = "0.5", features = ["cors", "trace"] }
|
||||
apb = { path = "apb", features = ["unstructured", "orm", "activitypub-fe", "activitypub-counters", "litepub"] }
|
||||
apb = { path = "apb", features = ["unstructured", "orm", "activitypub-fe", "activitypub-counters", "litepub", "ostatus", "toot"] }
|
||||
# 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" }
|
||||
# migrations
|
||||
|
|
|
@ -67,6 +67,9 @@ pub struct SecurityConfig {
|
|||
|
||||
#[serde(default)]
|
||||
pub allow_public_debugger: bool,
|
||||
|
||||
#[serde_inline_default(true)]
|
||||
pub show_reply_ids: bool,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ impl Model {
|
|||
.set_summary(self.summary.as_deref())
|
||||
.set_content(self.content.as_deref())
|
||||
.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_published(Some(self.published))
|
||||
.set_updated(self.updated)
|
||||
|
|
|
@ -33,6 +33,8 @@ impl LD for serde_json::Value {
|
|||
Some(_) => {
|
||||
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("ostatus".to_string(), serde_json::Value::String("http://ostatus.org#".into()));
|
||||
ctx.insert("conversation".to_string(), serde_json::Value::String("ostatus:conversation".into()));
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ pub mod replies;
|
|||
|
||||
use apb::{CollectionMut, ObjectMut};
|
||||
use axum::extract::{Path, Query, State};
|
||||
use sea_orm::{ColumnTrait, ModelTrait, QueryFilter};
|
||||
use sea_orm::{ColumnTrait, EntityTrait, ModelTrait, QueryFilter, QuerySelect, SelectColumns};
|
||||
|
||||
use crate::{errors::UpubError, model::{self, addressing::Event}, server::{auth::AuthIdentity, fetcher::Fetcher, Context}};
|
||||
|
||||
|
@ -31,11 +31,11 @@ pub async fn view(
|
|||
.await?
|
||||
.ok_or_else(UpubError::not_found)?;
|
||||
|
||||
let (object, liked) = match item {
|
||||
let object = match item {
|
||||
Event::Tombstone => return Err(UpubError::not_found()),
|
||||
Event::Activity(_) => return Err(UpubError::not_found()),
|
||||
Event::StrayObject { object, liked } => (object, liked),
|
||||
Event::DeepActivity { activity: _, liked, object } => (object, liked),
|
||||
Event::StrayObject { liked: _, object } => object,
|
||||
Event::DeepActivity { activity: _, liked: _, object } => object,
|
||||
};
|
||||
|
||||
let attachments = object.find_related(model::attachment::Entity)
|
||||
|
@ -45,24 +45,32 @@ pub async fn view(
|
|||
.map(|x| x.ap())
|
||||
.collect::<Vec<serde_json::Value>>();
|
||||
|
||||
// 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));
|
||||
let mut replies = apb::Node::Empty;
|
||||
|
||||
let likes_count = object.likes as u64;
|
||||
let mut obj = object.ap().set_attachment(apb::Node::array(attachments));
|
||||
if ctx.cfg().security.show_reply_ids {
|
||||
let replies_ids = model::addressing::Entity::find_addressed(None)
|
||||
.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?;
|
||||
|
||||
if let Some(liked) = liked {
|
||||
obj = obj.set_audience(apb::Node::object( // TODO setting this again ewww...
|
||||
replies = apb::Node::object(
|
||||
serde_json::Value::new_object()
|
||||
.set_collection_type(Some(apb::CollectionType::OrderedCollection))
|
||||
.set_total_items(Some(likes_count))
|
||||
.set_ordered_items(apb::Node::links(vec![liked]))
|
||||
));
|
||||
// .set_id(Some(&crate::url!(ctx, "/objects/{id}/replies")))
|
||||
// .set_first(apb::Node::link(crate::url!(ctx, "/objects/{id}/replies/page")))
|
||||
.set_collection_type(Some(apb::CollectionType::Collection))
|
||||
.set_total_items(Some(object.comments as u64))
|
||||
.set_items(apb::Node::links(replies_ids))
|
||||
);
|
||||
}
|
||||
|
||||
Ok(JsonLD(obj.ld_context()))
|
||||
Ok(JsonLD(
|
||||
object.ap()
|
||||
.set_attachment(apb::Node::array(attachments))
|
||||
.set_replies(replies)
|
||||
.ld_context()
|
||||
))
|
||||
}
|
||||
|
|
|
@ -307,11 +307,6 @@ async fn fetch_object_inner(ctx: &Context, id: &str, depth: usize) -> crate::Res
|
|||
if let Some(reply) = object.in_reply_to().id() {
|
||||
if depth <= 16 {
|
||||
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 {
|
||||
tracing::warn!("thread deeper than 16, giving up fetching more replies");
|
||||
}
|
||||
|
|
|
@ -31,15 +31,20 @@ impl Normalizer for super::Context {
|
|||
object_model.content = Some(mdhtml::safe_html(&content));
|
||||
}
|
||||
|
||||
// fix context also for remote posts
|
||||
// TODO this is not really appropriate because we're mirroring incorrectly remote objects, but
|
||||
// it makes it SOO MUCH EASIER for us to fetch threads and stuff, so we're filling it for them
|
||||
match (&object_model.in_reply_to, &object_model.context) {
|
||||
(Some(reply_id), None) => // get context from replied object
|
||||
object_model.context = self.fetch_object(reply_id).await?.context,
|
||||
(None, None) => // generate a new context
|
||||
object_model.context = Some(object_model.id.clone()),
|
||||
(_, Some(_)) => {}, // leave it as set by user
|
||||
// fix context for remote posts
|
||||
// > note that this will effectively recursively try to fetch the parent object, in order to find
|
||||
// > the context (which is id of topmost object). there's a recursion limit of 16 hidden inside
|
||||
// > btw! also if any link is broken or we get rate limited, the whole insertion fails which is
|
||||
// > kind of dumb. there should be a job system so this can be done in waves. or maybe there's
|
||||
// > some whole other way to do this?? im thinking but misskey aaaa!! TODO
|
||||
if let Some(ref reply) = object_model.in_reply_to {
|
||||
if let Some(o) = model::object::Entity::find_by_id(reply).one(self.db()).await? {
|
||||
object_model.context = o.context;
|
||||
} 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?;
|
||||
|
|
Loading…
Reference in a new issue