feat(api): Implement glitch-soc /v1/notifications/destroy_multiple route

This commit is contained in:
Jesse Wierzbinski 2024-04-15 20:48:36 -10:00
parent 6dff872822
commit 5030d03404
No known key found for this signature in database
2 changed files with 153 additions and 0 deletions

View file

@ -0,0 +1,112 @@
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
import { config } from "config-manager";
import {
deleteOldTestUsers,
getTestStatuses,
getTestUsers,
sendTestRequest,
} from "~tests/utils";
import type { Notification as APINotification } from "~types/mastodon/notification";
import { meta } from "./index";
await deleteOldTestUsers();
const { users, tokens, deleteUsers } = await getTestUsers(2);
const statuses = await getTestStatuses(40, users[0]);
let notifications: APINotification[] = [];
// Create some test notifications
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}`,
},
},
);
for (const i of [0, 1, 2, 3]) {
await fetch(
new URL(
`/api/v1/statuses/${statuses[i].id}/favourite`,
config.http.base_url,
),
{
method: "POST",
headers: {
Authorization: `Bearer ${tokens[1].accessToken}`,
},
},
);
}
notifications = await fetch(
new URL("/api/v1/notifications", config.http.base_url),
{
headers: {
Authorization: `Bearer ${tokens[0].accessToken}`,
},
},
).then((r) => r.json());
expect(notifications.length).toBe(5);
});
afterAll(async () => {
await deleteUsers();
});
// /api/v1/notifications/destroy_multiple
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), {
method: "DELETE",
}),
);
expect(response.status).toBe(401);
});
test("should dismiss notifications", async () => {
const response = await sendTestRequest(
new Request(
new URL(
`${meta.route}?${new URLSearchParams(
notifications.slice(1).map((n) => ["ids[]", n.id]),
).toString()}`,
config.http.base_url,
),
{
method: "DELETE",
headers: {
Authorization: `Bearer ${tokens[0].accessToken}`,
},
},
),
);
expect(response.status).toBe(200);
});
test("should not display dismissed notification", async () => {
const response = await sendTestRequest(
new Request(
new URL("/api/v1/notifications", config.http.base_url),
{
headers: {
Authorization: `Bearer ${tokens[0].accessToken}`,
},
},
),
);
expect(response.status).toBe(200);
const output = await response.json();
expect(output.length).toBe(1);
});
});

View file

@ -0,0 +1,41 @@
import { apiRoute, applyConfig, idValidator } from "@api";
import { errorResponse, jsonResponse } from "@response";
import { inArray } from "drizzle-orm";
import { z } from "zod";
import { db } from "~drizzle/db";
import { notification } from "~drizzle/schema";
export const meta = applyConfig({
allowedMethods: ["DELETE"],
route: "/api/v1/notifications/destroy_multiple",
ratelimits: {
max: 100,
duration: 60,
},
auth: {
required: true,
oauthPermissions: ["write:notifications"],
},
});
export const schema = z.object({
ids: z.array(z.string().regex(idValidator)),
});
export default apiRoute<typeof meta, typeof schema>(
async (req, matchedRoute, extraData) => {
const { user } = extraData.auth;
if (!user) return errorResponse("Unauthorized", 401);
const { ids } = extraData.parsedRequest;
await db
.update(notification)
.set({
dismissed: true,
})
.where(inArray(notification.id, ids));
return jsonResponse({});
},
);