From 5f998e9773ee16abb3bce619df383d7a99a2022f Mon Sep 17 00:00:00 2001 From: alemi Date: Wed, 20 Nov 2024 19:55:29 +0100 Subject: [PATCH] chore: update apb usage it should become a bit faster which makes no sense but before refs were made from strings created on demand and then cloned again so this should at least make sense --- upub/cli/src/fetch.rs | 2 +- upub/cli/src/nuke.rs | 8 +-- upub/cli/src/relay.rs | 16 ++--- upub/core/src/model/activity.rs | 2 +- upub/core/src/model/actor.rs | 22 +++---- upub/core/src/model/attachment.rs | 4 +- upub/core/src/model/object.rs | 8 +-- upub/core/src/selector/rich.rs | 6 +- upub/core/src/traits/fetch.rs | 34 +++++------ upub/core/src/traits/normalize.rs | 61 +++++++++---------- upub/core/src/traits/process.rs | 28 ++++----- .../routes/src/activitypub/actor/following.rs | 2 +- upub/routes/src/activitypub/actor/inbox.rs | 2 +- upub/routes/src/activitypub/actor/mod.rs | 4 +- .../src/activitypub/actor/notifications.rs | 2 +- upub/routes/src/activitypub/actor/outbox.rs | 2 +- upub/routes/src/activitypub/application.rs | 14 ++--- upub/routes/src/activitypub/inbox.rs | 2 +- upub/routes/src/activitypub/object/context.rs | 2 +- upub/routes/src/activitypub/object/mod.rs | 2 +- upub/routes/src/activitypub/object/replies.rs | 2 +- upub/routes/src/activitypub/outbox.rs | 2 +- upub/routes/src/activitypub/tags.rs | 2 +- upub/routes/src/builders.rs | 6 +- upub/worker/src/outbound.rs | 36 +++++------ web/src/activities/item.rs | 8 +-- web/src/actors/header.rs | 18 +++--- web/src/components/post.rs | 26 ++++---- web/src/components/user.rs | 8 +-- web/src/config.rs | 2 +- web/src/objects/attachment.rs | 7 +-- web/src/objects/item.rs | 33 +++++----- web/src/objects/view.rs | 6 +- web/src/page/config.rs | 17 ++++-- web/src/page/search.rs | 2 +- web/src/timeline/mod.rs | 28 ++++----- web/src/timeline/thread.rs | 10 +-- 37 files changed, 218 insertions(+), 218 deletions(-) diff --git a/upub/cli/src/fetch.rs b/upub/cli/src/fetch.rs index 3c63623..8be3b60 100644 --- a/upub/cli/src/fetch.rs +++ b/upub/cli/src/fetch.rs @@ -25,7 +25,7 @@ pub async fn fetch(ctx: upub::Context, uri: String, save: bool, actor: Option() .await? diff --git a/upub/cli/src/nuke.rs b/upub/cli/src/nuke.rs index b01ff13..15108ea 100644 --- a/upub/cli/src/nuke.rs +++ b/upub/cli/src/nuke.rs @@ -63,7 +63,7 @@ pub async fn nuke(ctx: upub::Context, for_real: bool, delete_posts: bool) -> Res let aid = ctx.aid(&upub::Context::new_id()); let undo_activity = apb::new() - .set_id(Some(&aid)) + .set_id(Some(aid.clone())) .set_activity_type(Some(apb::ActivityType::Undo)) .set_actor(apb::Node::link(activity.actor.clone())) .set_object(apb::Node::object(undone)) @@ -73,7 +73,7 @@ pub async fn nuke(ctx: upub::Context, for_real: bool, delete_posts: bool) -> Res let job = upub::model::job::ActiveModel { internal: NotSet, - activity: Set(aid.clone()), + activity: Set(aid), job_type: Set(upub::model::job::JobType::Outbound), actor: Set(activity.actor), target: Set(None), @@ -101,7 +101,7 @@ pub async fn nuke(ctx: upub::Context, for_real: bool, delete_posts: bool) -> Res let aid = ctx.aid(&upub::Context::new_id()); let actor = object.attributed_to.unwrap_or_else(|| ctx.domain().to_string()); let undo_activity = apb::new() - .set_id(Some(&aid)) + .set_id(Some(aid.clone())) .set_activity_type(Some(apb::ActivityType::Delete)) .set_actor(apb::Node::link(actor.clone())) .set_object(apb::Node::link(object.id.clone())) @@ -114,7 +114,7 @@ pub async fn nuke(ctx: upub::Context, for_real: bool, delete_posts: bool) -> Res let job = upub::model::job::ActiveModel { internal: NotSet, - activity: Set(aid.clone()), + activity: Set(aid), job_type: Set(upub::model::job::JobType::Outbound), actor: Set(actor), target: Set(None), diff --git a/upub/cli/src/relay.rs b/upub/cli/src/relay.rs index 40bfc62..67b4849 100644 --- a/upub/cli/src/relay.rs +++ b/upub/cli/src/relay.rs @@ -67,7 +67,7 @@ pub async fn relay(ctx: upub::Context, action: RelayCommand) -> Result<(), Reque RelayCommand::Follow { actor } => { let aid = ctx.aid(&upub::Context::new_id()); let payload = apb::new() - .set_id(Some(&aid)) + .set_id(Some(aid.clone())) .set_activity_type(Some(apb::ActivityType::Follow)) .set_actor(apb::Node::link(ctx.base().to_string())) .set_object(apb::Node::link(actor.clone())) @@ -76,7 +76,7 @@ pub async fn relay(ctx: upub::Context, action: RelayCommand) -> Result<(), Reque .set_published(Some(chrono::Utc::now())); let job = upub::model::job::ActiveModel { internal: NotSet, - activity: Set(aid.clone()), + activity: Set(aid), job_type: Set(upub::model::job::JobType::Outbound), actor: Set(ctx.base().to_string()), target: Set(None), @@ -103,7 +103,7 @@ pub async fn relay(ctx: upub::Context, action: RelayCommand) -> Result<(), Reque .ok_or_else(|| DbErr::RecordNotFound(format!("activity#{}", relation.activity)))?; let aid = ctx.aid(&upub::Context::new_id()); let payload = apb::new() - .set_id(Some(&aid)) + .set_id(Some(aid.clone())) .set_activity_type(Some(apb::ActivityType::Accept(apb::AcceptType::Accept))) .set_actor(apb::Node::link(ctx.base().to_string())) .set_object(apb::Node::link(activity.id)) @@ -112,7 +112,7 @@ pub async fn relay(ctx: upub::Context, action: RelayCommand) -> Result<(), Reque .set_published(Some(chrono::Utc::now())); let job = upub::model::job::ActiveModel { internal: NotSet, - activity: Set(aid.clone()), + activity: Set(aid), job_type: Set(upub::model::job::JobType::Outbound), actor: Set(ctx.base().to_string()), target: Set(None), @@ -140,7 +140,7 @@ pub async fn relay(ctx: upub::Context, action: RelayCommand) -> Result<(), Reque .ok_or_else(|| DbErr::RecordNotFound(format!("activity#{}", accept_activity_id)))?; let aid = ctx.aid(&upub::Context::new_id()); let payload = apb::new() - .set_id(Some(&aid)) + .set_id(Some(aid.clone())) .set_activity_type(Some(apb::ActivityType::Undo)) .set_actor(apb::Node::link(ctx.base().to_string())) .set_object(apb::Node::object(activity.ap())) @@ -149,7 +149,7 @@ pub async fn relay(ctx: upub::Context, action: RelayCommand) -> Result<(), Reque .set_published(Some(chrono::Utc::now())); let job = upub::model::job::ActiveModel { internal: NotSet, - activity: Set(aid.clone()), + activity: Set(aid), job_type: Set(upub::model::job::JobType::Outbound), actor: Set(ctx.base().to_string()), target: Set(None), @@ -176,7 +176,7 @@ pub async fn relay(ctx: upub::Context, action: RelayCommand) -> Result<(), Reque .ok_or_else(|| DbErr::RecordNotFound(format!("activity#{}", relation.activity)))?; let aid = ctx.aid(&upub::Context::new_id()); let payload = apb::new() - .set_id(Some(&aid)) + .set_id(Some(aid.clone())) .set_activity_type(Some(apb::ActivityType::Undo)) .set_actor(apb::Node::link(ctx.base().to_string())) .set_object(apb::Node::object(activity.ap())) @@ -185,7 +185,7 @@ pub async fn relay(ctx: upub::Context, action: RelayCommand) -> Result<(), Reque .set_published(Some(chrono::Utc::now())); let job = upub::model::job::ActiveModel { internal: NotSet, - activity: Set(aid.clone()), + activity: Set(aid), job_type: Set(upub::model::job::JobType::Outbound), actor: Set(ctx.base().to_string()), target: Set(None), diff --git a/upub/core/src/model/activity.rs b/upub/core/src/model/activity.rs index 21946e2..db51b34 100644 --- a/upub/core/src/model/activity.rs +++ b/upub/core/src/model/activity.rs @@ -90,7 +90,7 @@ impl Entity { impl Model { pub fn ap(self) -> serde_json::Value { apb::new() - .set_id(Some(&self.id)) + .set_id(Some(self.id)) .set_activity_type(Some(self.activity_type)) .set_actor(apb::Node::link(self.actor)) .set_object(apb::Node::maybe_link(self.object)) diff --git a/upub/core/src/model/actor.rs b/upub/core/src/model/actor.rs index e62a339..8ec5cf3 100644 --- a/upub/core/src/model/actor.rs +++ b/upub/core/src/model/actor.rs @@ -1,6 +1,6 @@ use sea_orm::{entity::prelude::*, QuerySelect, SelectColumns}; -use apb::{field::OptionalString, ActorMut, ActorType, BaseMut, DocumentMut, EndpointsMut, ObjectMut, PublicKeyMut}; +use apb::{ActorMut, ActorType, BaseMut, DocumentMut, EndpointsMut, ObjectMut, PublicKeyMut}; use crate::ext::{JsonVec, TypeName}; @@ -25,8 +25,8 @@ impl TypeName for Field { impl From for Field { fn from(value: T) -> Self { Field { - name: value.name().str().unwrap_or_default(), - value: mdhtml::safe_html(value.value().unwrap_or_default()), + name: value.name().unwrap_or_default().to_string(), + value: mdhtml::safe_html(&value.value().unwrap_or_default()), field_type: "PropertyValue".to_string(), // TODO can we try parsing this instead?? verified_at: None, // TODO where does verified_at come from? extend apb maybe } @@ -203,10 +203,10 @@ impl Entity { impl Model { pub fn ap(self) -> serde_json::Value { apb::new() - .set_id(Some(&self.id)) + .set_id(Some(self.id.clone())) .set_actor_type(Some(self.actor_type)) - .set_name(self.name.as_deref()) - .set_summary(self.summary.as_deref()) + .set_name(self.name) + .set_summary(self.summary) .set_icon(apb::Node::maybe_object(self.icon.map(|i| apb::new() .set_document_type(Some(apb::DocumentType::Image)) @@ -225,7 +225,7 @@ impl Model { )) .set_published(Some(self.published)) .set_updated(if self.updated != self.published { Some(self.updated) } else { None }) - .set_preferred_username(Some(&self.preferred_username)) + .set_preferred_username(Some(self.preferred_username)) .set_statuses_count(Some(self.statuses_count as u64)) .set_followers_count(Some(self.followers_count as u64)) .set_following_count(Some(self.following_count as u64)) @@ -235,13 +235,13 @@ impl Model { .set_followers(apb::Node::maybe_link(self.followers)) .set_public_key(apb::Node::object( apb::new() - .set_id(Some(&format!("{}#main-key", self.id))) - .set_owner(Some(&self.id)) - .set_public_key_pem(&self.public_key) + .set_id(Some(format!("{}#main-key", self.id))) + .set_owner(Some(self.id)) + .set_public_key_pem(self.public_key) )) .set_endpoints(apb::Node::object( apb::new() - .set_shared_inbox(self.shared_inbox.as_deref()) + .set_shared_inbox(self.shared_inbox) )) .set_also_known_as(apb::Node::links(self.also_known_as.0)) .set_moved_to(apb::Node::maybe_link(self.moved_to)) diff --git a/upub/core/src/model/attachment.rs b/upub/core/src/model/attachment.rs index 97851f5..12082bf 100644 --- a/upub/core/src/model/attachment.rs +++ b/upub/core/src/model/attachment.rs @@ -39,7 +39,7 @@ impl Model { apb::new() .set_url(apb::Node::link(self.url)) .set_document_type(Some(self.document_type)) - .set_media_type(Some(&self.media_type)) - .set_name(self.name.as_deref()) + .set_media_type(Some(self.media_type)) + .set_name(self.name) } } diff --git a/upub/core/src/model/object.rs b/upub/core/src/model/object.rs index bf5e045..d776735 100644 --- a/upub/core/src/model/object.rs +++ b/upub/core/src/model/object.rs @@ -163,12 +163,12 @@ impl Entity { impl Model { pub fn ap(self) -> serde_json::Value { apb::new() - .set_id(Some(&self.id)) + .set_id(Some(self.id)) .set_object_type(Some(self.object_type)) .set_attributed_to(apb::Node::maybe_link(self.attributed_to)) - .set_name(self.name.as_deref()) - .set_summary(self.summary.as_deref()) - .set_content(self.content.as_deref()) + .set_name(self.name) + .set_summary(self.summary) + .set_content(self.content) .set_image(apb::Node::maybe_object(self.image.map(|x| apb::new() .set_document_type(Some(apb::DocumentType::Image)) diff --git a/upub/core/src/selector/rich.rs b/upub/core/src/selector/rich.rs index 625fb04..62b61d7 100644 --- a/upub/core/src/selector/rich.rs +++ b/upub/core/src/selector/rich.rs @@ -12,8 +12,8 @@ impl RichMention { use apb::LinkMut; apb::new() .set_link_type(Some(apb::LinkType::Mention)) - .set_href(Some(&self.id)) - .set_name(Some(&self.fqn)) + .set_href(Some(self.id)) + .set_name(Some(self.fqn)) } } @@ -25,7 +25,7 @@ impl RichHashtag { pub fn ap(self) -> serde_json::Value { use apb::LinkMut; apb::new() - .set_name(Some(&format!("#{}", self.hash.name))) + .set_name(Some(format!("#{}", self.hash.name))) .set_link_type(Some(apb::LinkType::Hashtag)) } } diff --git a/upub/core/src/traits/fetch.rs b/upub/core/src/traits/fetch.rs index 5fe1085..7c822f8 100644 --- a/upub/core/src/traits/fetch.rs +++ b/upub/core/src/traits/fetch.rs @@ -1,14 +1,14 @@ use std::collections::BTreeMap; -use apb::{Activity, Actor, ActorMut, Base, Collection, CollectionPage, Object}; +use apb::{Shortcuts, Activity, Actor, ActorMut, Base, Collection, CollectionPage, Object}; use reqwest::{header::{ACCEPT, CONTENT_TYPE, USER_AGENT}, Method, Response}; use sea_orm::{ActiveValue::Set, ColumnTrait, ConnectionTrait, DbErr, EntityTrait, IntoActiveModel, NotSet, QueryFilter, ActiveModelTrait}; -use crate::{ext::Shortcuts, traits::normalize::AP}; - use super::{Addresser, Cloaker, Normalizer}; use httpsign::HttpSignature; +use crate::AP; + #[derive(Debug, Clone)] pub enum Pull { Actor(T), @@ -184,7 +184,7 @@ impl Fetcher for crate::Context { if depth >= self.cfg().security.max_id_redirects { return Err(RequestError::TooManyRedirects); } - return self.pull(doc_id).await; + return self.pull(&doc_id).await; } match document.object_type()? { @@ -299,7 +299,7 @@ impl Fetcher for crate::Context { // TODO try fetching these numbers from audience/generator fields to avoid making 2 more GETs every time if let Ok(followers_url) = document.followers().id() { let req = Self::request( - Method::GET, followers_url, None, + Method::GET, &followers_url, None, self.base(), self.pkey(), self.domain(), ).await; if let Ok(res) = req { @@ -313,7 +313,7 @@ impl Fetcher for crate::Context { if let Ok(following_url) = document.following().id() { let req = Self::request( - Method::GET, following_url, None, + Method::GET, &following_url, None, self.base(), self.pkey(), self.domain(), ).await; if let Ok(res) = req { @@ -362,7 +362,7 @@ impl Fetcher for crate::Context { let document = self.pull(id).await?.actor()?; if document.id()? != id { - if let Some(x) = crate::model::actor::Entity::find_by_ap_id(document.id()?).one(tx).await? { + if let Some(x) = crate::model::actor::Entity::find_by_ap_id(&document.id()?).one(tx).await? { return Ok(x); // already in db but we had to follow the "pretty" url, mehh } } @@ -381,16 +381,16 @@ impl Fetcher for crate::Context { } async fn resolve_activity(&self, activity: serde_json::Value, tx: &impl ConnectionTrait) -> Result { - let _domain = self.fetch_domain(&crate::Context::server(activity.id()?), tx).await?; + let _domain = self.fetch_domain(&crate::Context::server(&activity.id()?), tx).await?; if let Ok(activity_actor) = activity.actor().id() { - if let Err(e) = self.fetch_user(activity_actor, tx).await { + if let Err(e) = self.fetch_user(&activity_actor, tx).await { tracing::warn!("could not get actor of fetched activity: {e}"); } } if let Ok(activity_object) = activity.object().id() { - if let Err(e) = self.fetch_object(activity_object, tx).await { + if let Err(e) = self.fetch_object(&activity_object, tx).await { tracing::warn!("could not get object of fetched activity: {e}"); } } @@ -441,13 +441,13 @@ impl Fetcher for crate::Context { } for obj in page.items().flat() { - if let Err(e) = self.fetch_object(obj.id()?, tx).await { + if let Err(e) = self.fetch_object(&obj.id()?, tx).await { tracing::warn!("error fetching reply: {e}"); } } for obj in page.ordered_items().flat() { - if let Err(e) = self.fetch_object(obj.id()?, tx).await { + if let Err(e) = self.fetch_object(&obj.id()?, tx).await { tracing::warn!("error fetching reply: {e}"); } } @@ -477,7 +477,7 @@ async fn fetch_object_r(ctx: &crate::Context, id: &str, depth: u32, tx: &impl Co let object = ctx.pull(id).await?.object()?; if object.id()? != id { - if let Some(x) = crate::model::object::Entity::find_by_ap_id(object.id()?).one(tx).await? { + if let Some(x) = crate::model::object::Entity::find_by_ap_id(&object.id()?).one(tx).await? { return Ok(x); // already in db but we had to follow the "pretty" url, mehh } } @@ -490,21 +490,21 @@ async fn resolve_object_r(ctx: &crate::Context, object: serde_json::Value, depth if let Ok(oid) = object.id() { if oid != id { - if let Some(x) = crate::model::object::Entity::find_by_ap_id(oid).one(tx).await? { + if let Some(x) = crate::model::object::Entity::find_by_ap_id(&oid).one(tx).await? { return Ok(x); // already in db, but with id different that given url } } } if let Ok(attributed_to) = object.attributed_to().id() { - if let Err(e) = ctx.fetch_user(attributed_to, tx).await { + if let Err(e) = ctx.fetch_user(&attributed_to, tx).await { tracing::warn!("could not get actor of fetched object: {e}"); } } if let Ok(reply) = object.in_reply_to().id() { if depth <= ctx.cfg().security.thread_crawl_depth { - fetch_object_r(ctx, reply, depth + 1, tx).await?; + fetch_object_r(ctx, &reply, depth + 1, tx).await?; } else { tracing::warn!("thread deeper than {}, giving up fetching more replies", ctx.cfg().security.thread_crawl_depth); } @@ -527,7 +527,7 @@ impl Dereferenceable for apb::Node { apb::Node::Link(uri) => { let href = uri.href()?; tracing::info!("dereferencing {href}"); - let res = crate::Context::request(Method::GET, href, None, ctx.base(), ctx.pkey(), ctx.domain()) + let res = crate::Context::request(Method::GET, &href, None, ctx.base(), ctx.pkey(), ctx.domain()) .await? .json::() .await?; diff --git a/upub/core/src/traits/normalize.rs b/upub/core/src/traits/normalize.rs index f66c253..5637615 100644 --- a/upub/core/src/traits/normalize.rs +++ b/upub/core/src/traits/normalize.rs @@ -1,6 +1,5 @@ -use apb::{field::OptionalString, Document, Endpoints, Node, Object, PublicKey}; +use apb::{Document, Endpoints, Node, Object, PublicKey, Shortcuts}; use sea_orm::{sea_query::Expr, ActiveModelTrait, ActiveValue::{Unchanged, NotSet, Set}, ColumnTrait, ConnectionTrait, DbErr, EntityTrait, IntoActiveModel, QueryFilter}; -use crate::ext::Shortcuts; use super::{Cloaker, Fetcher}; @@ -40,7 +39,7 @@ impl Normalizer for crate::Context { // > 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 Ok(reply) = object.in_reply_to().id() { - if let Some(o) = crate::model::object::Entity::find_by_ap_id(reply).one(tx).await? { + if let Some(o) = crate::model::object::Entity::find_by_ap_id(&reply).one(tx).await? { object_model.context = o.context; } else { object_model.context = None; // TODO to be filled by some other task @@ -104,7 +103,7 @@ impl Normalizer for crate::Context { Node::Link(l) => { let url = l.href().unwrap_or_default(); if url == obj_image { continue }; - let mut media_type = l.media_type().unwrap_or("link").to_string(); + let mut media_type = l.media_type().unwrap_or("link".to_string()); let mut document_type = apb::DocumentType::Page; if self.cfg().compat.fix_attachment_images_media_type && [".jpg", ".jpeg", ".png", ".webp", ".bmp"] // TODO more image types??? @@ -117,10 +116,10 @@ impl Normalizer for crate::Context { } crate::model::attachment::ActiveModel { internal: sea_orm::ActiveValue::NotSet, - url: Set(self.cloaked(url)), + url: Set(self.cloaked(&url)), object: Set(object_model.internal), document_type: Set(document_type), - name: Set(l.name().str()), + name: Set(l.name().ok()), media_type: Set(media_type), } }, @@ -142,7 +141,7 @@ impl Normalizer for crate::Context { // we should try to resolve remote users mentioned, otherwise most mentions will // be lost. also we shouldn't fail inserting the whole post if the mention fails // resolving. - if let Ok(user) = self.fetch_user(href, tx).await { + if let Ok(user) = self.fetch_user(&href, tx).await { let model = crate::model::mention::ActiveModel { internal: NotSet, object: Set(object_model.internal), @@ -156,7 +155,7 @@ impl Normalizer for crate::Context { }, Ok(apb::LinkType::Hashtag) => { let hashtag = l.name() - .unwrap_or_else(|_| l.href().unwrap_or_default().split('/').last().unwrap_or_default()) // TODO maybe just fail? + .unwrap_or_else(|_| l.href().unwrap_or_default().split('/').last().unwrap_or_default().to_string()) // TODO maybe just fail? .replace('#', ""); // TODO lemmy added a "fix" to make its communities kind of work with mastodon: // basically they include the community name as hashtag. ughhhh, since we handle @@ -238,8 +237,8 @@ impl AP { id: activity.id()?.to_string(), activity_type: activity.activity_type()?, actor: activity.actor().id()?.to_string(), - object: activity.object().id().str(), - target: activity.target().id().str(), + object: activity.object().id().ok(), + target: activity.target().id().ok(), published: activity.published().unwrap_or(chrono::Utc::now()), to: activity.to().all_ids().into(), bto: activity.bto().all_ids().into(), @@ -268,11 +267,11 @@ impl AP { } Ok(crate::model::attachment::Model { internal: 0, - url: document.url().id().str().unwrap_or_default(), + url: document.url().id().unwrap_or_default(), object: parent, document_type: document.as_document().map_or(apb::DocumentType::Document, |x| x.document_type().unwrap_or(apb::DocumentType::Page)), - name: document.name().str(), - media_type: document.media_type().unwrap_or("link").to_string(), + name: document.name().ok(), + media_type: document.media_type().unwrap_or("link".to_string()), }) } @@ -307,21 +306,21 @@ impl AP { internal: 0, id: object.id()?.to_string(), object_type: object.object_type()?, - attributed_to: object.attributed_to().id().str(), - name: object.name().str(), - summary: object.summary().str(), - content: object.content().str(), + attributed_to: object.attributed_to().id().ok(), + name: object.name().ok(), + summary: object.summary().ok(), + content: object.content().ok(), image: object.image_url().ok(), - context: object.context().id().str(), - in_reply_to: object.in_reply_to().id().str(), - quote: object.quote_url().id().str(), + context: object.context().id().ok(), + in_reply_to: object.in_reply_to().id().ok(), + quote: object.quote_url().id().ok(), published: object.published().unwrap_or_else(|_| chrono::Utc::now()), updated: object.updated().unwrap_or_else(|_| chrono::Utc::now()), - url: object.url().id().str(), + url: object.url().id().ok(), replies: object.replies_count().unwrap_or_default(), likes: object.likes_count().unwrap_or_default(), announces: object.shares_count().unwrap_or_default(), - audience: object.audience().id().str(), + audience: object.audience().id().ok(), to: object.to().all_ids().into(), bto: object.bto().all_ids().into(), cc: object.cc().all_ids().into(), @@ -362,19 +361,19 @@ impl AP { internal: 0, domain, id: ap_id, - preferred_username: actor.preferred_username().unwrap_or(&fallback_preferred_username).to_string(), + preferred_username: actor.preferred_username().unwrap_or(fallback_preferred_username).to_string(), actor_type: actor.actor_type()?, - name: actor.name().str(), - summary: actor.summary().str(), + name: actor.name().ok(), + summary: actor.summary().ok(), icon: actor.icon_url().ok(), image: actor.image_url().ok(), - inbox: actor.inbox().id().str(), - outbox: actor.outbox().id().str(), + inbox: actor.inbox().id().ok(), + outbox: actor.outbox().id().ok(), shared_inbox: actor.endpoints().inner().and_then(|x| x.shared_inbox()).map(|x| x.to_string()).ok(), - followers: actor.followers().id().str(), - following: actor.following().id().str(), - also_known_as: actor.also_known_as().flat().into_iter().filter_map(|x| x.id().str()).collect::>().into(), - moved_to: actor.moved_to().id().str(), + followers: actor.followers().id().ok(), + following: actor.following().id().ok(), + also_known_as: actor.also_known_as().flat().into_iter().filter_map(|x| x.id().ok()).collect::>().into(), + moved_to: actor.moved_to().id().ok(), published: actor.published().unwrap_or(chrono::Utc::now()), updated: chrono::Utc::now(), following_count: actor.following_count().unwrap_or(0) as i32, diff --git a/upub/core/src/traits/process.rs b/upub/core/src/traits/process.rs index cdd6964..06e641d 100644 --- a/upub/core/src/traits/process.rs +++ b/upub/core/src/traits/process.rs @@ -60,14 +60,14 @@ pub async fn create(ctx: &crate::Context, activity: impl apb::Activity, tx: &Dat tracing::error!("refusing to process activity without embedded object"); return Err(ProcessorError::Unprocessable(activity.id()?.to_string())); }; - if model::object::Entity::ap_to_internal(object_node.id()?, tx).await?.is_some() { + if model::object::Entity::ap_to_internal(&object_node.id()?, tx).await?.is_some() { return Err(ProcessorError::AlreadyProcessed); } if object_node.attributed_to().id()? != activity.actor().id()? { return Err(ProcessorError::Unauthorized); } if let Ok(reply) = object_node.in_reply_to().id() { - if let Err(e) = ctx.fetch_object(reply, tx).await { + if let Err(e) = ctx.fetch_object(&reply, tx).await { tracing::warn!("failed fetching replies for received object: {e}"); } } @@ -96,8 +96,8 @@ pub async fn create(ctx: &crate::Context, activity: impl apb::Activity, tx: &Dat } pub async fn like(ctx: &crate::Context, activity: impl apb::Activity, tx: &DatabaseTransaction) -> Result<(), ProcessorError> { - let actor = ctx.fetch_user(activity.actor().id()?, tx).await?; - let obj = ctx.fetch_object(activity.object().id()?, tx).await?; + let actor = ctx.fetch_user(&activity.actor().id()?, tx).await?; + let obj = ctx.fetch_object(&activity.object().id()?, tx).await?; let likes_local_object = obj.attributed_to.as_ref().map(|x| ctx.is_local(x)).unwrap_or_default(); if crate::model::like::Entity::find_by_uid_oid(actor.internal, obj.internal) .any(tx) @@ -146,8 +146,8 @@ pub async fn like(ctx: &crate::Context, activity: impl apb::Activity, tx: &Datab // TODO basically same as like, can we make one function, maybe with const generic??? pub async fn dislike(ctx: &crate::Context, activity: impl apb::Activity, tx: &DatabaseTransaction) -> Result<(), ProcessorError> { - let actor = ctx.fetch_user(activity.actor().id()?, tx).await?; - let obj = ctx.fetch_object(activity.object().id()?, tx).await?; + let actor = ctx.fetch_user(&activity.actor().id()?, tx).await?; + let obj = ctx.fetch_object(&activity.object().id()?, tx).await?; if crate::model::dislike::Entity::find_by_uid_oid(actor.internal, obj.internal) .any(tx) .await? @@ -186,11 +186,11 @@ pub async fn dislike(ctx: &crate::Context, activity: impl apb::Activity, tx: &Da } pub async fn follow(ctx: &crate::Context, activity: impl apb::Activity, tx: &DatabaseTransaction) -> Result<(), ProcessorError> { - let source_actor = crate::model::actor::Entity::find_by_ap_id(activity.actor().id()?) + let source_actor = crate::model::actor::Entity::find_by_ap_id(&activity.actor().id()?) .one(tx) .await? .ok_or(ProcessorError::Incomplete)?; - let target_actor = ctx.fetch_user(activity.object().id()?, tx).await?; + let target_actor = ctx.fetch_user(&activity.object().id()?, tx).await?; let activity_model = ctx.insert_activity(activity, tx).await?; ctx.address(Some(&activity_model), None, tx).await?; @@ -246,7 +246,7 @@ pub async fn follow(ctx: &crate::Context, activity: impl apb::Activity, tx: &Dat pub async fn accept(ctx: &crate::Context, activity: impl apb::Activity, tx: &DatabaseTransaction) -> Result<(), ProcessorError> { // TODO what about TentativeAccept - let follow_activity = crate::model::activity::Entity::find_by_ap_id(activity.object().id()?) + let follow_activity = crate::model::activity::Entity::find_by_ap_id(&activity.object().id()?) .one(tx) .await? .ok_or(ProcessorError::Incomplete)?; @@ -305,7 +305,7 @@ pub async fn accept(ctx: &crate::Context, activity: impl apb::Activity, tx: &Dat pub async fn reject(ctx: &crate::Context, activity: impl apb::Activity, tx: &DatabaseTransaction) -> Result<(), ProcessorError> { // TODO what about TentativeReject? - let follow_activity = crate::model::activity::Entity::find_by_ap_id(activity.object().id()?) + let follow_activity = crate::model::activity::Entity::find_by_ap_id(&activity.object().id()?) .one(tx) .await? .ok_or(ProcessorError::Incomplete)?; @@ -429,7 +429,7 @@ pub async fn undo(ctx: &crate::Context, activity: impl apb::Activity, tx: &Datab match undone_activity.as_activity()?.activity_type()? { apb::ActivityType::Like => { let internal_oid = crate::model::object::Entity::ap_to_internal( - undone_activity.as_activity()?.object().id()?, + &undone_activity.as_activity()?.object().id()?, tx ) .await? @@ -450,7 +450,7 @@ pub async fn undo(ctx: &crate::Context, activity: impl apb::Activity, tx: &Datab }, apb::ActivityType::Follow => { let internal_uid_following = crate::model::actor::Entity::ap_to_internal( - undone_activity.as_activity()?.object().id()?, + &undone_activity.as_activity()?.object().id()?, tx, ) .await? @@ -494,7 +494,7 @@ pub async fn undo(ctx: &crate::Context, activity: impl apb::Activity, tx: &Datab ctx.address(Some(&activity_model), None, tx).await?; } - if let Some(internal) = crate::model::activity::Entity::ap_to_internal(undone_activity.id()?, tx).await? { + if let Some(internal) = crate::model::activity::Entity::ap_to_internal(&undone_activity.id()?, tx).await? { crate::model::notification::Entity::delete_many() .filter(crate::model::notification::Column::Activity.eq(internal)) .exec(tx) @@ -532,7 +532,7 @@ pub async fn announce(ctx: &crate::Context, activity: impl apb::Activity, tx: &D } }; - let actor = ctx.fetch_user(activity.actor().id()?, tx).await?; + let actor = ctx.fetch_user(&activity.actor().id()?, tx).await?; // we only care about announces produced by "Person" actors, because there's intention // anything shared by groups, services or applications is automated: fetch it and be done diff --git a/upub/routes/src/activitypub/actor/following.rs b/upub/routes/src/activitypub/actor/following.rs index 3f1deea..794f330 100644 --- a/upub/routes/src/activitypub/actor/following.rs +++ b/upub/routes/src/activitypub/actor/following.rs @@ -47,7 +47,7 @@ pub async fn get( }; - crate::builders::collection(&upub::url!(ctx, "/actors/{id}/{follow___}"), Some(count as u64)) + crate::builders::collection(upub::url!(ctx, "/actors/{id}/{follow___}"), Some(count as u64)) } pub async fn page( diff --git a/upub/routes/src/activitypub/actor/inbox.rs b/upub/routes/src/activitypub/actor/inbox.rs index 620b4ce..ec5f707 100644 --- a/upub/routes/src/activitypub/actor/inbox.rs +++ b/upub/routes/src/activitypub/actor/inbox.rs @@ -14,7 +14,7 @@ pub async fn get( Identity::Anonymous => Err(crate::ApiError::forbidden()), Identity::Remote { .. } => Err(crate::ApiError::forbidden()), Identity::Local { id: user, .. } => if ctx.uid(&id) == user { - crate::builders::collection(&upub::url!(ctx, "/actors/{id}/inbox"), None) + crate::builders::collection(upub::url!(ctx, "/actors/{id}/inbox"), None) } else { Err(crate::ApiError::forbidden()) }, diff --git a/upub/routes/src/activitypub/actor/mod.rs b/upub/routes/src/activitypub/actor/mod.rs index 4b76771..1be689b 100644 --- a/upub/routes/src/activitypub/actor/mod.rs +++ b/upub/routes/src/activitypub/actor/mod.rs @@ -65,8 +65,8 @@ pub async fn view( .set_manually_approves_followers(Some(!cfg.accept_follow_requests)) .set_endpoints(Node::object( apb::new() - .set_shared_inbox(Some(&upub::url!(ctx, "/inbox"))) - .set_proxy_url(Some(&upub::url!(ctx, "/fetch"))) + .set_shared_inbox(Some(upub::url!(ctx, "/inbox"))) + .set_proxy_url(Some(upub::url!(ctx, "/fetch"))) )); if auth.is(&uid) { diff --git a/upub/routes/src/activitypub/actor/notifications.rs b/upub/routes/src/activitypub/actor/notifications.rs index 8d0d215..5a5e8bd 100644 --- a/upub/routes/src/activitypub/actor/notifications.rs +++ b/upub/routes/src/activitypub/actor/notifications.rs @@ -22,7 +22,7 @@ pub async fn get( .count(ctx.db()) .await?; - crate::builders::collection(&upub::url!(ctx, "/actors/{id}/notifications"), Some(count)) + crate::builders::collection(upub::url!(ctx, "/actors/{id}/notifications"), Some(count)) } pub async fn page( diff --git a/upub/routes/src/activitypub/actor/outbox.rs b/upub/routes/src/activitypub/actor/outbox.rs index 7a0cfac..5e7f1bf 100644 --- a/upub/routes/src/activitypub/actor/outbox.rs +++ b/upub/routes/src/activitypub/actor/outbox.rs @@ -9,7 +9,7 @@ pub async fn get( State(ctx): State, Path(id): Path, ) -> crate::ApiResult> { - crate::builders::collection(&upub::url!(ctx, "/actors/{id}/outbox"), None) + crate::builders::collection(upub::url!(ctx, "/actors/{id}/outbox"), None) } pub async fn page( diff --git a/upub/routes/src/activitypub/application.rs b/upub/routes/src/activitypub/application.rs index 9d5eb99..219220e 100644 --- a/upub/routes/src/activitypub/application.rs +++ b/upub/routes/src/activitypub/application.rs @@ -22,21 +22,21 @@ pub async fn view( } Ok(JsonLD( apb::new() - .set_id(Some(&upub::url!(ctx, ""))) + .set_id(Some(upub::url!(ctx, ""))) .set_actor_type(Some(apb::ActorType::Application)) - .set_name(Some(&ctx.cfg().instance.name)) - .set_summary(Some(&ctx.cfg().instance.description)) + .set_name(Some(ctx.cfg().instance.name.clone())) + .set_summary(Some(ctx.cfg().instance.description.clone())) .set_inbox(apb::Node::link(upub::url!(ctx, "/inbox"))) .set_outbox(apb::Node::link(upub::url!(ctx, "/outbox"))) .set_published(Some(ctx.actor().published)) .set_endpoints(apb::Node::Empty) - .set_preferred_username(Some(ctx.domain())) + .set_preferred_username(Some(ctx.domain().to_string())) .set_url(apb::Node::link(upub::url!(ctx, "/"))) .set_public_key(apb::Node::object( apb::new() - .set_id(Some(&upub::url!(ctx, "#main-key"))) - .set_owner(Some(&upub::url!(ctx, ""))) - .set_public_key_pem(&ctx.actor().public_key) + .set_id(Some(upub::url!(ctx, "#main-key"))) + .set_owner(Some(upub::url!(ctx, ""))) + .set_public_key_pem(ctx.actor().public_key.clone()) )) .ld_context() ).into_response()) diff --git a/upub/routes/src/activitypub/inbox.rs b/upub/routes/src/activitypub/inbox.rs index 5db3b63..27280b9 100644 --- a/upub/routes/src/activitypub/inbox.rs +++ b/upub/routes/src/activitypub/inbox.rs @@ -11,7 +11,7 @@ use super::Pagination; pub async fn get( State(ctx): State, ) -> crate::ApiResult> { - crate::builders::collection(&upub::url!(ctx, "/inbox"), None) + crate::builders::collection(upub::url!(ctx, "/inbox"), None) } pub async fn page( diff --git a/upub/routes/src/activitypub/object/context.rs b/upub/routes/src/activitypub/object/context.rs index 3cc1751..377f70f 100644 --- a/upub/routes/src/activitypub/object/context.rs +++ b/upub/routes/src/activitypub/object/context.rs @@ -17,7 +17,7 @@ pub async fn get( .count(ctx.db()) .await?; - crate::builders::collection(&upub::url!(ctx, "/objects/{id}/context"), Some(count)) + crate::builders::collection(upub::url!(ctx, "/objects/{id}/context"), Some(count)) } pub async fn page( diff --git a/upub/routes/src/activitypub/object/mod.rs b/upub/routes/src/activitypub/object/mod.rs index de4613d..5b046c8 100644 --- a/upub/routes/src/activitypub/object/mod.rs +++ b/upub/routes/src/activitypub/object/mod.rs @@ -55,7 +55,7 @@ pub async fn view( replies = apb::Node::object( apb::new() - .set_id(Some(&upub::url!(ctx, "/objects/{id}/replies"))) + .set_id(Some(upub::url!(ctx, "/objects/{id}/replies"))) .set_first(apb::Node::link(upub::url!(ctx, "/objects/{id}/replies/page"))) .set_collection_type(Some(apb::CollectionType::Collection)) .set_total_items(item.object.as_ref().map(|x| x.replies as u64)) diff --git a/upub/routes/src/activitypub/object/replies.rs b/upub/routes/src/activitypub/object/replies.rs index 425df01..caaa968 100644 --- a/upub/routes/src/activitypub/object/replies.rs +++ b/upub/routes/src/activitypub/object/replies.rs @@ -32,7 +32,7 @@ pub async fn get( Ok(JsonLD( apb::new() - .set_id(Some(&upub::url!(ctx, "/objects/{id}/replies"))) + .set_id(Some(upub::url!(ctx, "/objects/{id}/replies"))) .set_collection_type(Some(apb::CollectionType::Collection)) .set_first(apb::Node::link(upub::url!(ctx, "/objects/{id}/replies/page"))) .set_total_items(Some(replies_ids.len() as u64)) diff --git a/upub/routes/src/activitypub/outbox.rs b/upub/routes/src/activitypub/outbox.rs index edec93f..1b4e1e2 100644 --- a/upub/routes/src/activitypub/outbox.rs +++ b/upub/routes/src/activitypub/outbox.rs @@ -5,7 +5,7 @@ use upub::Context; use crate::{activitypub::{CreationResult, Pagination}, AuthIdentity, builders::JsonLD}; pub async fn get(State(ctx): State) -> crate::ApiResult> { - crate::builders::collection(&upub::url!(ctx, "/outbox"), None) + crate::builders::collection(upub::url!(ctx, "/outbox"), None) } pub async fn page( diff --git a/upub/routes/src/activitypub/tags.rs b/upub/routes/src/activitypub/tags.rs index 415bf04..52f7925 100644 --- a/upub/routes/src/activitypub/tags.rs +++ b/upub/routes/src/activitypub/tags.rs @@ -10,7 +10,7 @@ pub async fn get( Path(id): Path, ) -> crate::ApiResult> { crate::builders::collection( - &upub::url!(ctx, "/tags/{id}"), + upub::url!(ctx, "/tags/{id}"), None, ) } diff --git a/upub/routes/src/builders.rs b/upub/routes/src/builders.rs index 51be453..8c9a756 100644 --- a/upub/routes/src/builders.rs +++ b/upub/routes/src/builders.rs @@ -63,7 +63,7 @@ pub fn collection_page(id: &str, offset: u64, limit: u64, items: Vec) -> crate::ApiResult> { +pub fn collection(id: String, total_items: Option) -> crate::ApiResult> { Ok(JsonLD( apb::new() - .set_id(Some(id)) .set_collection_type(Some(apb::CollectionType::OrderedCollection)) .set_first(apb::Node::link(format!("{id}/page"))) .set_total_items(total_items) + .set_id(Some(id)) .ld_context() )) } diff --git a/upub/worker/src/outbound.rs b/upub/worker/src/outbound.rs index ef4b76a..295aaad 100644 --- a/upub/worker/src/outbound.rs +++ b/upub/worker/src/outbound.rs @@ -1,4 +1,4 @@ -use apb::{field::OptionalString, target::Addressed, Activity, ActivityMut, Base, BaseMut, Object, ObjectMut}; +use apb::{target::Addressed, Activity, ActivityMut, Base, BaseMut, Object, ObjectMut, Shortcuts}; use sea_orm::{prelude::Expr, ColumnTrait, DbErr, EntityTrait, QueryFilter, QueryOrder, QuerySelect, SelectColumns, TransactionTrait}; use upub::{model::{self, actor::Field}, traits::{process::ProcessorError, Addresser, Processor}, Context}; @@ -17,7 +17,7 @@ pub async fn process(ctx: Context, job: &model::job::Model) -> crate::JobResult< let actor = upub::model::actor::Entity::ap_to_internal(&job.actor, &tx) .await? .ok_or_else(|| DbErr::RecordNotFound(job.actor.clone()))?; - let activity = upub::model::activity::Entity::ap_to_internal(activity.object().id()?, &tx) + let activity = upub::model::activity::Entity::ap_to_internal(&activity.object().id()?, &tx) .await? .ok_or_else(|| DbErr::RecordNotFound(activity.object().id().unwrap_or_default().to_string()))?; upub::model::notification::Entity::update_many() @@ -41,14 +41,14 @@ pub async fn process(ctx: Context, job: &model::job::Model) -> crate::JobResult< } activity = activity - .set_id(Some(&job.activity)) + .set_id(Some(job.activity.clone())) .set_actor(apb::Node::link(job.actor.clone())) .set_published(Some(now)); if matches!(t, apb::ObjectType::Activity(apb::ActivityType::Undo)) { let mut undone = activity.object().into_inner()?; if undone.id().is_err() { - let undone_target = undone.object().id().str().ok_or(crate::JobError::MissingPayload)?; + let undone_target = undone.object().id()?; let undone_type = undone.activity_type().map_err(|_| crate::JobError::MissingPayload)?; let undone_model = model::activity::Entity::find() .filter(model::activity::Column::Object.eq(&undone_target)) @@ -59,7 +59,7 @@ pub async fn process(ctx: Context, job: &model::job::Model) -> crate::JobResult< .await? .ok_or_else(|| sea_orm::DbErr::RecordNotFound(format!("actor={},type={},object={}",job.actor, undone_type, undone_target)))?; undone = undone - .set_id(Some(&undone_model.id)) + .set_id(Some(undone_model.id)) .set_actor(apb::Node::link(job.actor.clone())); } activity = activity.set_object(apb::Node::object(undone)); @@ -67,7 +67,7 @@ pub async fn process(ctx: Context, job: &model::job::Model) -> crate::JobResult< macro_rules! update { ($prev:ident, $field:ident, $getter:expr) => { - if let Some($field) = $getter { + if let Ok($field) = $getter { $prev.$field = Some($field.to_string()); } }; @@ -77,7 +77,7 @@ pub async fn process(ctx: Context, job: &model::job::Model) -> crate::JobResult< let mut updated = activity.object().into_inner()?; match updated.object_type()? { apb::ObjectType::Actor(_) => { - let mut prev = model::actor::Entity::find_by_ap_id(updated.id()?) + let mut prev = model::actor::Entity::find_by_ap_id(&updated.id()?) .one(&tx) .await? .ok_or_else(|| crate::JobError::MissingPayload)?; @@ -86,10 +86,10 @@ pub async fn process(ctx: Context, job: &model::job::Model) -> crate::JobResult< return Err(crate::JobError::Forbidden); } - update!(prev, name, updated.name().ok()); - update!(prev, summary, updated.summary().ok()); - update!(prev, icon, updated.icon().get().and_then(|x| x.url().id().str())); - update!(prev, image, updated.image().get().and_then(|x| x.url().id().str())); + update!(prev, name, updated.name()); + update!(prev, summary, updated.summary()); + update!(prev, icon, updated.icon_url()); + update!(prev, image, updated.image_url()); if !updated.attachment().is_empty() { prev.fields = updated.attachment() @@ -104,7 +104,7 @@ pub async fn process(ctx: Context, job: &model::job::Model) -> crate::JobResult< updated = prev.ap(); }, apb::ObjectType::Note => { - let mut prev = model::object::Entity::find_by_ap_id(updated.id()?) + let mut prev = model::object::Entity::find_by_ap_id(&updated.id()?) .one(&tx) .await? .ok_or_else(|| crate::JobError::MissingPayload)?; @@ -113,10 +113,10 @@ pub async fn process(ctx: Context, job: &model::job::Model) -> crate::JobResult< return Err(crate::JobError::Forbidden); } - update!(prev, name, updated.name().ok()); - update!(prev, summary, updated.summary().ok()); - update!(prev, content, updated.content().ok()); - update!(prev, image, updated.image().get().and_then(|x| x.url().id().str())); + update!(prev, name, updated.name()); + update!(prev, summary, updated.summary()); + update!(prev, content, updated.content()); + update!(prev, image, updated.image_url()); if let Ok(sensitive) = updated.sensitive() { prev.sensitive = sensitive; @@ -158,8 +158,8 @@ pub async fn process(ctx: Context, job: &model::job::Model) -> crate::JobResult< activity = activity .set_object(apb::Node::object( object - .set_id(Some(&oid)) - .set_content(content.as_deref()) + .set_id(Some(oid)) + .set_content(content) .set_attributed_to(apb::Node::link(job.actor.clone())) .set_published(Some(now)) .set_updated(Some(now)) diff --git a/web/src/activities/item.rs b/web/src/activities/item.rs index 14e6c59..fa7aeec 100644 --- a/web/src/activities/item.rs +++ b/web/src/activities/item.rs @@ -1,16 +1,16 @@ use leptos::*; use crate::prelude::*; -use apb::{field::OptionalString, target::Addressed, Activity, ActivityMut, Base, Object}; +use apb::{target::Addressed, Activity, ActivityMut, Base, Object}; #[component] pub fn ActivityLine(activity: crate::Object, children: Children) -> impl IntoView { - let object_id = activity.object().id().str().unwrap_or_default(); + let object_id = activity.object().id().unwrap_or_default(); let activity_url = activity.id().map(|x| view! { "↗" }); - let actor_id = activity.actor().id().str().unwrap_or_default(); + let actor_id = activity.actor().id().unwrap_or_default(); let actor = cache::OBJECTS.get_or(&actor_id, serde_json::Value::String(actor_id.clone()).into()); let kind = activity.activity_type().unwrap_or(apb::ActivityType::Activity); let href = match kind { @@ -60,7 +60,7 @@ pub fn Item( Some(view! { {sep.clone()} }.into_view()), // everything else apb::ObjectType::Activity(t) => { - let object_id = item.object().id().str().unwrap_or_default(); + let object_id = item.object().id().unwrap_or_default(); let object = match t { apb::ActivityType::Create | apb::ActivityType::Announce => cache::OBJECTS.get(&object_id).map(|obj| { diff --git a/web/src/actors/header.rs b/web/src/actors/header.rs index 4036aae..3a985cb 100644 --- a/web/src/actors/header.rs +++ b/web/src/actors/header.rs @@ -2,7 +2,7 @@ use leptos::*; use leptos_router::*; use crate::{getters::Getter, prelude::*, FALLBACK_IMAGE_URL}; -use apb::{field::OptionalString, ActivityMut, Actor, Base, Object, ObjectMut}; +use apb::{ActivityMut, Actor, Base, Object, ObjectMut, Shortcuts}; #[component] pub fn ActorHeader() -> impl IntoView { @@ -16,7 +16,7 @@ pub fn ActorHeader() -> impl IntoView { Some(x) => Some(x.clone()), None => { let user = cache::OBJECTS.resolve(&id, U::Actor, auth).await?; - if let Some(url) = user.url().id().str() { + if let Ok(url) = user.url().id() { cache::WEBFINGER.store(&url, user.id().unwrap_or_default().to_string()); } Some(user) @@ -29,10 +29,10 @@ pub fn ActorHeader() -> impl IntoView { None => view! { }.into_view(), Some(None) => view! { "could not resolve user" }.into_view(), Some(Some(actor)) => { - let avatar_url = actor.icon().get().map(|x| x.url().id().str().unwrap_or(FALLBACK_IMAGE_URL.into())).unwrap_or(FALLBACK_IMAGE_URL.into()); - let background_url = actor.image().get().map(|x| x.url().id().str().unwrap_or(FALLBACK_IMAGE_URL.into())).unwrap_or(FALLBACK_IMAGE_URL.into()); + let avatar_url = actor.icon_url().unwrap_or(FALLBACK_IMAGE_URL.into()); + let background_url = actor.image_url().unwrap_or(FALLBACK_IMAGE_URL.into()); let username = actor.preferred_username().unwrap_or_default().to_string(); - let name = actor.name().str().unwrap_or(username.clone()); + let name = actor.name().unwrap_or(username.clone()); let created = actor.published().ok(); let following_me = actor.following_me().unwrap_or(false); let followed_by_me = actor.followed_by_me().unwrap_or(false); @@ -44,11 +44,11 @@ pub fn ActorHeader() -> impl IntoView { let fields = actor.attachment() .flat() .into_iter() - .filter_map(|x| x.extract()) + .filter_map(|x| x.into_inner().ok()) .map(|x| view! { - {x.name().str().unwrap_or_default()} - + {x.name().unwrap_or_default()} + }) .collect_view(); @@ -110,7 +110,7 @@ pub fn ActorHeader() -> impl IntoView { }} -

+

{fields}

diff --git a/web/src/components/post.rs b/web/src/components/post.rs index b56b72e..d3f3f39 100644 --- a/web/src/components/post.rs +++ b/web/src/components/post.rs @@ -1,4 +1,4 @@ -use apb::{field::OptionalString, ActivityMut, Base, BaseMut, Object, ObjectMut}; +use apb::{ActivityMut, Base, BaseMut, Object, ObjectMut}; use leptos::*; use crate::prelude::*; @@ -12,7 +12,7 @@ pub struct ReplyControls { impl ReplyControls { pub fn reply(&self, oid: &str) { if let Some(obj) = cache::OBJECTS.get(oid) { - self.context.set(obj.context().id().str()); + self.context.set(obj.context().id().ok()); self.reply_to.set(obj.id().ok().map(|x| x.to_string())); } } @@ -24,7 +24,7 @@ impl ReplyControls { } fn post_author(post_id: &str) -> Option { - let usr = cache::OBJECTS.get(post_id)?.attributed_to().id().str()?; + let usr = cache::OBJECTS.get(post_id)?.attributed_to().id().ok()?; cache::OBJECTS.get(&usr) } @@ -135,9 +135,9 @@ pub fn PostBox(advanced: WriteSignal) -> impl IntoView { .into_iter() .map(|x| { use apb::LinkMut; - LinkMut::set_name(apb::new(), Some(&format!("@{}@{}", x.name, x.domain))) // TODO ewww but name clashes + LinkMut::set_name(apb::new(), Some(format!("@{}@{}", x.name, x.domain))) // TODO ewww but name clashes .set_link_type(Some(apb::LinkType::Mention)) - .set_href(Some(&x.href)) + .set_href(Some(x.href)) }) .collect(); @@ -146,10 +146,10 @@ pub fn PostBox(advanced: WriteSignal) -> impl IntoView { if let Ok(uid) = au.id() { to_vec.push(uid.to_string()); if let Ok(name) = au.name() { - let domain = Uri::domain(uid); + let domain = Uri::domain(&uid); mention_tags.push({ use apb::LinkMut; - LinkMut::set_name(apb::new(), Some(&format!("@{}@{}", name, domain))) // TODO ewww but name clashes + LinkMut::set_name(apb::new(), Some(format!("@{}@{}", name, domain))) // TODO ewww but name clashes .set_link_type(Some(apb::LinkType::Mention)) .set_href(Some(uid)) }); @@ -162,8 +162,8 @@ pub fn PostBox(advanced: WriteSignal) -> impl IntoView { } let payload = apb::new() .set_object_type(Some(apb::ObjectType::Note)) - .set_summary(summary.as_deref()) - .set_content(Some(&content)) + .set_summary(summary) + .set_content(Some(content)) .set_context(apb::Node::maybe_link(reply.context.get())) .set_in_reply_to(apb::Node::maybe_link(reply.reply_to.get())) .set_to(apb::Node::links(to_vec)) @@ -299,11 +299,11 @@ pub fn AdvancedPostBox(advanced: WriteSignal) -> impl IntoView { if embedded.get() { apb::Node::object( serde_json::Value::Object(serde_json::Map::default()) - .set_id(object_id.as_deref()) + .set_id(object_id) .set_object_type(Some(apb::ObjectType::Note)) - .set_name(name.as_deref()) - .set_summary(summary.as_deref()) - .set_content(content.as_deref()) + .set_name(name) + .set_summary(summary) + .set_content(content) .set_in_reply_to(apb::Node::maybe_link(reply)) .set_context(apb::Node::maybe_link(context)) .set_to(apb::Node::links(to)) diff --git a/web/src/components/user.rs b/web/src/components/user.rs index 4624713..cc2065d 100644 --- a/web/src/components/user.rs +++ b/web/src/components/user.rs @@ -1,7 +1,7 @@ use leptos::*; use crate::{prelude::*, FALLBACK_IMAGE_URL}; -use apb::{field::OptionalString, Activity, ActivityMut, Actor, Base, Object, ObjectMut}; +use apb::{Activity, ActivityMut, Actor, Base, Object, ObjectMut, Shortcuts}; lazy_static::lazy_static! { static ref REGEX: regex::Regex = regex::Regex::new(r":\w+:").expect("failed compiling custom emoji regex"); @@ -12,7 +12,7 @@ pub fn ActorStrip(object: crate::Object) -> impl IntoView { let actor_id = object.id().unwrap_or_default().to_string(); let username = object.preferred_username().unwrap_or_default().to_string(); let domain = object.id().unwrap_or_default().replace("https://", "").split('/').next().unwrap_or_default().to_string(); - let avatar = object.icon().get().map(|x| x.url().id().str().unwrap_or(FALLBACK_IMAGE_URL.into())).unwrap_or(FALLBACK_IMAGE_URL.into()); + let avatar = object.icon_url().unwrap_or(FALLBACK_IMAGE_URL.into()); view! { {username}@{domain} @@ -29,7 +29,7 @@ pub fn ActorBanner(object: crate::Object) -> impl IntoView { serde_json::Value::Object(_) => { let uid = object.id().unwrap_or_default().to_string(); let uri = Uri::web(U::Actor, &uid); - let avatar_url = object.icon().get().map(|x| x.url().id().str().unwrap_or(FALLBACK_IMAGE_URL.into())).unwrap_or(FALLBACK_IMAGE_URL.into()); + let avatar_url = object.icon_url().unwrap_or(FALLBACK_IMAGE_URL.into()); let username = object.preferred_username().unwrap_or_default().to_string(); let domain = object.id().unwrap_or_default().replace("https://", "").split('/').next().unwrap_or_default().to_string(); let display_name = object.name().unwrap_or_default().to_string(); @@ -70,7 +70,7 @@ pub fn FollowRequestButtons(activity_id: String, actor_id: String) -> impl IntoV // TODO lmao what is going on with this double move / triple clone ??????????? let _activity_id = activity_id.clone(); let _actor_id = actor_id.clone(); - let from_actor = cache::OBJECTS.get(&activity_id).map(|x| x.actor().id().str().unwrap_or_default()).unwrap_or_default(); + let from_actor = cache::OBJECTS.get(&activity_id).and_then(|x| x.actor().id().ok()).unwrap_or_default(); let _from_actor = from_actor.clone(); if actor_id == auth.user_id() { Some(view! { diff --git a/web/src/config.rs b/web/src/config.rs index e460e8d..48c7109 100644 --- a/web/src/config.rs +++ b/web/src/config.rs @@ -66,7 +66,7 @@ impl FiltersConfig { let mut reply_filter = true; if let Ok(obj_id) = item.object().id() { - if let Some(obj) = crate::cache::OBJECTS.get(obj_id) { + if let Some(obj) = crate::cache::OBJECTS.get(&obj_id) { if obj.in_reply_to().id().is_ok() { reply_filter = self.replies; } diff --git a/web/src/objects/attachment.rs b/web/src/objects/attachment.rs index a028795..965d1e8 100644 --- a/web/src/objects/attachment.rs +++ b/web/src/objects/attachment.rs @@ -2,7 +2,7 @@ use leptos::*; use crate::{prelude::*, URL_SENSITIVE}; use base64::prelude::*; -use apb::{field::OptionalString, Document, Object}; +use apb::{Document, Object}; fn uncloak(txt: Option<&str>) -> Option { let decoded = BASE64_URL_SAFE.decode(txt?).ok()?; @@ -17,11 +17,10 @@ pub fn Attachment( ) -> impl IntoView { let config = use_context::>().expect("missing config context"); let (expand, set_expand) = create_signal(false); - let href = object.url().id().str().unwrap_or_default(); + let href = object.url().id().ok().unwrap_or_default(); let uncloaked = uncloak(href.split('/').last()).unwrap_or_default(); let media_type = object.media_type() - .unwrap_or("link") // TODO make it an Option rather than defaulting to link everywhere - .to_string(); + .unwrap_or("link".to_string()); // TODO make it an Option rather than defaulting to link everywhere let mut kind = media_type .split('/') .next() diff --git a/web/src/objects/item.rs b/web/src/objects/item.rs index 21b8204..91f1ffa 100644 --- a/web/src/objects/item.rs +++ b/web/src/objects/item.rs @@ -3,29 +3,26 @@ use std::sync::Arc; use leptos::*; use crate::{prelude::*, URL_SENSITIVE}; -use apb::{field::OptionalString, target::Addressed, ActivityMut, Base, Collection, CollectionMut, Object, ObjectMut}; +use apb::{target::Addressed, ActivityMut, Base, Collection, CollectionMut, Object, ObjectMut}; #[component] pub fn Object(object: crate::Object) -> impl IntoView { let oid = object.id().unwrap_or_default().to_string(); - let author_id = object.attributed_to().id().str().unwrap_or_default(); + let author_id = object.attributed_to().id().ok().unwrap_or_default(); let author = cache::OBJECTS.get_or(&author_id, serde_json::Value::String(author_id.clone()).into()); let sensitive = object.sensitive().unwrap_or_default(); let addressed = object.addressed(); let public = addressed.iter().any(|x| x.as_str() == apb::target::PUBLIC); - let external_url = object.url().id().str().unwrap_or_else(|| oid.clone()); + let external_url = object.url().id().ok().unwrap_or_else(|| oid.clone()); let attachments = object.attachment() .flat() .into_iter() - .filter_map(|x| x.extract()) // TODO maybe show links? + .filter_map(|x| x.into_inner().ok()) // TODO maybe show links? .map(|x| view! { }) .collect_view(); - let comments = object.replies().get() - .map_or(0, |x| x.total_items().unwrap_or(0)); - let shares = object.shares().get() - .map_or(0, |x| x.total_items().unwrap_or(0)); - let likes = object.likes().get() - .map_or(0, |x| x.total_items().unwrap_or(0)); + let comments = object.replies().inner().and_then(|x| x.total_items()).unwrap_or_default(); + let shares = object.shares().inner().and_then(|x| x.total_items()).unwrap_or_default(); + let likes = object.likes().inner().and_then(|x| x.total_items()).unwrap_or_default(); let already_liked = object.liked_by_me().unwrap_or(false); let attachments_padding = if object.attachment().is_empty() { @@ -34,9 +31,9 @@ pub fn Object(object: crate::Object) -> impl IntoView { Some(view! {
}) }; - let content = mdhtml::safe_html(object.content().unwrap_or_default()); + let content = mdhtml::safe_html(&object.content().unwrap_or_default()); - let audience_badge = object.audience().id().str() + let audience_badge = object.audience().id().ok() .map(|x| { // TODO this isn't guaranteed to work every time... let name = x.split('/').last().unwrap_or_default().to_string(); @@ -56,7 +53,7 @@ pub fn Object(object: crate::Object) -> impl IntoView { .id() .ok() .map(|x| { - let href = Uri::web(U::Object, x); + let href = Uri::web(U::Object, &x); view! {
@@ -103,7 +100,7 @@ pub fn Object(object: crate::Object) -> impl IntoView { uid.replace("https://", "").replace("http://", "").split('/').next().unwrap_or_default().to_string(), ) }; - let href = Uri::web(U::Actor, uid); + let href = Uri::web(U::Actor, &uid); Some(view! { @@ -119,7 +116,7 @@ pub fn Object(object: crate::Object) -> impl IntoView { } }).collect_view(); - let post_image = object.image().get().and_then(|x| x.url().id().str()).map(|x| { + let post_image = object.image().inner().and_then(|x| x.url().id()).ok().map(|x| { let (expand, set_expand) = create_signal(false); view! { impl IntoView { - {object.in_reply_to().id().str().map(|reply| view! { + {object.in_reply_to().id().ok().map(|reply| view! { reply })} - + "↗" @@ -262,7 +259,7 @@ pub fn LikeButton( set_count.set(count.get() + 1); if let Some(cached) = cache::OBJECTS.get(&target) { let mut new = (*cached).clone().set_liked_by_me(Some(true)); - if let Some(likes) = new.likes().get() { + if let Ok(likes) = new.likes().inner() { if let Ok(count) = likes.total_items() { new = new.set_likes(apb::Node::object(likes.clone().set_total_items(Some(count + 1)))); } diff --git a/web/src/objects/view.rs b/web/src/objects/view.rs index 7bf11b8..9aa7db5 100644 --- a/web/src/objects/view.rs +++ b/web/src/objects/view.rs @@ -13,7 +13,7 @@ pub fn ObjectView() -> impl IntoView { move |oid| async move { let obj = cache::OBJECTS.resolve(&oid, U::Object, auth).await?; if let Ok(author) = obj.attributed_to().id() { - cache::OBJECTS.resolve(author, U::Actor, auth).await; + cache::OBJECTS.resolve(&author, U::Actor, auth).await; } Some(obj) @@ -36,8 +36,8 @@ pub fn ObjectView() -> impl IntoView { Some(Some(o)) => { let object = o.clone(); let oid = o.id().unwrap_or_default(); - let base = Uri::web(U::Object, oid); - let api = Uri::api(U::Object, oid, false); + let base = Uri::web(U::Object, &oid); + let api = Uri::api(U::Object, &oid, false); view!{
diff --git a/web/src/page/config.rs b/web/src/page/config.rs index 23aa837..493676a 100644 --- a/web/src/page/config.rs +++ b/web/src/page/config.rs @@ -21,10 +21,15 @@ pub fn ConfigPage(setter: WriteSignal) -> impl IntoView { let banner_url_ref: NodeRef = create_node_ref(); let myself = cache::OBJECTS.get(&auth.userid.get_untracked().unwrap_or_default()); - let curr_display_name = myself.as_ref().and_then(|x| Some(x.name().ok()?.to_string())).unwrap_or_default(); - let curr_summary = myself.as_ref().and_then(|x| Some(x.summary().ok()?.to_string())).unwrap_or_default(); - let curr_icon = myself.as_ref().and_then(|x| Some(x.icon().get()?.url().id().ok()?.to_string())).unwrap_or_default(); - let curr_banner = myself.as_ref().and_then(|x| Some(x.image().get()?.url().id().ok()?.to_string())).unwrap_or_default(); + let (curr_display_name, curr_summary, curr_icon, curr_banner) = match myself.as_ref() { + None => (String::default(), String::default(), String::default(), String::default()), + Some(myself) => ( + myself.name().unwrap_or_default().to_string(), + myself.summary().unwrap_or_default().to_string(), + myself.icon().inner().and_then(|x| Ok(x.url().id()?.to_string())).unwrap_or_default(), + myself.image().inner().and_then(|x| Ok(x.url().id()?.to_string())).unwrap_or_default(), + ), + }; macro_rules! get_cfg { (filter $field:ident) => { @@ -175,8 +180,8 @@ pub fn ConfigPage(setter: WriteSignal) -> impl IntoView { .set_to(apb::Node::links(vec![apb::target::PUBLIC.to_string(), format!("{id}/followers")])) .set_object(apb::Node::object( (*me).clone() - .set_name(display_name.as_deref()) - .set_summary(summary.as_deref()) + .set_name(display_name) + .set_summary(summary) .set_icon(apb::Node::maybe_object(avatar)) .set_image(apb::Node::maybe_object(banner)) .set_published(Some(chrono::Utc::now())) diff --git a/web/src/page/search.rs b/web/src/page/search.rs index fcb6cbd..2ac755f 100644 --- a/web/src/page/search.rs +++ b/web/src/page/search.rs @@ -41,7 +41,7 @@ pub fn SearchPage() -> impl IntoView { .ordered_items() .flat() .into_iter() - .filter_map(|x| x.extract()) + .filter_map(|x| x.into_inner().ok()) .collect(), auth ).await diff --git a/web/src/timeline/mod.rs b/web/src/timeline/mod.rs index 2ce91b3..0503766 100644 --- a/web/src/timeline/mod.rs +++ b/web/src/timeline/mod.rs @@ -3,7 +3,7 @@ pub mod thread; use std::{collections::BTreeSet, pin::Pin, sync::Arc}; -use apb::{field::OptionalString, Activity, ActivityMut, Actor, Base, Object}; +use apb::{Activity, ActivityMut, Actor, Base, Object}; use leptos::*; use crate::prelude::*; @@ -89,7 +89,7 @@ impl Timeline { .ordered_items() .flat() .into_iter() - .filter_map(|x| x.extract()) + .filter_map(|x| x.into_inner().ok()) .collect(); let mut feed = self.feed.get_untracked(); @@ -121,18 +121,18 @@ pub async fn process_activities(activities: Vec, auth: Auth) for activity in activities { let activity_type = activity.activity_type().unwrap_or(apb::ActivityType::Activity); // save embedded object if present - if let Some(object) = activity.object().get() { + if let Ok(object) = activity.object().inner() { // also fetch actor attributed to - if let Some(attributed_to) = object.attributed_to().id().str() { + if let Ok(attributed_to) = object.attributed_to().id() { actors_seen.insert(attributed_to); } if let Ok(object_uri) = object.id() { - cache::OBJECTS.store(object_uri, Arc::new(object.clone())); + cache::OBJECTS.store(&object_uri, Arc::new(object.clone())); } else { tracing::warn!("embedded object without id: {object:?}"); } } else { // try fetching it - if let Some(object_id) = activity.object().id().str() { + if let Ok(object_id) = activity.object().id() { if !gonna_fetch.contains(&object_id) { let fetch_kind = match activity_type { apb::ActivityType::Follow => U::Actor, @@ -145,25 +145,25 @@ pub async fn process_activities(activities: Vec, auth: Auth) } // save activity, removing embedded object - let object_id = activity.object().id().str(); - if let Some(activity_id) = activity.id().str() { + let object_id = activity.object().id().ok(); + if let Ok(activity_id) = activity.id() { out.push(activity_id.to_string()); cache::OBJECTS.store( &activity_id, Arc::new(activity.clone().set_object(apb::Node::maybe_link(object_id))) ); - } else if let Some(object_id) = activity.object().id().str() { + } else if let Ok(object_id) = activity.object().id() { out.push(object_id); } - if let Some(uid) = activity.attributed_to().id().str() { + if let Ok(uid) = activity.attributed_to().id() { if cache::OBJECTS.get(&uid).is_none() && !gonna_fetch.contains(&uid) { gonna_fetch.insert(uid.clone()); sub_tasks.push(Box::pin(fetch_and_update(U::Actor, uid, auth))); } } - if let Some(uid) = activity.actor().id().str() { + if let Ok(uid) = activity.actor().id() { if cache::OBJECTS.get(&uid).is_none() && !gonna_fetch.contains(&uid) { gonna_fetch.insert(uid.clone()); sub_tasks.push(Box::pin(fetch_and_update(U::Actor, uid, auth))); @@ -185,7 +185,7 @@ async fn fetch_and_update(kind: U, id: String, auth: Auth) { Err(e) => console_warn(&format!("could not fetch '{id}': {e}")), Ok(data) => { if data.actor_type().is_ok() { - if let Some(url) = data.url().id().str() { + if let Ok(url) = data.url().id() { cache::WEBFINGER.store(&id, url); } } @@ -198,8 +198,8 @@ async fn fetch_and_update_with_user(kind: U, id: String, auth: Auth) { fetch_and_update(kind, id.clone(), auth).await; if let Some(obj) = cache::OBJECTS.get(&id) { if let Some(actor_id) = match kind { - U::Object => obj.attributed_to().id().str(), - U::Activity => obj.actor().id().str(), + U::Object => obj.attributed_to().id().ok(), + U::Activity => obj.actor().id().ok(), U::Actor => None, U::Hashtag => None, } { diff --git a/web/src/timeline/thread.rs b/web/src/timeline/thread.rs index 2eb650b..f22fc45 100644 --- a/web/src/timeline/thread.rs +++ b/web/src/timeline/thread.rs @@ -1,4 +1,4 @@ -use apb::{field::OptionalString, Activity, Base, Object}; +use apb::{Activity, Base, Object}; use leptos::*; use crate::prelude::*; use super::Timeline; @@ -40,15 +40,15 @@ fn FeedRecursive(tl: Timeline, root: String) -> impl IntoView { let (oid, reply) = match document.object_type().ok()? { // if it's a create, get and check created object: does it reply to root? apb::ObjectType::Activity(apb::ActivityType::Create) => { - let object = cache::OBJECTS.get(document.object().id().ok()?)?; - (object.id().str()?, object.in_reply_to().id().str()?) + let object = cache::OBJECTS.get(&document.object().id().ok()?)?; + (object.id().ok()?, object.in_reply_to().id().ok()?) }, // if it's a raw note, directly check if it replies to root - apb::ObjectType::Note => (document.id().str()?, document.in_reply_to().id().str()?), + apb::ObjectType::Note => (document.id().ok()?, document.in_reply_to().id().ok()?), // if it's anything else, check if it relates to root, maybe like or announce? - _ => (document.id().str()?, document.object().id().str()?), + _ => (document.id().ok()?, document.object().id().ok()?), }; if reply == root { Some((oid, document))