fix: store in_reply_to on remote notes + use full handle in federation component links/actions

This commit is contained in:
2026-05-15 05:09:44 +02:00
parent e04b08c202
commit 09bebf7dc9
8 changed files with 28 additions and 8 deletions

View File

@@ -144,6 +144,7 @@ impl ApObjectHandler for ThoughtsObjectHandler {
note.sensitive, note.sensitive,
note.summary, note.summary,
visibility, visibility,
note.in_reply_to.as_ref(),
) )
.await .await
.map_err(|e| anyhow!("{e}")) .map_err(|e| anyhow!("{e}"))

View File

@@ -218,11 +218,24 @@ impl ActivityPubRepository for PgActivityPubRepository {
sensitive: bool, sensitive: bool,
content_warning: Option<String>, content_warning: Option<String>,
visibility: &str, visibility: &str,
in_reply_to: Option<&Url>,
) -> Result<(), DomainError> { ) -> Result<(), DomainError> {
let capped: String = content.chars().take(500).collect(); let capped: String = content.chars().take(500).collect();
let (in_reply_to_id, in_reply_to_url) = match in_reply_to {
Some(url) => {
// If the parent is a local thought, extract its UUID for in_reply_to_id.
let local_uuid = url
.path()
.strip_prefix("/thoughts/")
.and_then(|s| s.split('/').next())
.and_then(|s| uuid::Uuid::parse_str(s).ok());
(local_uuid, Some(url.as_str().to_string()))
}
None => (None, None),
};
sqlx::query( sqlx::query(
"INSERT INTO thoughts(id,user_id,content,ap_id,visibility,sensitive,local,content_warning,created_at) "INSERT INTO thoughts(id,user_id,content,ap_id,visibility,sensitive,local,content_warning,created_at,in_reply_to_id,in_reply_to_url)
VALUES($1,$2,$3,$4,$8,$5,false,$6,$7) ON CONFLICT(ap_id) DO NOTHING", VALUES($1,$2,$3,$4,$8,$5,false,$6,$7,$9,$10) ON CONFLICT(ap_id) DO NOTHING",
) )
.bind(uuid::Uuid::new_v4()) .bind(uuid::Uuid::new_v4())
.bind(author_id.as_uuid()) .bind(author_id.as_uuid())
@@ -232,6 +245,8 @@ impl ActivityPubRepository for PgActivityPubRepository {
.bind(content_warning) .bind(content_warning)
.bind(published) .bind(published)
.bind(visibility) .bind(visibility)
.bind(in_reply_to_id)
.bind(&in_reply_to_url)
.execute(&self.pool) .execute(&self.pool)
.await .await
.map_err(|e| DomainError::Internal(e.to_string())) .map_err(|e| DomainError::Internal(e.to_string()))

View File

@@ -173,6 +173,7 @@ impl FederationEventService {
note.sensitive, note.sensitive,
note.content_warning, note.content_warning,
"public", "public",
None,
) )
.await; .await;
} }

View File

@@ -391,6 +391,7 @@ pub trait ActivityPubRepository: Send + Sync {
sensitive: bool, sensitive: bool,
content_warning: Option<String>, content_warning: Option<String>,
visibility: &str, visibility: &str,
in_reply_to: Option<&url::Url>,
) -> Result<(), DomainError>; ) -> Result<(), DomainError>;
/// Apply an Update to a previously accepted remote Note. /// Apply an Update to a previously accepted remote Note.

View File

@@ -847,6 +847,7 @@ impl ActivityPubRepository for TestStore {
_sensitive: bool, _sensitive: bool,
_content_warning: Option<String>, _content_warning: Option<String>,
_visibility: &str, _visibility: &str,
_in_reply_to: Option<&url::Url>,
) -> Result<(), DomainError> { ) -> Result<(), DomainError> {
Ok(()) Ok(())
} }

View File

@@ -59,7 +59,7 @@ export function PendingRequests({ compact = false }: Props) {
className="flex items-center justify-between gap-3" className="flex items-center justify-between gap-3"
> >
<Link <Link
href={`/users/@${actor.handle}`} href={`/users/@${fullFediverseHandle(actor.handle, actor.url)}`}
className="flex items-center gap-2 min-w-0 hover:opacity-80" className="flex items-center gap-2 min-w-0 hover:opacity-80"
> >
<UserAvatar <UserAvatar

View File

@@ -39,7 +39,7 @@ export function RemoteFollowers() {
{followers.map((actor) => ( {followers.map((actor) => (
<li key={actor.url} className="flex items-center justify-between gap-3"> <li key={actor.url} className="flex items-center justify-between gap-3">
<Link <Link
href={`/users/@${actor.handle}`} href={`/users/@${fullFediverseHandle(actor.handle, actor.url)}`}
className="flex items-center gap-2 min-w-0 hover:opacity-80" className="flex items-center gap-2 min-w-0 hover:opacity-80"
> >
<UserAvatar <UserAvatar

View File

@@ -22,9 +22,10 @@ export function RemoteFollowing() {
.finally(() => setLoading(false)); .finally(() => setLoading(false));
}, [token]); }, [token]);
const unfollow = async (handle: string) => { const unfollow = async (actor: RemoteActor) => {
if (!token) return; if (!token) return;
setFollowing((prev) => prev.filter((f) => f.handle !== handle)); const handle = fullFediverseHandle(actor.handle, actor.url);
setFollowing((prev) => prev.filter((f) => f.url !== actor.url));
await unfollowRemoteActor(handle, token).catch(() => { await unfollowRemoteActor(handle, token).catch(() => {
toast.error("Failed to unfollow"); toast.error("Failed to unfollow");
}); });
@@ -39,7 +40,7 @@ export function RemoteFollowing() {
{following.map((actor) => ( {following.map((actor) => (
<li key={actor.url} className="flex items-center justify-between gap-3"> <li key={actor.url} className="flex items-center justify-between gap-3">
<Link <Link
href={`/users/@${actor.handle}`} href={`/users/@${fullFediverseHandle(actor.handle, actor.url)}`}
className="flex items-center gap-2 min-w-0 hover:opacity-80" className="flex items-center gap-2 min-w-0 hover:opacity-80"
> >
<UserAvatar <UserAvatar
@@ -59,7 +60,7 @@ export function RemoteFollowing() {
<Button <Button
size="sm" size="sm"
variant="outline" variant="outline"
onClick={() => unfollow(actor.handle)} onClick={() => unfollow(actor)}
> >
Unfollow Unfollow
</Button> </Button>