Skip to content

Commit

Permalink
More accurate shares/likes count
Browse files Browse the repository at this point in the history
  • Loading branch information
dahlia committed Jan 2, 2025
1 parent 596de1b commit 0d8239b
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 24 deletions.
9 changes: 9 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ Version 0.5.0

To be released.

- The number of shares and likes became more accurate.

- The `Note` objects now have `shares` and `likes` collections with
their `totalItems` numbers.
- When a remote `Note` is persisted, now the `totalItems` numbers of
`shares` and `likes` are also persisted.
- When a `Announce(Note)` or `Undo(Announce(Note))` activity is received,
now it is forwarded to the followers as well if the activity is signed.


Version 0.4.2
-------------
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
},
"dependencies": {
"@aws-sdk/credential-providers": "^3.716.0",
"@fedify/fedify": "^1.3.3",
"@fedify/fedify": "1.4.0-dev.599",
"@fedify/markdown-it-hashtag": "0.2.0",
"@fedify/markdown-it-mention": "^0.1.1",
"@fedify/postgres": "^0.2.2",
Expand Down
30 changes: 28 additions & 2 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/federation/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ export async function persistAccountPosts(
typeof schema,
ExtractTablesWithRelations<typeof schema>
>,
account: schema.Account,
account: schema.Account & { owner: schema.AccountOwner | null },
fetchPosts: number,
baseUrl: URL | string,
options: {
Expand Down
37 changes: 27 additions & 10 deletions src/federation/inbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ export async function onPostShared(
): Promise<void> {
const object = await announce.getObject();
if (!isPost(object)) return;
await db.transaction(async (tx) => {
const post = await db.transaction(async (tx) => {
const post = await persistSharingPost(
tx,
announce,
Expand All @@ -427,11 +427,19 @@ export async function onPostShared(
if (post?.sharingId != null) {
await updatePostStats(tx, { id: post.sharingId });
}
return post;
});
if (post?.sharing?.account?.owner != null) {
await ctx.forwardActivity(
{ username: post.sharing.account.owner.handle },
"followers",
{ skipIfUnsigned: true },
);
}
}

export async function onPostUnshared(
_ctx: InboxContext<void>,
ctx: InboxContext<void>,
undo: Undo,
): Promise<void> {
const object = await undo.getObject();
Expand All @@ -440,7 +448,14 @@ export async function onPostUnshared(
const sharer = object.actorId;
const originalPost = object.objectId;
if (sharer == null || originalPost == null) return;
await db.transaction(async (tx) => {
const original = await db.transaction(async (tx) => {
const original = await tx.query.posts.findFirst({
with: {
account: { with: { owner: true } },
},
where: eq(posts.iri, originalPost.href),
});
if (original == null) return null;
const deleted = await tx
.delete(posts)
.where(
Expand All @@ -452,20 +467,22 @@ export async function onPostUnshared(
.from(accounts)
.where(eq(accounts.iri, sharer.href)),
),
eq(
posts.sharingId,
db
.select({ id: posts.id })
.from(posts)
.where(eq(posts.iri, originalPost.href)),
),
eq(posts.sharingId, original.id),
),
)
.returning();
if (deleted.length > 0 && deleted[0].sharingId != null) {
await updatePostStats(tx, { id: deleted[0].sharingId });
}
return original;
});
if (original?.account.owner != null) {
await ctx.forwardActivity(
{ username: original.account.owner.handle },
"followers",
{ skipIfUnsigned: true },
);
}
}

export async function onPostPinned(
Expand Down
54 changes: 45 additions & 9 deletions src/federation/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,17 @@ export async function persistPost(
options: {
contextLoader?: DocumentLoader;
documentLoader?: DocumentLoader;
account?: Account;
account?: Account & { owner: AccountOwner | null };
replyTarget?: Post;
skipUpdate?: boolean;
} = {},
): Promise<(Post & { mentions: Mention[] }) | null> {
): Promise<
| (Post & {
account: Account & { owner: AccountOwner | null };
mentions: Mention[];
})
| null
> {
if (object.id == null) return null;
const existingPost = await db.query.posts.findFirst({
with: { account: { with: { owner: true } }, mentions: true },
Expand Down Expand Up @@ -218,6 +224,8 @@ export async function persistPost(
const to = new Set(object.toIds.map((url) => url.href));
const cc = new Set(object.ccIds.map((url) => url.href));
const replies = await object.getReplies(options);
const shares = await object.getShares(options);
const likes = await object.getLikes(options);
const previewLink =
object.content == null
? null
Expand Down Expand Up @@ -259,8 +267,8 @@ export async function persistPost(
sensitive: object.sensitive ?? false,
url: object.url instanceof Link ? object.url.href?.href : object.url?.href,
repliesCount: replies?.totalItems ?? 0,
sharesCount: 0, // TODO
likesCount: 0, // TODO
sharesCount: shares?.totalItems ?? 0,
likesCount: likes?.totalItems ?? 0,
published,
updated,
} as const;
Expand Down Expand Up @@ -457,7 +465,7 @@ export async function persistPost(
mentions: mentionRows,
replyTarget: replyTargetObj,
});
return { ...post, mentions: mentionRows };
return { ...post, account, mentions: mentionRows };
}

export async function persistSharingPost(
Expand All @@ -470,14 +478,25 @@ export async function persistSharingPost(
object: ASPost,
baseUrl: URL | string,
options: {
account?: Account;
account?: Account & { owner: AccountOwner | null };
contextLoader?: DocumentLoader;
documentLoader?: DocumentLoader;
} = {},
): Promise<Post | null> {
): Promise<
| (Post & {
account: Account & { owner: AccountOwner | null };
sharing:
| (Post & { account: Account & { owner: AccountOwner | null } })
| null;
})
| null
> {
if (announce.id == null) return null;
const existingPost = await db.query.posts.findFirst({
with: { account: { with: { owner: true } } },
with: {
account: { with: { owner: true } },
sharing: { with: { account: { with: { owner: true } } } },
},
where: eq(posts.iri, announce.id.href),
});
if (existingPost != null) return existingPost;
Expand Down Expand Up @@ -531,7 +550,9 @@ export async function persistSharingPost(
mentions: [],
replyTarget: null,
});
return result[0] ?? null;
return result[0] == null
? null
: { ...result[0], account, sharing: originalPost };
}

export async function persistPollVote(
Expand Down Expand Up @@ -774,9 +795,24 @@ export function toObject(
replyTarget:
post.replyTarget == null ? null : new URL(post.replyTarget.iri),
replies: new OrderedCollection({
id: new URL("#replies", post.iri),
totalItems: post.replies.length,
items: post.replies.map((r) => new URL(r.iri)),
}),
shares:
post.sharesCount == null
? null
: new Collection({
id: new URL("#shares", post.iri),
totalItems: post.sharesCount,
}),
likes:
post.likesCount == null
? null
: new Collection({
id: new URL("#likes", post.iri),
totalItems: post.likesCount,
}),
attachments: post.media.map((medium) =>
medium.type.startsWith("video/")
? new Video({
Expand Down
2 changes: 1 addition & 1 deletion src/pages/accounts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ accounts.post("/", async (c) => {
await followAccount(tx, fedCtx, { ...account, owner }, following);
await persistAccountPosts(
tx,
account,
{ ...account, owner },
REMOTE_ACTOR_FETCH_POSTS,
c.req.url,
{
Expand Down

0 comments on commit 0d8239b

Please sign in to comment.