feat(api): Add notifications for follow requests again and mentions

This commit is contained in:
Jesse Wierzbinski 2024-04-15 19:40:35 -10:00
parent 06bcbbe451
commit 47133ac3fe
No known key found for this signature in database
4 changed files with 138 additions and 5 deletions

View file

@ -35,6 +35,7 @@ import {
status,
statusToMentions,
user,
notification,
} from "~drizzle/schema";
import { LogLevel } from "~packages/log-manager";
import type { Note } from "~types/lysand/Object";
@ -995,6 +996,18 @@ export const createNewStatus = async (
.where(inArray(attachment.id, media_attachments));
}
// Send notifications for mentioned local users
for (const mention of mentions ?? []) {
if (mention.instanceId === null) {
await db.insert(notification).values({
accountId: author.id,
notifiedId: mention.id,
type: "mention",
statusId: newStatus.id,
});
}
}
return (
(await findFirstStatuses({
where: (status, { eq }) => eq(status.id, newStatus.id),
@ -1146,6 +1159,18 @@ export const editStatus = async (
.execute();
}
// Send notifications for mentioned local users
for (const mention of mentions ?? []) {
if (mention.instanceId === null) {
await db.insert(notification).values({
accountId: statusToEdit.authorId,
notifiedId: mention.id,
type: "mention",
statusId: updated.id,
});
}
}
// Set attachment parents
await db
.update(attachment)

View file

@ -172,7 +172,7 @@ export const followRequestUser = async (
notify = false,
languages: string[] = [],
): Promise<InferSelectModel<typeof relationship>> => {
const isRemote = follower.instanceId !== followee.instanceId;
const isRemote = followee.instanceId !== null;
const updatedRelationship = (
await db
@ -226,9 +226,9 @@ export const followRequestUser = async (
}
} else {
await db.insert(notification).values({
accountId: followee.id,
accountId: follower.id,
type: followee.isLocked ? "follow_request" : "follow",
notifiedId: follower.id,
notifiedId: followee.id,
});
}

View file

@ -0,0 +1,110 @@
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
import { config } from "config-manager";
import {
deleteOldTestUsers,
getTestStatuses,
getTestUsers,
sendTestRequest,
} from "~tests/utils";
import { meta } from "./index";
import type { Notification as APINotification } from "~types/mastodon/notification";
await deleteOldTestUsers();
const { users, tokens, deleteUsers } = await getTestUsers(2);
const timeline = (await getTestStatuses(40, users[0])).toReversed();
// Create some test notifications: follow, favourite, reblog, mention
beforeAll(async () => {
await fetch(
new URL(`/api/v1/accounts/${users[0].id}/follow`, config.http.base_url),
{
method: "POST",
headers: {
Authorization: `Bearer ${tokens[1].accessToken}`,
},
},
);
await fetch(
new URL(
`/api/v1/statuses/${timeline[0].id}/favourite`,
config.http.base_url,
),
{
method: "POST",
headers: {
Authorization: `Bearer ${tokens[1].accessToken}`,
},
},
);
await fetch(
new URL(
`/api/v1/statuses/${timeline[0].id}/reblog`,
config.http.base_url,
),
{
method: "POST",
headers: {
Authorization: `Bearer ${tokens[1].accessToken}`,
},
},
);
await fetch(new URL("/api/v1/statuses", config.http.base_url), {
method: "POST",
headers: {
Authorization: `Bearer ${tokens[1].accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
status: `@${users[0].username} test mention`,
visibility: "direct",
federate: false,
}),
});
});
afterAll(async () => {
await deleteUsers();
});
// /api/v1/notifications
describe(meta.route, () => {
test("should return 401 if not authenticated", async () => {
const response = await sendTestRequest(
new Request(new URL(meta.route, config.http.base_url)),
);
expect(response.status).toBe(401);
});
test("should return 200 with notifications", async () => {
const response = await sendTestRequest(
new Request(new URL(meta.route, config.http.base_url), {
headers: {
Authorization: `Bearer ${tokens[0].accessToken}`,
},
}),
);
expect(response.status).toBe(200);
expect(response.headers.get("content-type")).toBe("application/json");
const objects = (await response.json()) as APINotification[];
expect(objects.length).toBe(4);
for (const [index, notification] of objects.entries()) {
expect(notification.account).toBeDefined();
expect(notification.account?.id).toBe(users[1].id);
expect(notification.created_at).toBeDefined();
expect(notification.id).toBeDefined();
expect(notification.type).toBeDefined();
expect(notification.type).toBe(
["follow", "favourite", "reblog", "mention"].toReversed()[
index
],
);
}
});
});

View file

@ -47,7 +47,6 @@ export const schema = z.object({
"group_reblog",
"group_favourite",
"user_approved",
"update",
])
.array()
.optional(),
@ -73,7 +72,6 @@ export const schema = z.object({
"group_reblog",
"group_favourite",
"user_approved",
"update",
])
.array()
.optional(),